कैसे एक वर्ग JSON सीरियल बनाने के लिए


833

पायथन वर्ग को क्रमबद्ध कैसे बनाया जाए?

एक साधारण वर्ग:

class FileItem:
    def __init__(self, fname):
        self.fname = fname

आउटपुट प्राप्त करने के लिए मुझे क्या करना चाहिए:

>>> import json

>>> my_file = FileItem('/foo/bar')
>>> json.dumps(my_file)
TypeError: Object of type 'FileItem' is not JSON serializable

बिना त्रुटि के


30
यह दुर्भाग्यपूर्ण है कि सभी सवालों के जवाब देने लगते हैं "मैं एक वर्ग को कैसे अनुक्रमित करूं?" एक्शन प्रश्न के बजाय "मैं एक वर्ग को कैसे अनुक्रमित कर सकता हूं?" ये उत्तर मान लेते हैं कि आप ऑब्जेक्ट को किसी अन्य मॉड्यूल के साथ पारित करने के बजाय, इसे क्रमबद्ध रूप से कर रहे हैं, जो इसे क्रमबद्ध करता है।
काइल डेलानी

यदि आप Python3.5 + का उपयोग कर रहे हैं, तो आप jsons का उपयोग कर सकते हैं। यह आपकी वस्तु (और इसके सभी गुणों को पुनरावर्ती रूप से ) में परिवर्तित कर देगा । import jsonsनीचे उत्तर देखें - यह पूरी तरह से ठीक काम करता है
tswaehn 13

जवाबों:


551

क्या आपको अपेक्षित आउटपुट के बारे में पता है? उदाहरण के लिए यह करेंगे?

>>> f  = FileItem("/foo/bar")
>>> magic(f)
'{"fname": "/foo/bar"}'

उस स्थिति में आप केवल कॉल कर सकते हैं json.dumps(f.__dict__)

यदि आप अधिक अनुकूलित आउटपुट चाहते हैं तो आपको JSONEncoderअपने स्वयं के कस्टम क्रमांकन को उप-वर्ग और कार्यान्वित करना होगा।

एक तुच्छ उदाहरण के लिए, नीचे देखें।

>>> from json import JSONEncoder
>>> class MyEncoder(JSONEncoder):
        def default(self, o):
            return o.__dict__    

>>> MyEncoder().encode(f)
'{"fname": "/foo/bar"}'

फिर आप इस वर्ग को json.dumps()विधि में clskwarg के रूप में पास करते हैं :

json.dumps(cls=MyEncoder)

अगर आप भी डीकोड करना चाहते हैं तो आपको एक कस्टम object_hookको JSONDecoderक्लास में सप्लाई करना होगा । उदाहरण के लिए

>>> def from_json(json_object):
        if 'fname' in json_object:
            return FileItem(json_object['fname'])
>>> f = JSONDecoder(object_hook = from_json).decode('{"fname": "/foo/bar"}')
>>> f
<__main__.FileItem object at 0x9337fac>
>>> 

44
उपयोग करना __dict__सभी मामलों में काम नहीं करेगा। यदि ऑब्जेक्ट को त्वरित किया गया था, तो विशेषताओं को सेट नहीं किया गया है, __dict__पूरी तरह से आबादी नहीं हो सकती है। ऊपर दिए गए उदाहरण में, आप ठीक हैं, लेकिन यदि आपके पास वर्ग विशेषताएँ हैं जिन्हें आप भी एनकोड करना चाहते हैं, __dict__तो उन्हें तब तक सूचीबद्ध नहीं किया जाएगा जब तक कि उन्हें __init__ऑब्जेक्ट के तुरंत बाद क्लास की कॉल या किसी अन्य तरीके से संशोधित नहीं किया गया हो।
क्रिस हार्डी

8
+1, लेकिन from_json()ऑब्जेक्ट-हुक के रूप में उपयोग किए जाने वाले फ़ंक्शन में एक else: return json_objectबयान होना चाहिए , इसलिए यह सामान्य वस्तुओं के साथ भी निपट सकता है।
जोगोजपन

8
__dict__यदि आप __slots__एक नई शैली वर्ग का उपयोग करते हैं तो @KrisHardy भी काम नहीं करता है ।
badp

7
आप JSONEncoderकस्टम प्रोटोकॉल बनाने के लिए ऊपर के रूप में एक कस्टम का उपयोग कर सकते हैं , जैसे कि __json_serializable__विधि के अस्तित्व की जाँच करना और वस्तु का JSON अनुक्रमिक प्रतिनिधित्व प्राप्त करने के लिए इसे कॉल करना। यह अन्य अजगर पैटर्न की तरह ध्यान में रखते हुए किया जाएगा __getitem__, __str__, __eq__, और __len__
jpmc26

5
__dict__यह भी पुनरावर्ती रूप से काम नहीं करेगा, उदाहरण के लिए, यदि आपकी वस्तु का एक गुण दूसरी वस्तु है।
नील

634

यहाँ एक सरल सुविधा के लिए एक सरल समाधान है:

.toJSON() तरीका

JSON क्रमिक श्रेणी के बजाय, एक धारावाहिक विधि लागू करें:

import json

class Object:
    def toJSON(self):
        return json.dumps(self, default=lambda o: o.__dict__, 
            sort_keys=True, indent=4)

तो आप बस इसे क्रमबद्ध करने के लिए कहते हैं:

me = Object()
me.name = "Onur"
me.age = 35
me.dog = Object()
me.dog.name = "Apollo"

