JSONデータをPythonオブジェクトに変換する方法


281

Pythonを使用してJSONデータをPythonオブジェクトに変換したい。

Facebook APIからJSONデータオブジェクトを受け取りました。これをデータベースに保存します。

私の現在のDjango(Python)のビュー(request.POSTJSONを含む):

response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
  • これは正常に動作しますが、複雑なJSONデータオブジェクトをどのように処理しますか?

  • 簡単に使用できるように、このJSONオブジェクトを何らかの方法でPythonオブジェクトに変換できたら、はるかに良いと思いませんか?


通常、JSONはバニラリストまたは辞書に変換されます。それでいいの?または、JSONを直接カスタム型に変換することを望んでいますか?
Shakakai

「。」を使用してアクセスできるオブジェクトに変換したい。。上記の例のように-> reponse.name、response.education.idなど...
サイクリシュナ

44
dictsの使用は、オブジェクト指向プログラミングを行うための弱い方法です。辞書は、コードの読者に期待を伝えるための非常に貧弱な方法です。ディクショナリを使用して、一部のディクショナリのキーと値のペアが必要であり、他のペアは不要であることを明確かつ再利用可能に指定するにはどうすればよいですか?特定の値が許容範囲またはセットにあることを確認するのはどうですか?操作しているオブジェクトのタイプに固有の関数(別名メソッド)はどうですか?辞書は便利で多用途ですが、開発者が多すぎるため、Pythonがオブジェクト指向言語であることを忘れたように振る舞います。
シチュー

1
このためのPythonライブラリはありgithub.com/jsonpickle/jsonpickleは(答えはスレッドに過ぎ以下であると、到達可能で文句を言わないので、コメントする。)
最高の願い

回答:


355

namedtupleand を使用して、1行で実行できますobject_hook

import json
from collections import namedtuple

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse JSON into an object with attributes corresponding to dict keys.
x = json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))
print x.name, x.hometown.name, x.hometown.id

または、これを簡単に再利用するには:

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def json2obj(data): return json.loads(data, object_hook=_json_object_hook)

x = json2obj(data)

適切な属性名ではないキーを処理する場合は、namedtuplerenameパラメータを確認してください


8
これにより、Valueエラーが発生する可能性があります。ValueError:タイプ名とフィールド名は、数字で始めることはできません: '123'
PvdL

3
Pythonの初心者として、セキュリティが問題となる場合にも、これが節約になるかどうかに興味があります。
ベンジスト、2015

8
これにより、解析中にJSONオブジェクトに遭遇するたびに新しい異なるクラスが作成されますよね?
fikr4n 2016年

2
面白い。同じ順序での依存d.keys()d.values()反復は保証されていないと思いましたが、間違っていました。ドキュメントは言う:「キー、値とアイテムビューが辞書に無い介在修正を繰り返し処理している場合は、項目の順序が直接対応します。」。このような小さなローカルコードブ​​ロックについて知っておくと役に立ちます。このような依存関係のコードのメンテナに明示的に警告するために、コメントを追加します。
cfi

1
素敵な汎用リバース操作については知りません。個々の名前付きタプルはx._asdict()、を使用して辞書に変換できます。これは、単純なケースに役立つ場合があります。
DS。

127

タイトルのセクションチェックアウトデコードJSONオブジェクトを専門json モジュールのドキュメントを。これを使用して、JSONオブジェクトを特定のPythonタイプにデコードできます。

次に例を示します。

class User(object):
    def __init__(self, name, username):
        self.name = name
        self.username = username

import json
def object_decoder(obj):
    if '__type__' in obj and obj['__type__'] == 'User':
        return User(obj['name'], obj['username'])
    return obj

json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}',
           object_hook=object_decoder)

print type(User)  # -> <type 'type'>

更新

jsonモジュールを介して辞書のデータにアクセスする場合は、次のようにします。

user = json.loads('{"__type__": "User", "name": "John Smith", "username": "jsmith"}')
print user['name']
print user['username']

通常の辞書のように。


1
ほら、読んでただけで、辞書が完全に機能することに気づきました。JSONオブジェクトを辞書に変換する方法と、辞書からこのデータにアクセスする方法を知りたいだけなのです。
サイクリシュナ

