13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Python】クラスインスタンスをjsonにエンコードしたい

Posted at

概要

  • json.dumpなどのメソッドに、クラスのインスタンスを直接投げ込んでjson化したい。
    • 何もせずにこれをやると、TypeErrorになる。
  • エンコーダのdefaultメソッドを書き換えて、インスタンスの__dict__を返すようにすると、とりあえずうまくいく。
    • メソッドがあっても無視してプロパティだけ出力してくれる。
    • 循環参照のチェックもそのまま動く。

実践

大体上に答えを書きましたが、こんなコードを書いてみました、テストデータを組み立てている部分の方が長いです。

classencode.py
import json

# テスト用のクラス、メソッド付き
class MyClass:
    def my_method(self):
        return True

# テスト用のクラス、ネストして使う用
class ChildClass:
    pass

parent = MyClass()
child = ChildClass()
child.value1 = 'value'
child.value2 = 11
parent.child = child
parent.childList=[child, child, child]

# 以下のような構造になっている
# MyClass{
#     child = ChildClass{
#         value1:'value1',
#         value2:11
#     }
#     childList=[child, child, child]
# }

# ここがポイント
def default_method(item):
    if isinstance(item, object) and hasattr(item, '__dict__'):
        return item.__dict__
    else:
        raise TypeError

# 作成したメソッドを指定してdumps
print(json.dumps(parent, default=default_method, indent=2))

isinstance(item, object)以外にもhasattr(item, '__dict__')しているのは、全てのobjectが__dict__を持っているわけではないためのガードです。1
他にも、default_methodの部分ではDecimal型の処理やそのほか、素のままでは処理してくれない型をエンコードしたいケースでも使用するので、クラス中に色々な型が出てくる場合、ちょっと中身が大変になりそうです。
なお、json.dumpsの内部で使われるJsonEncoderは、エンコードするオブジェクトが循環参照を起こしている場合にエラーを返しますが、そのチェックもちゃんと機能します。

出力

{
  "child": {
    "value1": "value",
    "value2": 11
  },
  "childList": [
    {
      "value1": "value",
      "value2": 11
    },
    {
      "value1": "value",
      "value2": 11
    },
    {
      "value1": "value",
      "value2": 11
    }
  ]
}

こんなふうに、ネストしたインスタンスやインスタンスのリストも無事に出力されました。ごく単純な構造でしか試していないし、pythonはまだ修業中の身なので、これでは扱い切れないケースがあるかもしれませんが、少ない手数でjson化できるのは悪くないと思います。

  1. __dict__に触るのは厳密には好ましくないようで、例えばクラスが__getattribute__などをオーバーライドしている場合、__dict__に直接アクセスすると__getattribute__は呼び出されません。これを厳密に処理したい場合、__dir__で諸々の名前を取得してうまくやる…しか思いつきませんが、大変なのでここではやりません。

13
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
10

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?