print(me.toJSON())

उत्पादन होगा:

{
    "age": 35,
    "dog": {
        "name": "Apollo"
    },
    "name": "Onur"
}

82
बहुत सीमित। यदि आपके पास एक प्रतिष्ठित {"फू": "बार", "बाज": "बल्ला"} है, जो आसानी से JSON पर प्रसारित होगा। यदि इसके बजाय आपके पास {"foo": "बार", "बाज": MyObject ()} है, तो आप नहीं कर सकते। आदर्श स्थिति यह होगी कि नेस्टेड वस्तुओं को स्पष्ट रूप से नहीं, बल्कि JSON के लिए अनुक्रमित किया जाता है।
मार्क ई। हासे

30
यह अभी भी काम करेगा। आप गायब हैं o.__dict___। अपने स्वयं के उदाहरण का प्रयास करें: class MyObject(): def __init__(self): self.prop = 1 j = json.dumps({ "foo": "bar", "baz": MyObject() }, default=lambda o: o.__dict__)
ओनुर येल्ड्रिम

14
क्या यह समाधान प्रतिवर्ती है? यानी क्या वस्तु को जसन से पुनर्निर्माण करना आसान है?
जॉर्ज लेइताओ

2
@ JCLeitão No. आप एक ही क्षेत्र के साथ दो अलग-अलग वर्ग हो सकते हैं। उस वर्ग की (और शायद समान गुणों वाली) वस्तुओं का समान a.__dict__/ होगा b.__dict__
मार्टिन थोमा

7
यह datetime.datetimeउदाहरणों के साथ काम नहीं करता है । यह निम्नलिखित त्रुटि फेंकता है:'datetime.datetime' object has no attribute '__dict__'
ब्रूनो फिंगर

171

अधिक जटिल कक्षाओं के लिए आप टूल जसनपिकल पर विचार कर सकते हैं :

jsonpickle, JSON से और इसके लिए जटिल पायथन ऑब्जेक्ट्स के क्रमांकन और डीरिएलाइज़ेशन के लिए एक पायथन लाइब्रेरी है।

JSON में पायथन को एन्कोड करने के लिए मानक पायथन लाइब्रेरी, जैसे कि स्टैडलिब के json, सिम्पसन, और डेमजसन, केवल पायथन प्राइमेटिव्स को संभाल सकते हैं जिनके पास एक सीधा JSON समतुल्य है (जैसे dicts, सूचियाँ, स्ट्रिंग्स, आदि)। jsonpickle इन पुस्तकालयों के ऊपर बनाता है और JSON के लिए अधिक जटिल डेटा संरचनाओं को क्रमांकित करने की अनुमति देता है। jsonpickle अत्यधिक विन्यास योग्य और विस्तार योग्य है - उपयोगकर्ता को JSON बैकएंड चुनने और अतिरिक्त बैकेंड जोड़ने की अनुमति देता है।

(PyPi पर jsonpickle का लिंक)


31
C # से आ रहा है, यह वही है जो मैं उम्मीद कर रहा था। एक साधारण एक लाइनर और कक्षाओं के साथ कोई खिलवाड़ नहीं।
जेरथ

2
jsonpickle कमाल है। यह वर्गों के कई स्तरों के साथ एक विशाल, जटिल, गड़बड़ वस्तु के लिए पूरी तरह से काम करता है
बुद्धिमानी

क्या इसे फ़ाइल में सहेजने के उचित तरीके का एक उदाहरण है? दस्तावेज़ केवल दिखाता है कि किसी jsonpickleऑब्जेक्ट को कैसे एनकोड और डिकोड किया जाए । इसके अलावा, यह पंडों के डेटाफ्रेम वाले डक्ट्स के एक बड़े हिस्से को डिकोड करने में सक्षम नहीं था।
user5359531

3
@ user5359531 आप उपयोग कर सकते हैं obj = jsonpickle.decode(file.read())और file.write(jsonpickle.encode(obj))
किलन बत्ज़नेर

1
विशेष रूप से django के लिए एक प्रश्न: क्या धारावाहिक सत्र डेटा के लिए jsonpickle का उपयोग अचार के समान भेद्यता है? (जैसा कि यहाँ वर्णित है docs.djangoproject.com/en/1.11/topics/http/session/… )?
पॉल बोरमन्स

89

अधिकांश उत्तरों में कॉल को json.dumps () में बदलना शामिल है , जो हमेशा संभव या वांछनीय नहीं है (यह उदाहरण के लिए एक फ्रेमवर्क घटक के अंदर हो सकता है)।

यदि आप json.dumps (obj) को कॉल करने में सक्षम होना चाहते हैं , तो एक सरल समाधान है जो डिसाइड कर रहा है :

class FileItem(dict):
    def __init__(self, fname):
        dict.__init__(self, fname=fname)

f = FileItem('tasks.txt')
json.dumps(f)  #No need to change anything here

यह काम करता है यदि आपकी कक्षा सिर्फ बुनियादी डेटा प्रतिनिधित्व है, तो पेचीदा चीजों के लिए आप हमेशा कुंजी स्पष्ट रूप से सेट कर सकते हैं।


2
यह वास्तव में एक अच्छा समाधान हो सकता है :) मुझे विश्वास है कि यह मेरे मामले के लिए है। लाभ: आप वस्तु के "आकार" को एक वर्ग के साथ निर्मित कर उसे संप्रेषित करते हैं, यह स्वाभाविक रूप से अनुक्रमिक है और यह पुनःप्राप्य के रूप में व्याख्यात्मक लगता है ।
पास्कलवीकूटेन

