JSON verilerini bir Python nesnesine dönüştürme


281

JSON verilerini bir Python nesnesine dönüştürmek için Python kullanmak istiyorum.

Veritabanımda saklamak istediğim Facebook API'sinden JSON veri nesneleri alıyorum.

Geçerli görünümüm Django (Python) ( request.POSTJSON içerir):

response = request.POST
user = FbApiUser(user_id = response['id'])
user.name = response['name']
user.username = response['username']
user.save()
  • Bu iyi çalışıyor, ancak karmaşık JSON veri nesnelerini nasıl işleyebilirim?

  • Bu JSON nesnesini bir şekilde kolay kullanım için bir Python nesnesine dönüştürürsem çok daha iyi olmaz mıydı?


Tipik olarak JSON, vanilya listelerine veya emirlerine dönüştürülür. İstediğin bu mu? Yoksa JSON'u doğrudan özel bir türe dönüştürmeyi mi umuyorsunuz?
Shakakai

Bir nesneye dönüştürmek istiyorum, "." Kullanarak erişebileceğim bir şey. . Yukarıdaki örnekte olduğu gibi -> reponse.name, response.education.id vb ....
Sai Krishna

44
S kullanmak dictnesne yönelimli programlama yapmak için zayıf soslu bir yoldur. Sözlükler, beklentilerinizi kodunuzun okuyucularına iletmenin çok kötü bir yoludur. Bir sözlük kullanarak, bazı sözlük anahtar / değer çiftlerinin gerekli olduğunu, bazılarının gerekmediğini nasıl açıkça ve tekrar tekrar belirtebilirsiniz? Belirli bir değerin kabul edilebilir aralıkta veya ayarlanmış olduğunu doğrulamaya ne dersiniz? Çalıştığınız nesnenin türüne özgü işlevler (diğer yöntemler olarak da bilinir) ne olacak? Sözlükler kullanışlı ve çok yönlüdür, ancak çok fazla devs, Python'un bir nedenden dolayı nesneye yönelik bir dil olduğunu unutmuş gibi davranır.
Yahni

1
Bu github.com/jsonpickle/jsonpickle için bir python kütüphanesi var (cevap iş parçacığında çok aşağıda olduğundan ve ulaşılamayacağından yorum yapıyor.)
En iyi dileklerimle

Yanıtlar:


356

Sen kullanarak, tek satırda bunu yapabilir namedtupleve 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

veya bunu kolayca yeniden kullanmak için:

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)

Eğer, iyi nitelik isimler değil anahtarları işlemek kontrol etmek istiyorsanız namedtuple'ın renameparametresini .


8
bu bir Değer hatasıyla sonuçlanabilir, ValueError: Tür adları ve alan adları bir sayı ile başlayamaz: '123'
PvdL

3
Python'a yeni başlayan biri olarak, güvenlik sorunu olduğunda da bu tasarruflu bir şey olup olmadığını merak ediyorum.
benjist

8
Bu, ayrıştırırken her JSON nesnesiyle karşılaştığında farklı bir sınıf yaratır , değil mi?
fikr4n

2
İlginç. Aynı sırayla güvenmeyi d.keys()ve d.values()yinelemeyi garanti ettim, ama yanılmışım. Dokümanlar ki: "anahtarlar, değerler ve ürün görünümleri sözlüğe hiçbir müdahalede değişiklik ile iterated ise, öğelerin sırası doğrudan will karşılık gelmektedir.". Böyle küçük, yerel kod blokları için bilmek güzel. Ben böyle bir bağımlılığın kod koruyucular açıkça uyarmak için olsa bir yorum eklemek istiyorum.
cfi

1
Herhangi bir genel amaçlı ters işlemin farkında değilim. Adlandırılmış herhangi bir birey x._asdict(), basit durumlar için yardımcı olabilecek bir dikteye dönüştürülebilir .
DS.

127

Başlıklı bölümüne göz atın deşifre JSON nesnesi uzmanlaşmış içinde json modül belgelerinde . Bir JSON nesnesini belirli bir Python türüne çözmek için bunu kullanabilirsiniz.

İşte bir örnek:

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'>

Güncelleme

Bir sözlükteki verilere json modülü aracılığıyla erişmek istiyorsanız, bunu yapın:

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

