Pythonでデータを保存したり、他のシステムとデータをやり取りする際に、JSON(JavaScript Object Notation)という形式がよく使われます。
この記事では、Pythonの標準ライブラリを使って、PythonオブジェクトをJSON形式に変換(シリアライズ)したり、逆にJSON形式からPythonオブジェクトに戻す(デシリアライズ)方法をわかりやすく解説します。
特に、クラスのインスタンスをJSONにシリアライズする方法や、カスタムシリアライザの作成方法についても詳しく説明します。
初心者の方でも理解しやすいように、具体的なコード例を交えながら進めていきますので、ぜひ参考にしてください。
PythonでのJSONシリアライズ
PythonでJSONシリアライズを行う方法について解説します。
JSON(JavaScript Object Notation)は、データを交換するための軽量なフォーマットで、Pythonでも広く利用されています。
Pythonでは、標準ライブラリを使用して簡単にJSONシリアライズを行うことができます。
Pythonの標準ライブラリ
jsonモジュールの紹介
Pythonには、JSONデータを扱うための標準ライブラリとしてjson
モジュールが用意されています。
このモジュールを使用することで、PythonオブジェクトをJSON形式に変換(シリアライズ)したり、JSON形式のデータをPythonオブジェクトに変換(デシリアライズ)したりすることができます。
基本的な使い方
json
モジュールの基本的な使い方を見てみましょう。
まずは、PythonオブジェクトをJSON形式に変換する方法です。
以下のコードは、Pythonの辞書型オブジェクトをJSON文字列に変換する例です。
import json
# Pythonの辞書型オブジェクト
data = {
"name": "Alice",
"age": 30,
"city": "Tokyo"
}
# JSON文字列に変換
json_data = json.dumps(data, ensure_ascii=False)
print(json_data)
このコードを実行すると、以下のようなJSON文字列が出力されます。
{"name": "Alice", "age": 30, "city": "Tokyo"}
次に、JSON文字列をPythonオブジェクトに変換する方法です。
以下のコードは、JSON文字列をPythonの辞書型オブジェクトに変換する例です。
import json
# JSON文字列
json_data = '{"name": "Alice", "age": 30, "city": "Tokyo"}'
# Pythonの辞書型オブジェクトに変換
data = json.loads(json_data)
print(data)
このコードを実行すると、以下のような辞書型オブジェクトが出力されます。
{'name': 'Alice', 'age': 30, 'city': 'Tokyo'}
Pythonオブジェクトのシリアライズ
基本データ型のシリアライズ
Pythonの基本データ型(数値、文字列、リスト、辞書など)は、json
モジュールを使用して簡単にJSON形式にシリアライズすることができます。
以下に、いくつかの基本データ型をJSON形式にシリアライズする例を示します。
import json
# 数値
number = 42
json_number = json.dumps(number)
print(json_number) # 出力: 42
# 文字列
string = "Hello, World!"
json_string = json.dumps(string)
print(json_string) # 出力: "Hello, World!"
# リスト
list_data = [1, 2, 3, 4, 5]
json_list = json.dumps(list_data)
print(json_list) # 出力: [1, 2, 3, 4, 5]
# 辞書
dict_data = {"name": "Alice", "age": 30}
json_dict = json.dumps(dict_data, ensure_ascii=False)
print(json_dict) # 出力: {"name": "Alice", "age": 30}
辞書やリストのシリアライズ
辞書やリストなどの複雑なデータ構造も、json
モジュールを使用して簡単にJSON形式にシリアライズすることができます。
以下に、辞書やリストを含む複雑なデータ構造をJSON形式にシリアライズする例を示します。
import json
# 複雑なデータ構造
complex_data = {
"name": "Alice",
"age": 30,
"children": [
{"name": "Bob", "age": 5},
{"name": "Charlie", "age": 3}
],
"address": {
"city": "Tokyo",
"zipcode": "100-0001"
}
}
# JSON文字列に変換
json_complex_data = json.dumps(complex_data, ensure_ascii=False, indent=4)
print(json_complex_data)
このコードを実行すると、以下のような整形されたJSON文字列が出力されます。
{
"name": "Alice",
"age": 30,
"children": [
{
"name": "Bob",
"age": 5
},
{
"name": "Charlie",
"age": 3
}
],
"address": {
"city": "Tokyo",
"zipcode": "100-0001"
}
}
このように、json
モジュールを使用することで、Pythonの基本データ型や複雑なデータ構造を簡単にJSON形式にシリアライズすることができます。
次のセクションでは、クラスをJSONにシリアライズする方法について詳しく解説します。
クラスをJSONにシリアライズする方法
クラスの定義
シンプルなクラスの例
まずは、シンプルなクラスを定義してみましょう。
以下の例では、Person
という名前のクラスを作成します。
このクラスは名前と年齢を属性として持ちます。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
クラスのインスタンス生成
次に、このクラスのインスタンスを生成してみます。
person = Person("Alice", 30)
このコードを実行すると、person
という名前のPersonクラス
のインスタンスが生成されます。
クラスのシリアライズ
json.dumps()の使用
Pythonの標準ライブラリであるjson
モジュールを使用して、クラスのインスタンスをJSONにシリアライズすることができます。
しかし、デフォルトの設定ではクラスのインスタンスを直接シリアライズすることはできません。
import json
person = Person("Alice", 30)
json_data = json.dumps(person)
このコードを実行すると、TypeError: Object of type Person is not JSON serializable
というエラーが発生します。
これは、json.dumps()
がクラスのインスタンスをシリアライズできないためです。
デフォルトのシリアライズ方法とその限界
デフォルトのシリアライズ方法では、基本的なデータ型(文字列、数値、リスト、辞書など)のみがサポートされています。
クラスのインスタンスをシリアライズするためには、カスタムシリアライザを作成する必要があります。
カスタムシリアライザの作成
カスタムシリアライザの必要性
クラスのインスタンスをJSONにシリアライズするためには、カスタムシリアライザを作成する必要があります。
これにより、クラスのインスタンスを辞書形式に変換し、その辞書をJSONにシリアライズすることができます。
defaultパラメータの使用方法
json.dumps()関数
には、default
というパラメータがあります。
このパラメータにカスタムシリアライザを指定することで、クラスのインスタンスをシリアライズすることができます。
カスタムシリアライザの実装例
以下に、カスタムシリアライザの実装例を示します。
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def person_serializer(obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age}
raise TypeError(f"Type {type(obj)} not serializable")
person = Person("Alice", 30)
json_data = json.dumps(person, default=person_serializer)
print(json_data)
このコードを実行すると、{"name": "Alice<", "age": 30}
というJSON文字列が出力されます。
クラスの属性を辞書に変換する方法
クラスの属性を辞書に変換するためには、__dict__
属性を利用する方法があります。
__dict__属性の利用
__dict__
属性を利用すると、クラスのインスタンスの属性を辞書形式で取得することができます。
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
person = Person("Alice", 30)
json_data = json.dumps(person.__dict__)
print(json_data)
このコードを実行すると、{"name": "Alice", "age": 30}
というJSON文字列が出力されます。
複雑なクラスのシリアライズ
複雑なクラスのシリアライズには、カスタムシリアライザをさらに拡張する必要があります。
ネストされたオブジェクトのシリアライズ
クラスの属性に他のクラスのインスタンスが含まれている場合、そのインスタンスもシリアライズする必要があります。
import json
class Address:
def __init__(self, city, street):
self.city = city
self.street = street
class Person:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def custom_serializer(obj):
if isinstance(obj, Person):
return {"name": obj.name, "age": obj.age, "address": obj.address}
if isinstance(obj, Address):
return {"city": obj.city, "street": obj.street}
raise TypeError(f"Type {type(obj)} not serializable")
address = Address("Tokyo", "Shibuya")
person = Person("Alice", 30, address)
json_data = json.dumps(person, default=custom_serializer)
print(json_data)
このコードを実行すると、{"name": "Alice", "age": 30, "address": {"city": "Tokyo", "street": "Shibuya"}}
というJSON文字列が出力されます。
再帰的なシリアライズ方法
再帰的なシリアライズ方法を使用すると、ネストされたオブジェクトを自動的にシリアライズすることができます。
import json
class Address:
def __init__(self, city, street):
self.city = city
self.street = street
class Person:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def custom_serializer(obj):
if hasattr(obj, "__dict__"):
return obj.__dict__
raise TypeError(f"Type {type(obj)} not serializable")
address = Address("Tokyo", "Shibuya")
person = Person("Alice", 30, address)
json_data = json.dumps(person, default=custom_serializer)
print(json_data)
このコードを実行すると、{"name": "Alice", "age": 30, "address": {"city": "Tokyo", "street": "Shibuya"}}
というJSON文字列が出力されます。
この方法では、クラスのインスタンスが持つすべての属性を再帰的にシリアライズすることができます。
JSONデシリアライズ
デシリアライズの基本
json.loads()の使用
JSONデータをPythonオブジェクトに変換するためには、json
モジュールのloads()関数
を使用します。
この関数は、JSON形式の文字列を引数として受け取り、対応するPythonオブジェクトを返します。
import json
json_data = '{"name": "Alice", "age": 30, "city": "Tokyo"}'
python_obj = json.loads(json_data)
print(python_obj)
# 出力: {'name': 'Alice', 'age': 30, 'city': 'Tokyo'}
基本データ型のデシリアライズ
json.loads()
は、基本的なデータ型(文字列、数値、リスト、辞書など)を適切にデシリアライズします。
以下にいくつかの例を示します。
# 数値のデシリアライズ
json_data = '123'
python_obj = json.loads(json_data)
print(python_obj)
# 出力: 123
# リストのデシリアライズ
json_data = '[1, 2, 3, 4, 5]'
python_obj = json.loads(json_data)
print(python_obj)
# 出力: [1, 2, 3, 4, 5]
# 辞書のデシリアライズ
json_data = '{"key1": "value1", "key2": "value2"}'
python_obj = json.loads(json_data)
print(python_obj)
# 出力: {'key1': 'value1', 'key2': 'value2'}
クラスのデシリアライズ
クラスインスタンスの再生成
クラスのインスタンスをJSONから再生成するためには、まずJSONデータを辞書にデシリアライズし、その辞書を使ってクラスのインスタンスを生成します。
import json
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
json_data = '{"name": "Alice", "age": 30, "city": "Tokyo"}'
data = json.loads(json_data)
person = Person(**data)
print(person.name, person.age, person.city)
# 出力: Alice 30 Tokyo
カスタムデシリアライザの作成
カスタムデシリアライザを作成することで、より複雑なクラスのデシリアライズが可能になります。
これには、デシリアライズ時に特定の処理を行う関数を定義します。
カスタムデシリアライザの実装例
以下は、カスタムデシリアライザを使用してクラスのインスタンスを生成する例です。
import json
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
def custom_person_decoder(dct):
if 'name' in dct and 'age' in dct and 'city' in dct:
return Person(dct['name'], dct['age'], dct['city'])
return dct
json_data = '{"name": "Alice", "age": 30, "city": "Tokyo"}'
person = json.loads(json_data, object_hook=custom_person_decoder)
print(person.name, person.age, person.city)
# 出力: Alice 30 Tokyo
辞書からクラスインスタンスを生成する方法
辞書からクラスインスタンスを生成するためには、辞書のキーとクラスの属性が一致している必要があります。
**
演算子を使用して辞書をアンパックし、クラスのコンストラクタに渡します。
data = {'name': 'Alice', 'age': 30, 'city': 'Tokyo'}
person = Person(**data)
print(person.name, person.age, person.city)
# 出力: Alice 30 Tokyo
__init__メソッドの利用
クラスの__init__メソッド
を利用して、デシリアライズされたデータをクラスのインスタンスに変換します。
これにより、クラスの属性が正しく初期化されます。
class Person:
def __init__(self, name, age, city):
self.name = name
self.age = age
self.city = city
data = {'name': 'Alice', 'age': 30, 'city': 'Tokyo'}
person = Person(**data)
print(person.name, person.age, person.city)
# 出力: Alice 30 Tokyo
複雑なクラスのデシリアライズ
複雑なクラスのデシリアライズには、ネストされたオブジェクトやカスタムデシリアライザを使用します。
以下は、ネストされたオブジェクトを含むクラスのデシリアライズ例です。
import json
class Address:
def __init__(self, street, city):
self.street = street
self.city = city
class Person:
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
def custom_decoder(dct):
if 'street' in dct and 'city' in dct:
return Address(dct['street'], dct['city'])
if 'name' in dct and 'age' in dct and 'address' in dct:
address = custom_decoder(dct['address'])
return Person(dct['name'], dct['age'], address)
return dct
json_data = '''
{
"name": "Alice",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Tokyo"
}
}
'''
person = json.loads(json_data, object_hook=custom_decoder)
print(person.name, person.age, person.address.street, person.address.city)
# 出力: Alice 30 123 Main St Tokyo
ネストされたオブジェクトのデシリアライズ
ネストされたオブジェクトのデシリアライズには、カスタムデシリアライザを再帰的に呼び出す必要があります。
上記の例では、custom_decoder関数
がネストされたAddress
オブジェクトを正しくデシリアライズしています。
再帰的なデシリアライズ方法
再帰的なデシリアライズ方法を使用することで、複雑なネスト構造を持つJSONデータを正しくデシリアライズできます。
再帰的なデシリアライザは、各レベルのオブジェクトを個別に処理し、最終的に完全なオブジェクトを生成します。
def custom_decoder(dct):
if 'street' in dct and 'city' in dct:
return Address(dct['street'], dct['city'])
if 'name' in dct and 'age' in dct and 'address' in dct:
address = custom_decoder(dct['address'])
return Person(dct['name'], dct['age'], address)
return dct
json_data = '''
{
"name": "Alice",
"age": 30,
"address": {
"street": "123 Main St",
"city": "Tokyo"
}
}
'''
person = json.loads(json_data, object_hook=custom_decoder)
print(person.name, person.age, person.address.street, person.address.city)
# 出力: Alice 30 123 Main St Tokyo
このようにして、PythonでクラスをJSONにシリアライズおよびデシリアライズする方法を理解することができます。
カスタムシリアライザとデシリアライザを使用することで、複雑なオブジェクトも簡単に扱うことができます。