1
हालांकि "डॉट-एक्सेस" अभी भी गायब है :(
पास्कलवूटेन

2
आह कि काम करने लगता है! धन्यवाद, निश्चित नहीं कि यह स्वीकृत उत्तर क्यों नहीं है। मैं इस बात से पूरी तरह सहमत हूं कि यह बदलना dumpsएक अच्छा समाधान नहीं है। वैसे, ज्यादातर मामलों में आप शायद dictप्रतिनिधिमंडल के साथ विरासत में एक साथ होना चाहते हैं , जिसका अर्थ है कि dictआपकी कक्षा के अंदर कुछ प्रकार की विशेषता होगी, तो आप इस विशेषता को पैरामीटर के रूप में आरंभिककरण के रूप में पारित करेंगे super().__init__(self.elements)
cglacet

47

मुझे ओनूर का जवाब पसंद है लेकिन toJSON()वस्तुओं के लिए एक वैकल्पिक विधि को शामिल करने के लिए खुद को क्रमबद्ध करने के लिए विस्तार करना होगा :

def dumper(obj):
    try:
        return obj.toJSON()
    except:
        return obj.__dict__
print json.dumps(some_big_object, default=dumper, indent=2)

मैंने इसे मौजूदा का उपयोग करने json.dumpsऔर कस्टम हैंडलिंग को शुरू करने के बीच सबसे अच्छा संतुलन पाया । धन्यवाद!
डैनियल बकमास्टर

12
मुझे वास्तव में यह पसंद है; बल्कि इसके बजाय try-catchशायद कुछ ऐसा होगा if 'toJSON' in obj.__attrs__():... एक मौन विफलता (toJSON की विफलता की स्थिति में) से बचने के लिए (इसके अलावा कुछ कारण नहीं होने के कारण) ... एक विफलता जो संभावित रूप से डेटा भ्रष्टाचार की ओर ले जाती है।
१२

39

एक अन्य विकल्प JSON डंपिंग को अपनी कक्षा में लपेटना है:

import json

class FileItem:
    def __init__(self, fname):
        self.fname = fname

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

या, और भी बेहतर, एक JsonSerializableवर्ग से FileItem वर्ग को उपवर्गित करना :

import json

class JsonSerializable(object):
    def toJson(self):
        return json.dumps(self.__dict__)

    def __repr__(self):
        return self.toJson()


class FileItem(JsonSerializable):
    def __init__(self, fname):
        self.fname = fname

परिक्षण:

>>> f = FileItem('/foo/bar')
>>> f.toJson()
'{"fname": "/foo/bar"}'
>>> f
'{"fname": "/foo/bar"}'
>>> str(f) # string coercion
'{"fname": "/foo/bar"}'

2
नमस्ते, मैं वास्तव में इस "कस्टम एनकोडर" दृष्टिकोण को पसंद नहीं करता हूं, यह बेहतर होगा यदि यू आपके वर्ग के जोंस को गंभीर बना सकता है। मैं कोशिश करता हूं, और कोशिश करता हूं और कुछ भी नहीं। क्या ऐसा करने का कोई विचार है। बात यह है कि json मॉड्यूल आपके वर्ग का निर्माण अजगर के प्रकारों के विरुद्ध करता है, और यहां तक ​​कि कहता है कि कस्टम कक्षाएं आपके एनकोडर को :) बनाती हैं। क्या यह फेक हो सकता है? तो मैं अपनी कक्षा के लिए कुछ कर सकता था, इसलिए यह सरल सूची की तरह व्यवहार करता है? मैं कोशिश subclasscheck और instancecheck लेकिन कुछ नहीं।
बोजान रैडोजेविक

@ADRENALIN यदि आप सभी श्रेणी विशेषता मान क्रमबद्ध हैं और आप हैक नहीं करते हैं, तो आप एक प्राथमिक प्रकार (शायद तानाशाह) से प्राप्त कर सकते हैं। आप मानक एक के बजाय jsonpickle या json_tricks या कुछ का उपयोग कर सकते हैं (फिर भी एक कस्टम एनकोडर, लेकिन आपको लिखने या कॉल करने की आवश्यकता नहीं है)। पूर्व उदाहरण उदाहरण देता है, उत्तरार्द्ध इसे विशेषताओं के तानाशाह के रूप में संग्रहीत करता है, जिसे आप कार्यान्वयन __json__encode__/ __json_decode__(प्रकटीकरण: मैं अंतिम एक बनाकर) बदल सकते हैं ।
मार्क

30

बस to_jsonइस तरह अपनी कक्षा में विधि जोड़ें :

def to_json(self):
  return self.message # or how you want it to be serialized

और इस कोड को ( इस उत्तर से ) , कहीं न कहीं हर चीज के शीर्ष पर जोड़ें:

from json import JSONEncoder

def _default(self, obj):
    return getattr(obj.__class__, "to_json", _default.default)(obj)

_default.default = JSONEncoder().default
JSONEncoder.default = _default

यह बंद हो जाएगा जब यह JSONEncoder.default () स्वचालित रूप से एक विशेष "to_json ()" विधि के लिए जाँच करता है और इसका उपयोग करता है, अगर यह पाया जाता है तो ऑब्जेक्ट को एनकोड करने के लिए इसका उपयोग करेगा।

जैसे ओनूर ने कहा, लेकिन इस बार आपको json.dumps()अपने प्रोजेक्ट में हर अपडेट नहीं करना है ।