Tıpkı normal bir sözlük gibi.


1
Hey, sadece okuyordum ve sözlüklerin tamamen yapacağını fark ettim, sadece JSON nesnelerini sözlüklere nasıl dönüştüreceğimizi ve bu verilere sözlükten nasıl erişebileceğimi merak ediyordum?
Sai Krishna

Harika, neredeyse açık, sadece bu nesne varsa -> {'eğitim': {'ad1': 456, 'ad2': 567}}, bu verilere nasıl erişebilirim?
Sai Krishna

sadece topLevelData ['education'] ['name1'] ==> 456 olur.
Shakakai

1
@Ben: Bence yorumunuz uygunsuz. Buradaki tüm cevaplardan şu anda sınıfları doğru yapan tek kişi bu. Bu şu anlama geliyor: Tek geçişli bir işlem ve sonuç doğru türleri kullanıyor. Turşunun kendisi JSON'dan (ikili ve metinsel rep'den) farklı uygulamalar içindir ve jsonpickle standart olmayan bir lib'dir. Std json
lib'in

Bu konuda @Ben ile hemfikirim. Bu gerçekten kötü bir çözüm. Hiç ölçeklenemez. Alan adlarını dize ve alan olarak tutmanız gerekir. Alanlarınızı yeniden düzenlemek istiyorsanız, kod çözme başarısız olur (elbette zaten serileştirilmiş veriler artık alakalı olmayacaktır). Aynı kavram zaten jsonpickle
guyarad

99

Bu kod golf değil, ama types.SimpleNamespaceJSON nesneleri için kapsayıcı olarak kullanarak, benim en kısa hiledir .

Önde gelen namedtupleçözümle karşılaştırıldığında :

  • muhtemelen her nesne için bir sınıf yaratmadığından daha hızlı / daha küçüktür
  • daha kısa
  • renameseçenek yok ve muhtemelen geçerli tanımlayıcı olmayan anahtarlarda aynı sınırlama ( setattrkapakların altında kullanır )

Misal:

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
Bu arada, serileştirme kütüphanesi Marshmallow, @post_loaddekoratörü ile benzer bir özellik sunuyor . marshmallow.readthedocs.io/en/latest/…
Taylor Edmiston

3
Argparse bağımlılığını önlemek için: argparse içe aktarma ile değiştirin from types import SimpleNamespaceve kullanın:x = json.loads(data, object_hook=lambda d: SimpleNamespace(**d))
maxschlepzig

8
Bu en zarif çözüm, en üstte olmalı.
ScalaWilliam

4
Python 3.x altında çalışırken @ maxschlepzig'in çözümünü kullanmak için düzenlendi ( types.SimpleNamespacemaalesef 2.7'de mevcut değil).
Dan Lenski

1
neden print_function?
chwi

90

Bunu deneyebilirsiniz:

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)

Yeni bir Nesne oluşturun ve parametreleri harita olarak iletin.


1
TypeError alıyorum: 'Kullanıcı' nesnesi abone olamaz
Mehdi

1
Bu kabul edilen cevap olmalı. benim için çalıştı diğerlerinden çok daha basit reklam.
İzik

* Args, ** kwargs kullanmadım ama çözüm işe yaradı.
Malkaviano

1
Kullanıcı (** j), ad ve kullanıcı adı parametrelerini kaçırdığını söylüyor, ayrıca sözlük nasıl başlatılır?
Aaron Stainback

40

İşte hızlı ve kirli bir json turşusu alternatifi

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
Bu iyi bir yaklaşım değil. İlk başta sınıfınıza to_json ve from_json yerleştirilmemelidir. İkincisi iç içe dersler için çalışmaz.
Jurass

17

Karmaşık nesneler için JSON Pickle'ı kullanabilirsiniz

Herhangi bir keyfi nesne grafiğini JSON'a serileştirmek için Python kütüphanesi. Neredeyse tüm Python nesnelerini alabilir ve nesneyi JSON'a dönüştürebilir. Ayrıca, nesneyi yeniden Python'a yeniden oluşturabilir.


6
Bence jsonstruct daha iyi. 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

3
Jsonstruct ile ilgili sorunlar, bakımlı görünmüyor (aslında terk edilmiş görünüyor) ve gibi bir nesne listesini dönüştüremediğidir '[{"name":"object1"},{"name":"object2"}]'. jsonpickle da çok iyi idare etmiyor.
LS

