236

クラス インスタンスの JSON 文字列表現を作成しようとしていますが、問題があります。クラスが次のように構築されているとしましょう:

class testclass:
    value1 = "a"
    value2 = "b"

json.dumps への呼び出しは次のように行われます。

t = testclass()
json.dumps(t)

失敗して、テストクラスが JSON シリアライズ可能ではないことを教えてくれます。

TypeError: <__main__.testclass object at 0x000000000227A400> is not JSON serializable

pickle モジュールも使用してみました:

t = testclass()
print(pickle.dumps(t, pickle.HIGHEST_PROTOCOL))

また、クラス インスタンス情報を提供しますが、クラス インスタンスのシリアル化されたコンテンツは提供しません。

b'\x80\x03c__main__\ntestclass\nq\x00)\x81q\x01}q\x02b.'

私は何を間違っていますか?

4

17 に答える 17

290

基本的な問題は、JSON エンコーダーがjson.dumps()、既定ですべての組み込み型の限られたオブジェクト型のセットをシリアル化する方法しか認識していないことです。ここにリスト: https://docs.python.org/3.3/library/json.html#encoders-and-decoders

良い解決策の 1 つは、クラスを関数から継承してからJSONEncoder実装し、JSONEncoder.default()その関数がクラスの正しい JSON を発行するようにすることです。

簡単な解決策は、そのインスタンスjson.dumps()のメンバーを呼び出すことです。.__dict__これは標準の Pythondictであり、クラスが単純であれば、JSON シリアライズ可能になります。

class Foo(object):
    def __init__(self):
        self.x = 1
        self.y = 2

foo = Foo()
s = json.dumps(foo) # raises TypeError with "is not JSON serializable"

s = json.dumps(foo.__dict__) # s set to: {"x":1, "y":2}

上記のアプローチは、このブログ投稿で説明されています。

    _ dict _を使用して任意の Python オブジェクトを JSON にシリアライズする

そしてもちろん、Python には.__dict__と呼ばれる組み込み関数が用意されていますvars()

したがって、上記の例は次のようにも実行できます。

s = json.dumps(vars(foo)) # s set to: {"x":1, "y":2}
于 2012-04-20T19:09:39.850 に答える
79

あなたが試すことができる私にとってうまくいく1つの方法があります:

json.dumps()オプションのパラメーターdefaultを使用して、不明な型のカスタムシリアライザー関数を指定できます。

def serialize(obj):
    """JSON serializer for objects not serializable by default json code"""

    if isinstance(obj, date):
        serial = obj.isoformat()
        return serial

    if isinstance(obj, time):
        serial = obj.isoformat()
        return serial

    return obj.__dict__

最初の 2 つの if は日付と時刻のシリアライゼーションobj.__dict__用で、その他のオブジェクトには が返されます。

最終的な呼び出しは次のようになります。

json.dumps(myObj, default=serialize)

__dict__コレクションをシリアル化していて、すべてのオブジェクトに対して明示的に呼び出したくない場合に特に便利です。ここでは、自動的に行われます。

これまでのところ、あなたの考えを楽しみにしています。

于 2016-12-17T16:25:13.633 に答える
25

私はただします:

data=json.dumps(myobject.__dict__)

これは完全な答えではありません。何らかの複雑なオブジェクト クラスがある場合、すべてを取得できるわけではありません。ただし、これをいくつかの単純なオブジェクトに使用します。

これが非常にうまく機能するのは、OptionParser モジュールから取得する「オプション」クラスです。ここでは、JSON リクエスト自体と一緒です。

  def executeJson(self, url, options):
        data=json.dumps(options.__dict__)
        if options.verbose:
            print data
        headers = {'Content-type': 'application/json', 'Accept': 'text/plain'}
        return requests.post(url, data, headers=headers)
于 2013-07-10T14:36:02.750 に答える
6

JSON は、任意の Python オブジェクトをシリアル化するためのものではありません。dictオブジェクトをシリアル化するのに最適ですが、pickleモジュールは実際に一般的に使用する必要があるものです。からの出力pickleは実際には人間が読めるものではありませんが、問題なく unpickle する必要があります。JSON の使用を主張する場合jsonpickleは、興味深いハイブリッド アプローチであるモジュールを確認できます。

https://github.com/jsonpickle/jsonpickle

于 2012-04-20T19:13:39.493 に答える
2

これを始める方法については、いくつかの良い答えがあります。ただし、次の点に注意してください。

  • インスタンスが大きなデータ構造内にネストされている場合はどうなりますか?
  • クラス名も必要な場合はどうなりますか?
  • インスタンスをデシリアライズしたい場合はどうしますか?
  • __slots__の代わりに使用している場合はどうなります__dict__か?
  • 自分でやりたくない場合はどうしますか?

json-tricksは、かなり長い間これを行うことができたライブラリ (私が作成し、他の人が貢献したもの) です。例えば:

class MyTestCls:
    def __init__(self, **kwargs):
        for k, v in kwargs.items():
            setattr(self, k, v)

cls_instance = MyTestCls(s='ub', dct={'7': 7})

json = dumps(cls_instance, indent=4)
instance = loads(json)

インスタンスを取り戻します。ここで、json は次のようになります。

{
    "__instance_type__": [
        "json_tricks.test_class",
        "MyTestCls"
    ],
    "attributes": {
        "s": "ub",
        "dct": {
            "7": 7
        }
    }
}

独自のソリューションを作成したい場合は、json-tricksいくつかの特殊なケース ( など__slots__) を忘れないように、 のソースを参照してください。

また、numpy 配列、日時、複素数などの他の型も処理します。コメントも可能です。

于 2017-09-19T18:11:12.190 に答える
2

これは、すでにこの機能が組み込まれているため、pydanticで簡単に処理できます。

オプション 1: 通常の方法

from pydantic import BaseModel

class testclass(BaseModel):
    value1: str = "a"
    value2: str = "b"

test = testclass()

>>> print(test.json(indent=4))
{
    "value1": "a",
    "value2": "b"
}

オプション 2: pydantic のデータクラスを使用する

import json
from pydantic.dataclasses import dataclass
from pydantic.json import pydantic_encoder

@dataclass
class testclass:
    value1: str = "a"
    value2: str = "b"

test = testclass()
>>> print(json.dumps(test, indent=4, default=pydantic_encoder))
{
    "value1": "a",
    "value2": "b"
}
于 2021-02-04T13:08:54.723 に答える
1

ここで適用できるもう 1 つの非常にシンプルで洗練されたアプローチがあります。これは、デフォルトでシリアライズ可能であるため、「dict」をサブクラス化するだけです。

from json import dumps

class Response(dict):
    def __init__(self, status_code, body):
        super().__init__(
            status_code = status_code,
            body = body
        )

r = Response()
dumps(r)
于 2021-01-23T02:14:59.637 に答える
0

objprintPython オブジェクトを印刷するための軽量ライブラリである を試すことができます。これは json 出力をサポートしています。

pip install objprint
from objprint import objjson
t = testclass()
json_obj = objjson(t)
print(json.dumps(json_obj))

objjson基本的に任意のオブジェクトを jsonifiable オブジェクトに変換し、.typeそれが dict や list などの組み込み型でない場合、元の Python 型の特別なキーを使用します。

単純に印刷したい場合opは、人間が読める形式でオブジェクトを印刷するために通常使用される which を使用できます。

from objprint import op
t = testclass()
op(t, format="json", indent=2)

# If you want to dump to a file
with open("my_obj.json", "w") as f:
    # This is the same usage as print
    op(t, format="json", file=f)
于 2021-08-28T21:50:40.763 に答える