6
बहुत धन्यवाद! यह एकमात्र उत्तर है जो मुझे वह करने की अनुमति देता है जो मैं चाहता हूं: मौजूदा कोड को बदलने के बिना किसी वस्तु को क्रमबद्ध करने में सक्षम हो। अन्य विधियां ज्यादातर मेरे लिए काम नहीं करती हैं। ऑब्जेक्ट को तृतीय-पक्ष लाइब्रेरी में परिभाषित किया गया है, और क्रमांकन कोड तृतीय-पक्ष भी है। उन्हें बदलना अजीब होगा। आपकी विधि के साथ, मुझे केवल करने की आवश्यकता है TheObject.to_json = my_serializer
योंगवेई वू

24

मैं दूसरे दिन इस समस्या को लेकर आया और पायथन ऑब्जेक्ट्स के लिए एनकोडर के एक अधिक सामान्य संस्करण को लागू किया, जो नेस्टेड ऑब्जेक्ट्स और इनहेरिट की गई फ़ील्ड्स को हैंडल कर सकता है :

import json
import inspect

class ObjectEncoder(json.JSONEncoder):
    def default(self, obj):
        if hasattr(obj, "to_json"):
            return self.default(obj.to_json())
        elif hasattr(obj, "__dict__"):
            d = dict(
                (key, value)
                for key, value in inspect.getmembers(obj)
                if not key.startswith("__")
                and not inspect.isabstract(value)
                and not inspect.isbuiltin(value)
                and not inspect.isfunction(value)
                and not inspect.isgenerator(value)
                and not inspect.isgeneratorfunction(value)
                and not inspect.ismethod(value)
                and not inspect.ismethoddescriptor(value)
                and not inspect.isroutine(value)
            )
            return self.default(d)
        return obj

उदाहरण:

class C(object):
    c = "NO"
    def to_json(self):
        return {"c": "YES"}

class B(object):
    b = "B"
    i = "I"
    def __init__(self, y):
        self.y = y

    def f(self):
        print "f"

class A(B):
    a = "A"
    def __init__(self):
        self.b = [{"ab": B("y")}]
        self.c = C()

print json.dumps(A(), cls=ObjectEncoder, indent=2, sort_keys=True)

परिणाम:

{
  "a": "A", 
  "b": [
    {
      "ab": {
        "b": "B", 
        "i": "I", 
        "y": "y"
      }
    }
  ], 
  "c": {
    "c": "YES"
  }, 
  "i": "I"
}

1
हालांकि यह थोड़ा पुराना है..मैं कुछ परिपत्र आयात त्रुटि का सामना कर रहा हूं। इसलिए return objअंतिम पंक्ति के बजाय मैंने ऐसा किया return super(ObjectEncoder, self).default(obj)यहाँ
SomeTypeFoo

23

यदि आप Python3.5 + का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं jsons। यह आपकी वस्तु (और इसके सभी गुणों को पुनरावर्ती रूप से) में परिवर्तित कर देगा।

import jsons

a_dict = jsons.dump(your_object)

या यदि आप एक स्ट्रिंग चाहते थे:

a_str = jsons.dumps(your_object)

या यदि आपकी कक्षा लागू हो jsons.JsonSerializable:

a_dict = your_object.json

3
यदि आप पायथॉन 3.7+ का उपयोग करने में सक्षम हैं, तो मैंने पाया कि अजगर कक्षाओं को डाइकट्सjsons और जेएसएन स्ट्रिंग्स (और वाइसवेरा ) में बदलने का सबसे साफ समाधान लाइब्रेरी को डेटाक्लेसेस के साथ मिलाना है । अब तक, मेरे लिए इतना अच्छा!
रुलुक

3
यह एक बाहरी लाइब्रेरी है, जिसे मानक पायथन इंस्टाल में नहीं बनाया गया है।
नूमेनन

केवल उस वर्ग के लिए जिसके पास स्लॉट विशेषता है
yehudahs

आप कर सकते हैं, लेकिन आपको स्लॉट्स का उपयोग करने की आवश्यकता नहीं है । केवल एक विशिष्ट वर्ग के हस्ताक्षर के अनुसार डंपिंग करते समय आपको स्लॉट की आवश्यकता होगी । आगामी संस्करण 1.1.0 में भी अब ऐसा नहीं है।
आरएच

11
import simplejson

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

    def _asdict(self):
        return self.__dict__

print(simplejson.dumps(User('alice', 'alice@mail.com')))

यदि मानक का उपयोग करते हैं json, तो एक defaultफ़ंक्शन को परिभाषित करने की आवश्यकता है

import json
def default(o):
    return o._asdict()

print(json.dumps(User('alice', 'alice@mail.com'), default=default))

2
मैंने लैंबडा के साथ _ddict फ़ंक्शन को हटाकर इसे सरल कर दिया json.dumps(User('alice', 'alice@mail.com'), default=lambda x: x.__dict__)
जस्टगेलैंड

8

jsonयह उन वस्तुओं के संदर्भ में सीमित है, जो इसे प्रिंट jsonpickleकर सकती हैं , और (आपको इसकी आवश्यकता हो सकती है pip install jsonpickle) उन शब्दों में सीमित है जो पाठ को इंडेंट नहीं कर सकते। यदि आप किसी ऐसी वस्तु की सामग्री का निरीक्षण करना चाहते हैं जिसका वर्ग आप नहीं बदल सकते हैं, तो मैं अभी भी इसके मुकाबले एक कठिन रास्ता नहीं खोज सकता:

 import json
 import jsonpickle
 ...
 print  json.dumps(json.loads(jsonpickle.encode(object)), indent=2)