1
Bu cevabın neden daha fazla oy alamadığını bilmiyorum. Diğer birçok çözüm oldukça dışarıda. Birisi JSON de / serialization için harika bir kütüphane geliştirdi - neden kullanmıyorsunuz? Buna ek olarak, listelerle iyi çalışıyor gibi görünüyor - @LS ile ilgili sorununuz neydi?
guyarad

1
@guyarad, sorun: x = jsonpickle.decode ('[{"ad": "nesne1"}, {"ad": "nesne2"}]') sözlüklerin bir listesini verir ([{'ad': ' object1 '}, {' name ':' object2 '}]), orijinal sorunun gerektirdiği özelliklere (x [0] .name ==' object1 ') sahip nesnelerin listesi değil. Bunu elde etmek için, eddygeek tarafından önerilen object_hook / Namespace yaklaşımını kullandım, ancak ubershmekel'in hızlı / kirli yaklaşımı da iyi görünüyor. Ben jsonpickle'ın set_encoder_options () (belgesiz!) İle object_hook kullanabilirsiniz düşünüyorum, ama temel json modülünden daha fazla kod alacaktı. Yanlış kanıtlanmayı çok isterim!
LS

@LS giriş üzerinde herhangi bir kontrole sahip değilseniz, bu gerçekten OP'nin istediği şeydir, jsonpickle her seviyede gerçek türü beklediğinden (ve eksikse temel türleri varsayacaktır) ideal değildir. Her iki çözüm de "sevimli".
guyarad

12

Python 3.5+ kullanıyorsanız, jsonsdüz eski Python nesnelerini serileştirmek ve serisini kaldırmak için kullanabilirsiniz :

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()

Daha fazla zarafet için FbApiUsermiras alabilirsiniz jsons.JsonSerializable:

user = FbApiUser.from_json(response)

Bu örnekler, sınıfınız dizeler, tamsayılar, listeler, tarihler, vb. Gibi Python varsayılan türlerinden oluşuyorsa çalışacaktır. jsonsLib, özel türler için tür ipuçları gerektirir.



6

Lovasoa'nın çok iyi cevabını geliştirmek.

Python 3.6+ kullanıyorsanız, aşağıdakileri kullanabilirsiniz:
pip install marshmallow-enumve
pip install marshmallow-dataclass

Basit ve tip güvenlidir.

Sınıfınızı bir string-json ve tersi şekilde dönüştürebilirsiniz:

Nesneden Dizeye 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'dan Object'e:

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

Sınıf tanımları:

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
Yapıcıya ihtiyacınız yok, sadece init = Dataclass True'ya geçin ve gitmekte fayda var.
Josef Korbel

5

İki Python türü arasında karmaşık dönüşümler yapmaya yardımcı olan any2any adlı küçük (de) serileştirme çerçevesi yazdım .

Sizin durumunuzda, sanırım bir sözlükten (ile elde edilen json.loads) karmaşık bir nesneye response.education ; response.name, iç içe bir yapıya response.education.idvb . Dönüştürmek istiyorsunuz ... Yani bu çerçeve tam olarak bunun için yapılmıştır. Dokümantasyon henüz mükemmel değil, ancak any2any.simple.MappingToObjectbunu kullanarak bunu kolayca yapabilmelisiniz. Lütfen yardıma ihtiyacınız varsa sorun.


Sebpiq, any2any'yi kurdu ve yöntem çağrılarının amaçlanan sırasını anlamada sorun yaşıyorum. Her anahtar için bir özelliği olan bir Python nesnesine sözlük dönüştürmenin basit bir örneğini verebilir misiniz?
sansjoe

Merhaba @sansjoe! Eğer pypi'den yüklediyseniz, sürüm tamamen güncel değil, birkaç hafta önce tam bir yeniden düzenleme yaptım. Github sürümünü kullanmalısınız (Doğru bir sürüm yapmam gerekiyor!)
sebpiq