すごい、ほぼ明らかですが、このオブジェクトがある場合、もう1つ小さなことを知りたいだけです-> {'education':{'name1':456、 'name2':567}}、このデータにアクセスするにはどうすればよいですか
サイクリシュナ

topLevelData ['education'] ['name1'] ==> 456になります。
Shakakai

1
@ベン:あなたのコメントは不適切だと思います。ここでのすべての答えの中で、現在、クラスを正しく理解するのはそれだけです。つまり、これはワンパス操作であり、結果は正しいタイプを使用します。Pickle自体はJSON(バイナリとテキストの両方の表現)とは異なるアプリケーション用であり、jsonpickleは非標準のlibです。std json libがオブジェクトフックに上位解析ツリーを提供しないという問題をどのように解決するのか興味があります
cfi

@Benに同意する必要があります。これは本当に悪い解決策です。まったくスケーラブルではありません。フィールドの名前を文字列およびフィールドとして保持する必要があります。フィールドをリファクタリングしたい場合、デコードは失敗します(もちろん、すでにシリアル化されたデータはもはや関連性がなくなります)。同じコンセプトがjsonpickleで
guyarad

98

これはコードゴルフではありませんが、ここで私の最短のトリックは、 types.SimpleNamespace JSONオブジェクトのコンテナーとしてする、です。

主要なnamedtupleソリューションと比較すると、次のとおりです。

  • 各オブジェクトのクラスを作成しないため、おそらくより速く/小さくなります
  • より短い
  • renameオプションはなく、おそらく有効な識別子ではないキーに対する同じ制限(setattrカバーの下で使用)

例:

from __future__ import print_function
import json

try:
    from types import SimpleNamespace as Namespace
except ImportError:
    # Python 2.x fallback
    from argparse import Namespace

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

x = json.loads(data, object_hook=lambda d: Namespace(**d))

print (x.name, x.hometown.name, x.hometown.id)

2
ちなみに、シリアライゼーションライブラリMarshmallowは、@post_loadデコレータで同様の機能を提供します。marshmallow.readthedocs.io/en/latest/...
テイラーEdmiston

3
argparseへの依存を避けるために:でargparse輸入を交換from types import SimpleNamespaceし、使用:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
maxschlepzig

8
これは最もエレガントなソリューションであり、一番上にあるはずです。
ScalaWilliam 2016

4
Python 3.xで実行するときに@maxschlepzigのソリューションを使用するように編集されました(types.SimpleNamespace残念ながら2.7には存在しません)。
Dan Lenski 2017

1
なんでprint_function
chwi

90

あなたはこれを試すことができます:

class User(object):
    def __init__(self, name, username, *args, **kwargs):
        self.name = name
        self.username = username

import json
j = json.loads(your_json)
u = User(**j)

新しいオブジェクトを作成し、パラメーターをマップとして渡すだけです。


1
TypeErrorが表示されます: 'User'オブジェクトは下付きではありません
Mahdi

1
これは受け入れられる答えになるはずです。他のすべてよりもはるかに簡単に私のために働いた。
Izik

* args、** kwargsは使用しませんでしたが、解決策は機能しました。
マルカビアーノ

1
User(** j)は、名前とユーザー名のパラメーターが不足していると言います。また、dictはどのように初期化されますか?
アーロンステインバック

40

ここでは、すばやく汚れたjson pickleの代替案を示します

import json

class User:
    def __init__(self, name, username):
        self.name = name
        self.username = username

    def to_json(self):
        return json.dumps(self.__dict__)

    @classmethod
    def from_json(cls, json_str):
        json_dict = json.loads(json_str)
        return cls(**json_dict)

# example usage
User("tbrown", "Tom Brown").to_json()
User.from_json(User("tbrown", "Tom Brown").to_json()).to_json()

1
これは良い方法ではありません。最初は、to_jsonとfrom_jsonをクラスに配置しないでください。次に、ネストされたクラスでは機能しません。
ジュラス

17

複雑なオブジェクトの場合、JSON Pickleを使用できます