नोट: कि अभी भी वे वस्तु विधियों को मुद्रित नहीं कर सकते हैं।


6

यह वर्ग चाल कर सकता है, यह ऑब्जेक्ट को मानक जोंस में परिवर्तित करता है।

import json


class Serializer(object):
    @staticmethod
    def serialize(object):
        return json.dumps(object, default=lambda o: o.__dict__.values()[0])

उपयोग:

Serializer.serialize(my_object)

में काम कर रहे python2.7और python3


मुझे यह तरीका सबसे ज्यादा पसंद आया। जब मैं अधिक जटिल वस्तुओं को क्रमबद्ध करने की कोशिश कर रहा था, तो मैं उन मुद्दों पर भाग गया, जिनके सदस्य / विधियाँ क्रमबद्ध नहीं हैं। यहाँ मेरा कार्यान्वयन है जो अधिक वस्तुओं पर काम करता है: `` वर्ग सीरियल (ऑब्जेक्ट): @staticmethod def serialize (obj): def check (o): k, v के लिए o। में। तानाशाही __। आइटम (): try: _ = json। .dumps (v) o .__ तानाशाह __ [k] = v को छोड़कर TypeError: o .__ dict __ [k] = str (v) रिटर्न o रिटर्न json.dumps (चेक (obj) .__ dict__, indi = 2) `` `
विल। चार्लटन

4
import json

class Foo(object):
    def __init__(self):
        self.bar = 'baz'
        self._qux = 'flub'

    def somemethod(self):
        pass

def default(instance):
    return {k: v
            for k, v in vars(instance).items()
            if not str(k).startswith('_')}

json_foo = json.dumps(Foo(), default=default)
assert '{"bar": "baz"}' == json_foo

print(json_foo)

से डॉक : पैरामीटर default(obj)एक समारोह है कि obj या बढ़ाने लेखन त्रुटि के एक serializable संस्करण लौट जाना है। डिफ़ॉल्ट defaultबस टाइपर्रोज़ उठाता है।
भाग्योदयदि

4

जारको ने बहुत साफ जवाब दिया। मुझे कुछ मामूली चीजों को ठीक करने की जरूरत थी, लेकिन यह काम करता है:

कोड

# Your custom class
class MyCustom(object):
    def __json__(self):
        return {
            'a': self.a,
            'b': self.b,
            '__python__': 'mymodule.submodule:MyCustom.from_json',
        }

    to_json = __json__  # supported by simplejson

    @classmethod
    def from_json(cls, json):
        obj = cls()
        obj.a = json['a']
        obj.b = json['b']
        return obj

# Dumping and loading
import simplejson

obj = MyCustom()
obj.a = 3
obj.b = 4

json = simplejson.dumps(obj, for_json=True)

# Two-step loading
obj2_dict = simplejson.loads(json)
obj2 = MyCustom.from_json(obj2_dict)

# Make sure we have the correct thing
assert isinstance(obj2, MyCustom)
assert obj2.__dict__ == obj.__dict__

ध्यान दें कि हमें लोडिंग के लिए दो चरणों की आवश्यकता है। अभी के लिए, __python__संपत्ति का उपयोग नहीं किया जाता है।

यह कितना सामान्य है?

अलजोहरी की पद्धति का उपयोग करते हुए , मैं दृष्टिकोणों की लोकप्रियता की जांच करता हूं:

सीरियलाइज़ेशन (पायथन -> JSON):

देशीकरण (JSON -> पायथन):


4

इसने मेरे लिए अच्छा काम किया है:

class JsonSerializable(object):

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

    def __repr__(self):
        return self.serialize()

    @staticmethod
    def dumper(obj):
        if "serialize" in dir(obj):
            return obj.serialize()

        return obj.__dict__

और फिर

class FileItem(JsonSerializable):
    ...

तथा

log.debug(json.dumps(<my object>, default=JsonSerializable.dumper, indent=2))

3

यदि आपको इसके लिए पैकेज स्थापित करने में कोई आपत्ति नहीं है, तो आप json-tricks का उपयोग कर सकते हैं :

pip install json-tricks

उसके बाद आप सिर्फ आयात करने की जरूरत dump(s)से json_tricksjson के बजाय, और यह आमतौर पर काम करना होगा:

from json_tricks import dumps
json_str = dumps(cls_instance, indent=4)

जो दूंगा

{
        "__instance_type__": [
                "module_name.test_class",
                "MyTestCls"
        ],
        "attributes": {
                "attr": "val",
                "dct_attr": {
                        "hello": 42
                }
        }
}

और वह मूल रूप से यह है!


यह सामान्य रूप से महान काम करेगा। कुछ अपवाद हैं, उदाहरण के लिए यदि विशेष चीजें होती हैं __new__, या अधिक मेटाक्लास जादू चल रहा है।

स्पष्ट रूप से लोड करना भी काम करता है (अन्यथा क्या बात है):

from json_tricks import loads
json_str = loads(json_str)

यह मानता है कि module_name.test_class.MyTestClsआयात किया जा सकता है और गैर-संगत तरीकों से नहीं बदला है। आपको एक उदाहरण मिलेगा , कुछ शब्दकोश या कुछ नहीं, और यह आपके द्वारा डंप की गई एक समान प्रति होनी चाहिए।

यदि आप अनुकूलित करना चाहते हैं कि कैसे कुछ (डी) क्रमबद्ध हो जाता है, तो आप अपनी कक्षा में विशेष तरीके जोड़ सकते हैं, जैसे:

class CustomEncodeCls:
        def __init__(self):
                self.relevant = 42
                self.irrelevant = 37

        def __json_encode__(self):
                # should return primitive, serializable types like dict, list, int, string, float...
                return {'relevant': self.relevant}

        def __json_decode__(self, **attrs):
                # should initialize all properties; note that __init__ is not called implicitly
                self.relevant = attrs['relevant']
                self.irrelevant = 12

जो एक उदाहरण के रूप में गुण मापदंडों के केवल भाग को क्रमबद्ध करता है।

और एक मुफ्त बोनस के रूप में, आपको सुस्पष्ट सरणियों, दिनांक और समय, क्रमबद्ध नक्शे, साथ ही साथ टिप्पणियों को शामिल करने की क्षमता मिलती है।

डिस्क्लेमर: मैंने json_tricks बनाया , क्योंकि मुझे आपके समान ही समस्या थी।


1
मैंने सिर्फ json_tricks का परीक्षण किया है और इसने सुशोभित किया (2019 में)।
पाँलहुँजो ३२

2

jsonweb मुझे सबसे अच्छा समाधान लगता है। Http://www.jsonweb.info/en/latest/ देखें

from jsonweb.encode import to_object, dumper

@to_object()
class DataModel(object):
  def __init__(self, id, value):
   self.id = id
   self.value = value

>>> data = DataModel(5, "foo")
>>> dumper(data)
'{"__type__": "DataModel", "id": 5, "value": "foo"}'

क्या यह नेस्टेड वस्तुओं के लिए अच्छी तरह से काम करता है? डिकोडिंग और एन्कोडिंग सहित
सिमोन ज़ंडारा

1

यहाँ मेरा 3 सेंट है ...
यह एक पेड़ की तरह अजगर ऑब्जेक्ट के लिए स्पष्ट जौन धारावाहिकिकरण को दर्शाता है।
नोट: यदि आप वास्तव में इस तरह से कुछ कोड चाहते हैं तो आप मुड़ फाइलपाथ क्लास का उपयोग कर सकते हैं ।

import json, sys, os

class File:
    def __init__(self, path):
        self.path = path

    def isdir(self):
        return os.path.isdir(self.path)

    def isfile(self):
        return os.path.isfile(self.path)

    def children(self):        
        return [File(os.path.join(self.path, f)) 
                for f in os.listdir(self.path)]

    def getsize(self):        
        return os.path.getsize(self.path)

    def getModificationTime(self):
        return os.path.getmtime(self.path)

def _default(o):
    d = {}
    d['path'] = o.path
    d['isFile'] = o.isfile()
    d['isDir'] = o.isdir()
    d['mtime'] = int(o.getModificationTime())
    d['size'] = o.getsize() if o.isfile() else 0
    if o.isdir(): d['children'] = o.children()
    return d

folder = os.path.abspath('.')
json.dump(File(folder), sys.stdout, default=_default)

1

मैं इस समस्या में भाग गया जब मैंने Peewee के मॉडल को PostgreSQL में संग्रहीत करने की कोशिश की JSONField

कुछ समय तक संघर्ष करने के बाद, यहाँ सामान्य समाधान है।

मेरे समाधान की कुंजी पायथन के स्रोत कोड से गुजर रही है और यह महसूस करते हुए कि कोड प्रलेखन ( यहां वर्णित ) पहले से ही json.dumpsअन्य डेटा प्रकारों का समर्थन करने के लिए मौजूदा का विस्तार करने का तरीका बताता है ।

मान लें कि आपके पास वर्तमान में एक मॉडल है जिसमें कुछ फ़ील्ड शामिल हैं जो JSON के लिए अनुक्रमिक नहीं हैं और मॉडल में JSON फ़ील्ड शामिल हैं जो मूल रूप से इस तरह हैं:

class SomeClass(Model):
    json_field = JSONField()

बस एक कस्टम JSONEncoderको इस तरह परिभाषित करें:

class CustomJsonEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, SomeTypeUnsupportedByJsonDumps):
            return < whatever value you want >
        return json.JSONEncoder.default(self, obj)

    @staticmethod
    def json_dumper(obj):
        return json.dumps(obj, cls=CustomJsonEncoder)

और फिर इसे JSONFieldनीचे दिए गए अपने जैसे उपयोग करें:

class SomeClass(Model):
    json_field = JSONField(dumps=CustomJsonEncoder.json_dumper)

कुंजी default(self, obj)ऊपर की विधि है। ... is not JSON serializableपायथन से आपको प्राप्त होने वाली हर एक शिकायत के लिए , केवल अनजाने-से-JSON प्रकार (जैसे Enumया) को संभालने के लिए कोड जोड़ेंdatetime )

उदाहरण के लिए, यहाँ बताया गया है कि मैं किस तरह विरासत में मिला वर्ग का समर्थन करता हूँ Enum:

class TransactionType(Enum):
   CURRENT = 1
   STACKED = 2

   def default(self, obj):
       if isinstance(obj, TransactionType):
           return obj.value
       return json.JSONEncoder.default(self, obj)

अंत में, ऊपर दिए गए कोड के साथ, आप किसी भी Peewee मॉडल को नीचे दिए गए JSON-seriazable ऑब्जेक्ट के रूप में बदल सकते हैं:

peewee_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

हालांकि ऊपर का कोड Peewee के लिए विशिष्ट (कुछ हद तक) था, लेकिन मुझे लगता है:

  1. यह सामान्य रूप से अन्य ORM (Django, आदि) पर लागू होता है
  2. इसके अलावा, यदि आप समझते हैं कि कैसे json.dumpsकाम करता है, तो यह समाधान सामान्य रूप से भी पायथन (ओएनएम ओआरएम) के साथ काम करता है

कोई प्रश्न, टिप्पणी अनुभाग में पोस्ट करें। धन्यवाद!


1

यह फ़ंक्शन शब्दकोश के प्रत्येक भाग पर पुनरावृत्ति करने के लिए पुनरावर्तन का उपयोग करता है और फिर उन वर्गों के repr () विधियों को कॉल करता है जो बिल्ड-इन प्रकार नहीं हैं।

def sterilize(obj):
    object_type = type(obj)
    if isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif object_type in (list, tuple):
        return [sterilize(v) for v in obj]
    elif object_type in (str, int, bool):
        return obj
    else:
        return obj.__repr__()

0

यह एक छोटी सी लाइब्रेरी है जो अपने सभी बच्चों के साथ JSON में ऑब्जेक्ट को क्रमबद्ध करती है और इसे वापस पार्स भी करती है:

https://github.com/Toubs/PyJSONSerialization/


0

मैं अपने समाधान के साथ आया था। इस विधि का प्रयोग करें, क्रमबद्ध करने के लिए किसी भी दस्तावेज़ ( तानाशाही , सूची , ऑब्जेक्टआईड आदि) को पास करें।

def getSerializable(doc):
    # check if it's a list
    if isinstance(doc, list):
        for i, val in enumerate(doc):
            doc[i] = getSerializable(doc[i])
        return doc

    # check if it's a dict
    if isinstance(doc, dict):
        for key in doc.keys():
            doc[key] = getSerializable(doc[key])
        return doc

    # Process ObjectId
    if isinstance(doc, ObjectId):
        doc = str(doc)
        return doc

    # Use any other custom serializting stuff here...

    # For the rest of stuff
    return doc

0

मैंने डेटाटाइम ऑब्जेक्ट क्रमांकन समस्या को हल करने के लिए डेकोरेटर्स का उपयोग करना चुना। यहाँ मेरा कोड है:

#myjson.py
#Author: jmooremcc 7/16/2017

import json
from datetime import datetime, date, time, timedelta
"""
This module uses decorators to serialize date objects using json
The filename is myjson.py
In another module you simply add the following import statement:
    from myjson import json

json.dumps and json.dump will then correctly serialize datetime and date 
objects
"""

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

    if isinstance(obj, (datetime, date)):
        serial = str(obj)
        return serial
    raise TypeError ("Type %s not serializable" % type(obj))


def FixDumps(fn):
    def hook(obj):
        return fn(obj, default=json_serial)

    return hook

def FixDump(fn):
    def hook(obj, fp):
        return fn(obj,fp, default=json_serial)

    return hook


json.dumps=FixDumps(json.dumps)
json.dump=FixDump(json.dump)


if __name__=="__main__":
    today=datetime.now()
    data={'atime':today, 'greet':'Hello'}
    str=json.dumps(data)
    print str

उपरोक्त मॉड्यूल को आयात करके, मेरे अन्य मॉड्यूल डेटा को क्रमबद्ध करने के लिए सामान्य तरीके से (डिफ़ॉल्ट कीवर्ड को निर्दिष्ट किए बिना) जस का उपयोग करते हैं जिसमें डेट ऑब्जेक्ट शामिल होते हैं। डेटाटाइम सीरियल कोड स्वचालित रूप से json.dumps और json.dump के लिए कहा जाता है।


0

मुझे लॉस्ट कोडर का तरीका सबसे ज्यादा पसंद आया। जब मैं अधिक जटिल वस्तुओं को क्रमबद्ध करने की कोशिश कर रहा था, तो मैं उन मुद्दों पर भाग गया, जिनके सदस्य / विधियाँ क्रमबद्ध नहीं हैं। यहाँ मेरा कार्यान्वयन है जो अधिक वस्तुओं पर काम करता है:

class Serializer(object):
    @staticmethod
    def serialize(obj):
        def check(o):
            for k, v in o.__dict__.items():
                try:
                    _ = json.dumps(v)
                    o.__dict__[k] = v
                except TypeError:
                    o.__dict__[k] = str(v)
            return o
        return json.dumps(check(obj).__dict__, indent=2)

0

यदि आप एक पैकेज स्थापित करने में सक्षम हैं, तो मैं डिल की कोशिश करना चाहूंगा , जिसने मेरी परियोजना के लिए ठीक काम किया। इस पैकेज के बारे में एक अच्छी बात यह है कि इसका इंटरफ़ेस समान है pickle, इसलिए यदि आप पहले से ही pickleअपने प्रोजेक्ट में उपयोग कर रहे हैं, तो आप बस इसमें विकल्प चुन सकते हैंdill किसी भी कोड को बदले बिना स्क्रिप्ट को चला हैं और देख हैं। तो यह कोशिश करने के लिए एक बहुत ही सस्ता उपाय है!

(पूर्ण विरोधी खुलासा: मैं किसी भी तरह से संबद्ध नहीं हूं और कभी भी डिल परियोजना में योगदान नहीं दिया है।)

पैकेज स्थापित करें:

pip install dill

इसके बाद आयात dillकरने के लिए अपना कोड संपादित करें pickle:

# import pickle
import dill as pickle

अपनी स्क्रिप्ट चलाएं और देखें कि क्या यह काम करता है। (यदि ऐसा होता है तो आप अपने कोड को साफ करना चाह सकते हैं ताकि आप अब छाया नहीं कर सकेंpickle मॉड्यूल नाम को !)

प्रोजेक्ट पृष्ठdill से डेटाटाइप्स पर कुछ बारीकियों को क्रमबद्ध और नहीं किया जा सकता है :

dill निम्नलिखित मानक प्रकार अचार कर सकते हैं:

कोई भी, प्रकार, बूल, इंट, लॉन्ग, फ्लोट, कॉम्प्लेक्स, स्ट्र, यूनिकोड, टपल, लिस्ट, डिफेंस, फाइल, बफर, बिलिन, दोनों पुराने और नए स्टाइल क्लासेस, पुराने और नए स्टाइल क्लासेस के इंस्टेंस, सेट, फ्रोज़ेनसेट, एरे , कार्य, अपवाद

dill अधिक 'विदेशी' मानक प्रकार का अचार भी बना सकते हैं:

पैदावार, नेस्टेड फ़ंक्शंस, लैम्ब्डा, सेल, मेथड, अनबेंडमेथोड, मॉड्यूल, कोड, मेथडवॉपर, डिक्टप्रोक्सी, मेथडेसप्टर, गेटेसेडस्क्रिप्ट, मेम्बरडेस्क्रिप्ट, रैपरसेप्टर, एक्सरेस, स्लाइस, नोटिफ़ाइज्ड, एलिप्सिस

dill अभी तक ये मानक प्रकार अचार नहीं कर सकते हैं:

फ्रेम, जनरेटर, ट्रेसबैक


0

मुझे यहाँ सीरियल संस्करण या बैककॉम का कोई उल्लेख नहीं दिखता है, इसलिए मैं अपना समाधान पोस्ट करूँगा जिसका उपयोग मैं थोड़ी देर के लिए कर रहा हूँ। मेरे पास सीखने के लिए बहुत कुछ है, विशेष रूप से जावा और जावास्क्रिप्ट शायद मेरे मुकाबले कहीं अधिक परिपक्व हैं लेकिन यहां जाता है

https://gist.github.com/andy-d/b7878d0044a4242c0498ed6d67fd50fe


0

एक और विकल्प जोड़ने के लिए: आप attrsपैकेज और asdictविधि का उपयोग कर सकते हैं ।

class ObjectEncoder(JSONEncoder):
    def default(self, o):
        return attr.asdict(o)

json.dumps(objects, cls=ObjectEncoder)

और वापस परिवर्तित करने के लिए

def from_json(o):
    if '_obj_name' in o:
        type_ = o['_obj_name']
        del o['_obj_name']
        return globals()[type_](**o)
    else:
        return o

data = JSONDecoder(object_hook=from_json).decode(data)

वर्ग इस तरह दिखता है

@attr.s
class Foo(object):
    x = attr.ib()
    _obj_name = attr.ib(init=False, default='Foo')

0

ओनुर के जवाब के अलावा , आप संभवतः नीचे की तरह डेटाइम प्रकार से निपटना चाहते हैं।
(हैंडल करने के लिए: 'datetime.datetime' ऑब्जेक्ट में कोई विशेषता ' तानाशाह ' अपवाद नहीं है।)

def datetime_option(value):
    if isinstance(value, datetime.date):
        return value.timestamp()
    else:
        return value.__dict__

उपयोग:

def toJSON(self):
    return json.dumps(self, default=datetime_option, sort_keys=True, indent=4)

0

पहले हमें अपना ऑब्जेक्ट JSON-compliant बनाने की आवश्यकता है, इसलिए हम इसे मानक JSON मॉड्यूल का उपयोग करके डंप कर सकते हैं। मैंने इसे इस तरह किया:

def serialize(o):
    if isinstance(o, dict):
        return {k:serialize(v) for k,v in o.items()}
    if isinstance(o, list):
        return [serialize(e) for e in o]
    if isinstance(o, bytes):
        return o.decode("utf-8")
    return o

0

क्विंटन काबो के जवाब पर बिल्डिंग :

def sterilize(obj):
    if type(obj) in (str, float, int, bool, type(None)):
        return obj
    elif isinstance(obj, dict):
        return {k: sterilize(v) for k, v in obj.items()}
    elif hasattr(obj, '__iter__') and callable(obj.__iter__):
        return [sterilize(v) for v in obj]
    elif hasattr(obj, '__dict__'):
        return {k: sterilize(v) for k, v in obj.__dict__.items() if k not in ['__module__', '__dict__', '__weakref__', '__doc__']}
    else:
        return repr(obj)

अंतर हैं

  1. बस के बजाय किसी भी चलने योग्य के लिए काम करता है listऔर tuple(यह NumPy सरणियों, आदि के लिए काम करता है)
  2. गतिशील प्रकारों के लिए काम करता है (जिनमें शामिल हैं a __dict__ ) ।
  3. देशी प्रकार शामिल हैं floatऔर Noneइसलिए वे स्ट्रिंग में परिवर्तित नहीं होते हैं।

पाठक के लिए एक अभ्यास के रूप में छोड़ दिया जाता है __slots__, कक्षाएं जो दोनों चलने योग्य हैं और सदस्य हैं, कक्षाएं जो शब्दकोशों हैं और सदस्य भी हैं, आदि।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.