Bunu pypy'den kurdum çünkü github pypy'den kurmayı söyledi. ! Ayrıca, Ben tho bir hata raporu yayımlandı :( eser yoktu .. PYPY önce tarih aylar dışında olduğunu söyledi github.com/sebpiq/any2any/issues/11
sneilan

4

Kimse benimki gibi bir cevap vermediğinden, buraya göndereceğim.

Kolayca json arasında ileri ve geri dönüştürebilir sağlam sınıftır strve dictben kopyalanmış olduğunu başka soruya cevabım :

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

Bir dosyadan yüklemek için @DS yanıtını biraz değiştirerek:

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)

Bir şey: bu sayıları olan öğeleri yükleyemez. Bunun gibi:

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

Çünkü "1_first_item" geçerli bir python alan adı değil.


2

Bir çözüm ararken, bu blog gönderisine rastladım: https://blog.mosthege.net/2016/11/12/json-deserialization-of-nested-objects/

Önceki cevaplarda belirtilenle aynı tekniği kullanır, ancak dekoratörler kullanır. Yararlı bulduğum başka bir şey, serileştirmenin sonunda yazılan bir nesneyi döndürmesi.

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)

Kullanımı:

@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'nin cevabını biraz genişleterek, nesnenin değiştirilebilir olması gerekiyorsa (adlandırılmış grup değil), adlandırılmış kayıt yerine kayıt sınıfı kitaplığını kullanabilirsiniz :

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()))

Değiştirilmiş nesne daha sonra simplejson kullanılarak kolayca json'a dönüştürülebilir :

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

1

Python 3.6 veya daha yenisini kullanıyorsanız , statik olarak yazılan veri yapıları için hafif bir modül olan squema'ya bakabilirsiniz . Kodunuzun okunmasını kolaylaştırırken aynı zamanda ekstra veri olmadan basit veri doğrulama, dönüştürme ve serileştirme sağlar. Bunu adlandırılmış üçlü ve veri belgelerine daha sofistike ve düşünceli bir alternatif olarak düşünebilirsiniz. Bunu nasıl kullanabileceğiniz aşağıda açıklanmıştır:

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()

Bu, JVM dilinin bunu yapmasına daha çok benzer.
javadba

1

recordclass.RecordClassBirlikte çalışan, iç içe geçmiş nesneleri destekleyen ve hem json serileştirme hem de json serileştirme için çalışan bir çözüm arıyordum .

DS'nin cevabına genişleyen ve BeneStr'in çözümünü genişleterek, işe yarayan aşağıdakileri buldum:

Kod:

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)

Kullanımı:

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

Burada verilen cevaplar doğru nesne türünü döndürmez, bu nedenle bu yöntemleri aşağıda oluşturdum. Ayrıca, verilen JSON'da bulunmayan sınıfa daha fazla alan eklemeye çalışırsanız da başarısız olurlar:

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

Bildiğim kadarıyla ulaşabileceğim en iyi yaklaşım bu.
Bu kod tedavi set () de unutmayın.
Bu yaklaşım, sınıfın genişletilmesine ihtiyaç duyan jeneriktir (ikinci örnekte).
Sadece dosyalara yaptığımı unutmayın, ancak davranışı zevkinize göre değiştirmek kolaydır.

Ancak bu bir CoDec.

Biraz daha fazla çalışma ile sınıfınızı başka şekillerde inşa edebilirsiniz. Örnek bir varsayılan yapıcı varsayalım, o zaman sınıf diksiyon güncelleyin.

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)

Düzenle

Biraz daha araştırma yaparak , bir metasınıf kullanarak SUPERCLASS kayıt yöntemi çağrısına ihtiyaç duymadan genellemenin bir yolunu buldum

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

Kullanabilirsiniz

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

nerede

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]

Genel, geleceğe dönük bir çözüm için.


-5

jsonModülü ( Python 2.6'da yeni olan ) veya simplejsonneredeyse her zaman takılı olan modülü kullanın .


2
Hey, cevap verdiğin için teşekkürler. JSON kodunun nasıl çözüleceğine ve daha sonra bu verilere nasıl erişileceğine ilişkin bir örnek gönderebilir misiniz?
Sai Krishna

Hey, şimdi bir noktan var ama bir şekilde, bilmeden yapmayı ve sonra tersine mühendislik yapmayı tercih ediyorum: D.
Sai Krishna

1
@Zach: Bağlandığım dokümanların hemen üstünde örnekler var.
Chris Morgan
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.