任意のオブジェクトグラフをJSONにシリアル化するためのPythonライブラリ。ほとんどすべてのPythonオブジェクトを受け取り、オブジェクトをJSONに変換できます。さらに、オブジェクトをPythonに再構成できます。


6
jsonstructの方が良いと思います。 jsonstruct originally a fork of jsonpickle (Thanks guys!). The key difference between this library and jsonpickle is that during deserialization, jsonpickle requires Python types to be recorded as part of the JSON. This library intends to remove this requirement, instead, requires a class to be passed in as an argument so that its definition can be inspected. It will then return an instance of the given class. This approach is similar to how Jackson (of Java) works.
Abhishek Gupta 2016

3
jsonstructの問題は、jsonstructが維持されていないように見え(実際には破棄されているように見える)、のようなオブジェクトのリストの変換に失敗すること'[{"name":"object1"},{"name":"object2"}]'です。jsonpickleもうまく処理できません。
LS

1
なぜこの回答がより多くの票を得ていないのか私にはわかりません。他のほとんどの解決策はまったくありません。誰かがJSONデシリアライゼーションのための素晴らしいライブラリを開発しました-なぜそれを使わないのですか?さらに、リストで問題なく動作しているようです-@LSの問題は何でしたか?
Guyarad

1
@guyarad、問題は次のとおりです:x = jsonpickle.decode( '[{"name": "object1"}、{"name": "object2"}]')は、辞書のリストを提供します([{'name': ' object1 '}、{' name ':' object2 '}])、プロパティ(x [0] .name ==' object1 ')を持つオブジェクトのリストではなく、これは元の質問で必要でした。それを得るために、私はeddygeekによって提案されたobject_hook / Namespaceアプローチを使用することになりましたが、ubershmekelによるクイック/ダーティーアプローチも良さそうです。jsonpickleのset_encoder_options()(ドキュメント化されていません!)でobject_hookを使用できると思いますが、基本的なjsonモジュールよりも多くのコードが必要になります。私は間違っていることが証明されたいです!
LS

@LSあなたが入力を制御できない場合、これは本当にOPが求めたものであり、jsonpickleは各レベルの実際のタイプを期待するため(そして欠落している場合は基本タイプを想定するため)理想的ではありません。どちらのソリューションも「かわいい」です。
Guyarad

12

Python 3.5以降を使用jsonsしている場合は、を使用して、古いPythonオブジェクトをシリアル化および逆シリアル化できます。

import jsons

response = request.POST

# You'll need your class attributes to match your dict keys, so in your case do:
response['id'] = response.pop('user_id')

# Then you can load that dict into your class:
user = jsons.load(response, FbApiUser)

user.save()

よりエレガントにするために、FbApiUser継承元にすることもできますjsons.JsonSerializable

user = FbApiUser.from_json(response)

これらの例は、クラスが文字列、整数、リスト、日時などのPythonのデフォルトの型で構成されている場合に機能しますjsons。ただし、ライブラリにはカスタム型の型ヒントが必要です。


7

Python 3.6以降を使用している場合は、marshmallow-dataclassを使用できます。上記のすべてのソリューションとは対照的に、それは単純であり、タイプセーフです。

from marshmallow_dataclass import dataclass

@dataclass
class User:
    name: str

user, err = User.Schema().load({"name": "Ramirez"})

TypeError: make_data_class() got an unexpected keyword argument 'many'
ジョン

@ジョン:あなたがで再現可能なテストケースで問題を開く必要がありgithub.com/lovasoa/marshmallow_dataclass/issues
lovasoa

5

2つのPythonタイプ間で複雑な変換を行うのに役立つ、any2anyと呼ばれる小さな(非)シリアライゼーションフレームワークを作成しました。

あなたの場合、私はあなたが辞書(で得られたjson.loads)から複雑なオブジェクトresponse.education ; response.name、ネストされた構造response.education.idなどに変換したいと思います...それで、まさにこのフレームワークが作られています。ドキュメントはまだ素晴らしいものではありませんが、を使用any2any.simple.MappingToObjectすることで、非常に簡単にできるはずです。助けが必要かどうか尋ねてください。


