クラスインスタンスを JSONシリアライズする

class User:
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address
class Address:
    def __init__(self, city, street, pin):
        self.city = city
        self.street = street
        self.pin = pin

address = Address("Tokyo", "Shinjuku", 1214)
user = User("uran", 26, address)

このUserクラスインスタンス user を JSONシリアライズしたい。

もっともシンプルな方法

import json

str = json.dumps(user, default=lambda o:o.__dict__, indent=3)

print(str)
{
   "name": "uran",
   "age": 26,
   "address": {
      "city": "Tokyo",
      "street": "Shinjuku",
      "pin": 1214
   }
}

default=lambda o:o.__dict__ は、つまり以下メソッドを宣言して渡すことと同じ

def toJson(o):
    return o.__dict__
str = json.dumps(user, default=toJson, indent=3)

もう1つ、json.JSONEncoder を継承して行う方法

import json
from json import JSONEncoder

JSONEncoder 継承するクラスを用意

class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__

そのまま実行すると

str = MyEncoder().(user)

print(str)
{"name": "uran", "age": 26, "address": {"city": "Tokyo", "street": "Shinjuku", "pin": 1214}}

とインデントはデフォルトで無いので、MyEncoder 生成時に指定しなければならない

str = MyEncoder(indent=3).(user)

ただし、これら、__dict__ を使ったJSONシリアライズは、
軽量・高速化を目的とした__slots__ を宣言しているクラスでは使えません。

AttributeError: 'User' object has no attribute '__dict__'

になり属性を __dict__.['attributeName'] という参照ができなくなります。
__dict__ は内部で直接参照しにいくみたいです。

class User:
    __slots__ = ['name', 'age', 'address']
    def __init__(self, name, age, address):
        self.name = name
        self.age = age
        self.address = address

このように __slots__ 定義していると、__dict__ による
JSONシリアライズができません。