Sebpiqはany2anyをインストールしており、メソッド呼び出しの意図されたシーケンスを理解するのに問題があります。辞書を各キーのプロパティを持つPythonオブジェクトに変換する簡単な例を挙げていただけませんか?
sansjoe

こんにちは@sansjoe!pypiからインストールした場合、バージョンは完全に古く、数週間前に完全なリファクタリングを行いました。githubバージョンを使用する必要があります(適切なリリースを作成する必要があります!)
sebpiq

githubがpypyからインストールするように言ったので、pypyからインストールしました。また、pypyは数か月前に古くなったと言っていました。それは機能しませんでした:(バグレポートを提出しました!github.com/sebpiq/any2any/issues/11
sneilan

5

ロヴァソアの非常に良い答えを改善する。

あなたのpython 3.6以降を使用している場合は、使用することができます
pip install marshmallow-enumし、
pip install marshmallow-dataclass

そのシンプルでタイプセーフです。

クラスをstring-jsonに変換したり、その逆を行うことができます。

ObjectからString Jsonへ:

    from marshmallow_dataclass import dataclass
    user = User("Danilo","50","RedBull",15,OrderStatus.CREATED)
    user_json = User.Schema().dumps(user)
    user_json_str = user_json.data

String JsonからObjectへ:

    json_str = '{"name":"Danilo", "orderId":"50", "productName":"RedBull", "quantity":15, "status":"Created"}'
    user, err = User.Schema().loads(json_str)
    print(user,flush=True)

クラス定義:

class OrderStatus(Enum):
    CREATED = 'Created'
    PENDING = 'Pending'
    CONFIRMED = 'Confirmed'
    FAILED = 'Failed'

@dataclass
class User:
    def __init__(self, name, orderId, productName, quantity, status):
        self.name = name
        self.orderId = orderId
        self.productName = productName
        self.quantity = quantity
        self.status = status

    name: str
    orderId: str
    productName: str
    quantity: int
    status: OrderStatus

1
コンストラクタは必要ありません。init= Trueをdataclassに渡すだけで問題ありません。
Josef Korbel

4

誰も私のように答えを提供してくれなかったので、ここに投稿します。

これは、簡単にJSONの間で前後に変換することができます強力なクラスであるstrdict私はからコピーしたことを別の質問に対する私の答え

import json

class PyJSON(object):
    def __init__(self, d):
        if type(d) is str:
            d = json.loads(d)

        self.from_dict(d)

    def from_dict(self, d):
        self.__dict__ = {}
        for key, value in d.items():
            if type(value) is dict:
                value = PyJSON(value)
            self.__dict__[key] = value

    def to_dict(self):
        d = {}
        for key, value in self.__dict__.items():
            if type(value) is PyJSON:
                value = value.to_dict()
            d[key] = value
        return d

    def __repr__(self):
        return str(self.to_dict())

    def __setitem__(self, key, value):
        self.__dict__[key] = value

    def __getitem__(self, key):
        return self.__dict__[key]

json_str = """... json string ..."""

py_json = PyJSON(json_str)

2

@DS応答を少し変更して、ファイルからロードします。

def _json_object_hook(d): return namedtuple('X', d.keys())(*d.values())
def load_data(file_name):
  with open(file_name, 'r') as file_data:
    return file_data.read().replace('\n', '')
def json2obj(file_name): return json.loads(load_data(file_name), object_hook=_json_object_hook)

1つ:これは、前の番号を持つ項目をロードできません。このような:

{
  "1_first_item": {
    "A": "1",
    "B": "2"
  }
}

「1_first_item」は有効なPythonフィールド名ではないためです。


2

解決策を探しているときに、このブログ投稿に遭遇しました:https : //blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/

前の回答で述べたのと同じテクニックを使用しますが、デコレータを使用します。もう1つ私が便利だと思ったのは、逆シリアル化の最後に型指定されたオブジェクトを返すということです。

class JsonConvert(object):
    class_mappings = {}

    @classmethod
    def class_mapper(cls, d):
        for keys, cls in clsself.mappings.items():
            if keys.issuperset(d.keys()):   # are all required arguments present?
                return cls(**d)
        else:
            # Raise exception instead of silently returning None
            raise ValueError('Unable to find a matching class for object: {!s}'.format(d))

    @classmethod
    def complex_handler(cls, Obj):
        if hasattr(Obj, '__dict__'):
            return Obj.__dict__
        else:
            raise TypeError('Object of type %s with value of %s is not JSON serializable' % (type(Obj), repr(Obj)))

    @classmethod
    def register(cls, claz):
        clsself.mappings[frozenset(tuple([attr for attr,val in cls().__dict__.items()]))] = cls
        return cls

    @classmethod
    def to_json(cls, obj):
        return json.dumps(obj.__dict__, default=cls.complex_handler, indent=4)

    @classmethod
    def from_json(cls, json_str):
        return json.loads(json_str, object_hook=cls.class_mapper)

使用法:

@JsonConvert.register
class Employee(object):
    def __init__(self, Name:int=None, Age:int=None):
        self.Name = Name
        self.Age = Age
        return

@JsonConvert.register
class Company(object):
    def __init__(self, Name:str="", Employees:[Employee]=None):
        self.Name = Name
        self.Employees = [] if Employees is None else Employees
        return

company = Company("Contonso")
company.Employees.append(Employee("Werner", 38))
company.Employees.append(Employee("Mary"))

as_json = JsonConvert.to_json(company)
from_json = JsonConvert.from_json(as_json)
as_json_from_json = JsonConvert.to_json(from_json)

assert(as_json_from_json == as_json)

print(as_json_from_json)

2

DSの答えを少し拡張すると、オブジェクトを変更可能にする必要がある場合(namedtupleは不可)、namedtupleの代わりにレコードクラスライブラリを使用できます。

import json
from recordclass import recordclass

data = '{"name": "John Smith", "hometown": {"name": "New York", "id": 123}}'

# Parse into a mutable object
x = json.loads(data, object_hook=lambda d: recordclass('X', d.keys())(*d.values()))

変更されたオブジェクトは、simplejsonを使用して非常に簡単にjsonに戻すことができます。

x.name = "John Doe"
new_json = simplejson.dumps(x)

1

Python 3.6以降を使用している場合は、静的に型指定されたデータ構造用の軽量モジュールであるsquemaを確認できます。コードを読みやすくすると同時に、追加の作業なしで簡単なデータ検証、変換、およびシリアル化を提供します。名前付きタプルやデータクラスに代わる、より洗練された独断的な選択肢と考えることができます。使用方法は次のとおりです。

from uuid import UUID
from squema import Squema


class FbApiUser(Squema):
    id: UUID
    age: int
    name: str

    def save(self):
        pass


user = FbApiUser(**json.loads(response))
user.save()

これは、JVM言語の方法と似ています。
javadba

1

私はうまくいった解決策を探していました recordclass.RecordClassで動作、ネストされたオブジェクトをサポート、jsonシリアル化とjson逆シリアル化の両方。

DSの答えを拡張し、BeneStrからのソリューションを拡張すると、うまくいくように見える次のことがわかりました。

コード:

import json
import recordclass

class NestedRec(recordclass.RecordClass):
    a : int = 0
    b : int = 0

class ExampleRec(recordclass.RecordClass):
    x : int       = None
    y : int       = None
    nested : NestedRec = NestedRec()

class JsonSerializer:
    @staticmethod
    def dumps(obj, ensure_ascii=True, indent=None, sort_keys=False):
        return json.dumps(obj, default=JsonSerializer.__obj_to_dict, ensure_ascii=ensure_ascii, indent=indent, sort_keys=sort_keys)

    @staticmethod
    def loads(s, klass):
        return JsonSerializer.__dict_to_obj(klass, json.loads(s))

    @staticmethod
    def __obj_to_dict(obj):
        if hasattr(obj, "_asdict"):
            return obj._asdict()
        else:
            return json.JSONEncoder().default(obj)

    @staticmethod
    def __dict_to_obj(klass, s_dict):
        kwargs = {
            key : JsonSerializer.__dict_to_obj(cls, s_dict[key]) if hasattr(cls,'_asdict') else s_dict[key] \
                for key,cls in klass.__annotations__.items() \
                    if s_dict is not None and key in s_dict
        }
        return klass(**kwargs)

使用法:

example_0 = ExampleRec(x = 10, y = 20, nested = NestedRec( a = 30, b = 40 ) )

#Serialize to JSON

json_str = JsonSerializer.dumps(example_0)
print(json_str)
#{
#  "x": 10,
#  "y": 20,
#  "nested": {
#    "a": 30,
#    "b": 40
#  }
#}

# Deserialize from JSON
example_1 = JsonSerializer.loads(json_str, ExampleRec)
example_1.x += 1
example_1.y += 1
example_1.nested.a += 1
example_1.nested.b += 1

json_str = JsonSerializer.dumps(example_1)
print(json_str)
#{
#  "x": 11,
#  "y": 21,
#  "nested": {
#    "a": 31,
#    "b": 41
#  }
#}

1

ここで与えられた答えは正しいオブジェクトタイプを返さないので、以下にこれらのメソッドを作成しました。指定されたJSONに存在しないクラスにフィールドを追加しようとした場合も失敗します。

def dict_to_class(class_name: Any, dictionary: dict) -> Any:
    instance = class_name()
    for key in dictionary.keys():
        setattr(instance, key, dictionary[key])
    return instance


def json_to_class(class_name: Any, json_string: str) -> Any:
    dict_object = json.loads(json_string)
    return dict_to_class(class_name, dict_object)

0

Python3.x

私の知識で到達できる最高のアプローチはこれでした。
このコードはset()も扱うことに注意してください。
このアプローチは、(2番目の例の)クラスの拡張が必要な​​だけの一般的なものです。
ファイルに対して行っているだけですが、動作を好みに合わせて変更するのは簡単です。

ただし、これはCoDecです。

もう少し作業を行うと、他の方法でクラスを構築できます。それをインスタンス化するデフォルトのコンストラクターを想定し、クラスdictを更新します。

import json
import collections


class JsonClassSerializable(json.JSONEncoder):

    REGISTERED_CLASS = {}

    def register(ctype):
        JsonClassSerializable.REGISTERED_CLASS[ctype.__name__] = ctype

    def default(self, obj):
        if isinstance(obj, collections.Set):
            return dict(_set_object=list(obj))
        if isinstance(obj, JsonClassSerializable):
            jclass = {}
            jclass["name"] = type(obj).__name__
            jclass["dict"] = obj.__dict__
            return dict(_class_object=jclass)
        else:
            return json.JSONEncoder.default(self, obj)

    def json_to_class(self, dct):
        if '_set_object' in dct:
            return set(dct['_set_object'])
        elif '_class_object' in dct:
            cclass = dct['_class_object']
            cclass_name = cclass["name"]
            if cclass_name not in self.REGISTERED_CLASS:
                raise RuntimeError(
                    "Class {} not registered in JSON Parser"
                    .format(cclass["name"])
                )
            instance = self.REGISTERED_CLASS[cclass_name]()
            instance.__dict__ = cclass["dict"]
            return instance
        return dct

    def encode_(self, file):
        with open(file, 'w') as outfile:
            json.dump(
                self.__dict__, outfile,
                cls=JsonClassSerializable,
                indent=4,
                sort_keys=True
            )

    def decode_(self, file):
        try:
            with open(file, 'r') as infile:
                self.__dict__ = json.load(
                    infile,
                    object_hook=self.json_to_class
                )
        except FileNotFoundError:
            print("Persistence load failed "
                  "'{}' do not exists".format(file)
                  )


class C(JsonClassSerializable):

    def __init__(self):
        self.mill = "s"


JsonClassSerializable.register(C)


class B(JsonClassSerializable):

    def __init__(self):
        self.a = 1230
        self.c = C()


JsonClassSerializable.register(B)


class A(JsonClassSerializable):

    def __init__(self):
        self.a = 1
        self.b = {1, 2}
        self.c = B()

JsonClassSerializable.register(A)

A().encode_("test")
b = A()
b.decode_("test")
print(b.a)
print(b.b)
print(b.c.a)

編集する

いくつかの調査により、メタクラスを使用して、SUPERCLASS registerメソッド呼び出しを必要とせずに一般化する方法を見つけました

import json
import collections

REGISTERED_CLASS = {}

class MetaSerializable(type):

    def __call__(cls, *args, **kwargs):
        if cls.__name__ not in REGISTERED_CLASS:
            REGISTERED_CLASS[cls.__name__] = cls
        return super(MetaSerializable, cls).__call__(*args, **kwargs)


class JsonClassSerializable(json.JSONEncoder, metaclass=MetaSerializable):

    def default(self, obj):
        if isinstance(obj, collections.Set):
            return dict(_set_object=list(obj))
        if isinstance(obj, JsonClassSerializable):
            jclass = {}
            jclass["name"] = type(obj).__name__
            jclass["dict"] = obj.__dict__
            return dict(_class_object=jclass)
        else:
            return json.JSONEncoder.default(self, obj)

    def json_to_class(self, dct):
        if '_set_object' in dct:
            return set(dct['_set_object'])
        elif '_class_object' in dct:
            cclass = dct['_class_object']
            cclass_name = cclass["name"]
            if cclass_name not in REGISTERED_CLASS:
                raise RuntimeError(
                    "Class {} not registered in JSON Parser"
                    .format(cclass["name"])
                )
            instance = REGISTERED_CLASS[cclass_name]()
            instance.__dict__ = cclass["dict"]
            return instance
        return dct

    def encode_(self, file):
        with open(file, 'w') as outfile:
            json.dump(
                self.__dict__, outfile,
                cls=JsonClassSerializable,
                indent=4,
                sort_keys=True
            )

    def decode_(self, file):
        try:
            with open(file, 'r') as infile:
                self.__dict__ = json.load(
                    infile,
                    object_hook=self.json_to_class
                )
        except FileNotFoundError:
            print("Persistence load failed "
                  "'{}' do not exists".format(file)
                  )


class C(JsonClassSerializable):

    def __init__(self):
        self.mill = "s"


class B(JsonClassSerializable):

    def __init__(self):
        self.a = 1230
        self.c = C()


class A(JsonClassSerializable):

    def __init__(self):
        self.a = 1
        self.b = {1, 2}
        self.c = B()


A().encode_("test")
b = A()
b.decode_("test")
print(b.a)
# 1
print(b.b)
# {1, 2}
print(b.c.a)
# 1230
print(b.c.c.mill)
# s

0

使用できます

x = Map(json.loads(response))
x.__class__ = MyClass

どこ

class Map(dict):
    def __init__(self, *args, **kwargs):
        super(Map, self).__init__(*args, **kwargs)
        for arg in args:
            if isinstance(arg, dict):
                for k, v in arg.iteritems():
                    self[k] = v
                    if isinstance(v, dict):
                        self[k] = Map(v)

        if kwargs:
            # for python 3 use kwargs.items()
            for k, v in kwargs.iteritems():
                self[k] = v
                if isinstance(v, dict):
                    self[k] = Map(v)

    def __getattr__(self, attr):
        return self.get(attr)

    def __setattr__(self, key, value):
        self.__setitem__(key, value)

    def __setitem__(self, key, value):
        super(Map, self).__setitem__(key, value)
        self.__dict__.update({key: value})

    def __delattr__(self, item):
        self.__delitem__(item)

    def __delitem__(self, key):
        super(Map, self).__delitem__(key)
        del self.__dict__[key]

汎用的で将来性のあるソリューション。


-5

jsonモジュールPython 2.6の新機能)またはsimplejsonほとんど常にインストールされるモジュールを使用します


2
お返事ありがとうございます。JSONをデコードしてそのデータにアクセスする方法の例を投稿していただけますか?
サイクリシュナ

ねえ、あなたはポイントを手に入れましたが、どういうわけか、私はそれを知らずにやって、それをリバースエンジニアリングすることを好みます:D.
サイ・クリシュナ

1
@Zach:リンクしたドキュメントの一番上に例があります。
Chris Morgan
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.