কীভাবে একটি ক্লাস জেএসএন সিরিয়ালযোগ্য করে তুলবেন


832

কীভাবে পাইথন ক্লাসের সিরিয়ালীকরণযোগ্য?

একটি সাধারণ শ্রেণি:

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
এটি দুর্ভাগ্যজনক যে উত্তরগুলি সকলেই এই প্রশ্নের উত্তর বলে মনে হয় "আমি কীভাবে একটি শ্রেণি সিরিয়াল করব?" অ্যাকশন প্রশ্নটির চেয়ে "আমি কীভাবে একটি শ্রেণিকরণ সিরিয়ালিয়াল করব?" এই উত্তরগুলি ধরে নিয়েছে যে আপনি সিরিয়ালাইজেশনটি নিজেই করছেন, বরং এটির সিরিয়ালাইজড কিছু অন্যান্য মডিউলের সাথে বস্তুটি পাস করার চেয়ে।
কাইল ডেলানি

আপনি যদি পাইথন 3.5 ব্যবহার করেন তবে আপনি জসসন ব্যবহার করতে পারেন। এটি আপনার বস্তুকে (এবং এর সমস্ত গুণাবলী পুনরাবৃত্তভাবে ) একটি ডিককে রূপান্তর করবে । import jsonsনিচে উত্তর দেখার - এটা জরিমানা ঠিকভাবে কাজ
tswaehn

উত্তর:


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()হিসাবে পদ্ধতিতে পাস করুন cls:

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__নতুন স্টাইলের ক্লাস ব্যবহার করেন তবে ক্রিসহার্ডিও কাজ করে না ।
Badp

7
আপনি JSONEncoderকাস্টম প্রোটোকল তৈরির জন্য উপরের মতো একটি কাস্টম ব্যবহার করতে পারেন , যেমন __json_serializable__পদ্ধতির অস্তিত্বের জন্য যাচাই করা এবং অবজেক্টটির জেএসওএন সিরিয়ালাইজযোগ্য উপস্থাপনা পেতে এটি কল করা। এর ফলে অন্য পাইথন নিদর্শন, মত সঙ্গে পালন করা হবে __getitem__, __str__, __eq__, এবং __len__
jpmc26

5
__dict__এছাড়াও পুনরাবৃত্তির সাথে কাজ করবে না, উদাহরণস্বরূপ, যদি আপনার অবজেক্টের কোনও বৈশিষ্ট্য অন্য কোনও বস্তু হয়।
নীল

633

একটি সাধারণ বৈশিষ্ট্যের জন্য এখানে একটি সহজ সমাধান:

.toJSON() পদ্ধতি

জেএসএন সিরিয়ালাইজযোগ্য ক্লাসের পরিবর্তে সিরিয়ালাইজার পদ্ধতিটি প্রয়োগ করুন:

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
খুবই কম সংখ্যক. আপনার যদি ডিক {"foo": "বার", "বাজ": "ব্যাট"} থাকে তবে এটি সহজেই JSON এ সিরিয়ালাইজ হবে। পরিবর্তে যদি আপনার {"foo": "বার", "বাজ": মাইঅবজেক্ট ()} থাকে তবে আপনি পারবেন না। আদর্শ পরিস্থিতিটি হ'ল নেস্টেড বস্তুগুলি স্পষ্টভাবে নয়, পুনরাবৃত্তভাবে 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 ন। আপনার একই ক্ষেত্রের সাথে দুটি পৃথক ক্লাস থাকতে পারে। ক্লাসের a এবং b অবজেক্টগুলিতে (সম্ভবত একই বৈশিষ্ট্যযুক্ত) একই a.__dict__/ থাকবে b.__dict__
মার্টিন থোমা

7
এটি datetime.datetimeদৃষ্টান্তগুলির সাথে কাজ করে না । এটি নিম্নলিখিত ত্রুটিটি ছুড়ে 'datetime.datetime' object has no attribute '__dict__'
ব্রুনো ফিঙ্গার

171

আরও জটিল ক্লাসের জন্য আপনি jsonpickle সরঞ্জামটি বিবেচনা করতে পারেন :

জেসনপিকল জেএসএনে এবং থেকে জটিল পাইথন অবজেক্টগুলির সিরিয়ালাইজেশন এবং ডিসরিয়ালাইজেশন করার জন্য একটি পাইথন গ্রন্থাগার।

জেএসএন-তে পাইথনকে এনকোড করার জন্য স্ট্যান্ডল পাইথন লাইব্রেরি, যেমন স্ট্ডলিবের জসন, সিম্পজসন এবং ডেমজসন কেবল পাইথন আদিমগুলি পরিচালনা করতে পারে যার সরাসরি জেএসওএন সমতুল্য (যেমন ডিক্টস, তালিকাগুলি, স্ট্রিংস, ইনটস ইত্যাদি) রয়েছে। jsonpickle এই লাইব্রেরির উপরে তৈরি করে এবং আরও জটিল ডেটা স্ট্রাকচারগুলি JSON এ সিরিয়ালায়িত করার অনুমতি দেয়। jsonpickle অত্যন্ত কনফিগার এবং প্রসারযোগ্য - ব্যবহারকারীকে JSON ব্যাকএন্ড চয়ন করতে এবং অতিরিক্ত ব্যাক-এন্ড যুক্ত করতে দেয়।

(পিপিআই-তে জসনপিকলের লিঙ্ক)


31
সি # থেকে আগত, এটিই আমি প্রত্যাশা করছিলাম। একটি সাধারণ একটি লাইনার এবং ক্লাসগুলির সাথে গোলযোগ নেই।
জেরের

2
jsonpickle দুর্দান্ত। এটি অনেক স্তরের ক্লাস সহ বিশাল, জটিল, অগোছালো অবজেক্টের জন্য পুরোপুরি কাজ করেছিল
উইসবাকী

এটি একটি ফাইল এ সংরক্ষণ করার সঠিক উপায় উদাহরণ আছে? ডকুমেন্টেশনটি কেবলমাত্র কোনও jsonpickleবস্তুকে এনকোড এবং ডিকোড করার পদ্ধতি দেখায় । এছাড়াও, এটি পান্ডাস ডেটাফ্রেমে থাকা ডিক্টের ডিক ডিকোড করতে সক্ষম হয় নি।
ব্যবহারকারী5359531

3
@ user5359531 আপনি ব্যবহার করতে পারেন obj = jsonpickle.decode(file.read())এবং file.write(jsonpickle.encode(obj))
কিলিয়ান ব্যাটজনার

1
জ্যাঙ্গোর জন্য বিশেষত একটি প্রশ্ন: সেশন ডেটা সিরিয়াল করার জন্য জসনপিকলের ব্যবহারের সাথে আচারের মতো একই দুর্বলতা রয়েছে? (এখানে বর্ণিত হিসাবে ডকস.ড্যাজঙ্গোপ্রজেক্ট /en/১১.১১ / টপিক্স / এইচটিটিপি / অ্যাসেসিশনস/… )?
পল বোরম্যানস

89

বেশিরভাগ উত্তরগুলির মধ্যে কলটি জসন.ডম্পস () এ পরিবর্তন করা জড়িত যা সর্বদা সম্ভব বা কাঙ্ক্ষিত নয় (উদাহরণস্বরূপ এটি কোনও ফ্রেমওয়ার্কের উপাদানগুলির মধ্যে ঘটতে পারে)।

আপনি যদি জসন.ডাম্পস (আপত্তি) হিসাবে কল করতে সক্ষম হতে চান , তবে একটি সহজ সমাধান ডিক থেকে উত্তরাধিকারসূত্রে প্রাপ্ত :

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

আপনার শ্রেণিটি যদি কেবল মৌলিক ডেটার উপস্থাপনা হয় তবে কৌশলযুক্ত জিনিসগুলির জন্য আপনি সর্বদা কীগুলি সুস্পষ্টভাবে সেট করতে পারেন This


2
এটি সত্যিই একটি দুর্দান্ত সমাধান হতে পারে :) আমি বিশ্বাস করি আমার ক্ষেত্রে এটি। সুবিধাগুলি: আপনি অবজেক্টের "আকৃতি" কে এন্টার দিয়ে ক্লাস তৈরি করে যোগাযোগ করেন, এটি অন্তর্নিহিত সিরিয়ালাইজযোগ্য এবং এটি পুনরায় হিসাবে ব্যাখ্যাযোগ্য বলে মনে হচ্ছে ।
পাসক্যালভিকুটেন

1
যদিও "ডট-অ্যাক্সেস" এখনও নিখোঁজ রয়েছে :(
পাস্কালভিকুটেন

2
আহ যে কাজ মনে হচ্ছে! ধন্যবাদ, কেন এটি গৃহীত উত্তর নয় তা নিশ্চিত নন। আমি সম্পূর্ণরূপে একমত যে পরিবর্তনটি dumpsকোনও ভাল সমাধান নয়। যাইহোক, বেশিরভাগ ক্ষেত্রে আপনি সম্ভবত dictপ্রতিনিধিদের সাথে একত্রে উত্তরাধিকার পেতে চান , যার অর্থ dictআপনার ক্লাসের ভিতরে আপনার কোনও ধরণের বৈশিষ্ট্য থাকবে, আপনি তখন এই বৈশিষ্ট্যটিকে আরম্ভের মতো কিছু হিসাবে প্যারামিটার হিসাবে পাস করবেন super().__init__(self.elements)
সিগ্লেসেট

47

আমি অনুরের উত্তরটি পছন্দ করি তবে toJSON()বস্তুগুলিকে নিজেরাই সিরিয়াল করার জন্য একটি alচ্ছিক পদ্ধতি অন্তর্ভুক্ত করতে প্রসারিত করব :

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__():... নীরব ব্যর্থতা এড়াতে (টাসসনে ব্যর্থ হওয়ার ক্ষেত্রে (এটি উপস্থিত না হওয়া ছাড়া অন্য কোনও কারণে)) ... ব্যর্থতা যা ডেটা দুর্নীতির দিকে পরিচালিত করে।
thclark

39

আরেকটি বিকল্প হ'ল জেএসওএন ডাম্পিংয়ের নিজস্ব শ্রেণিতে মোড়ক করা:

import json

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

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

বা, আরও ভাল, একটি JsonSerializableক্লাস থেকে ফাইল আইটেম ক্লাস সাবক্লাসিং :

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
হাই, আমি এই "কাস্টম এনকোডার" পদ্ধতির পছন্দ করি না, আপনি যদি আপনার ক্লাস জেসনকে সিরিয়াজেবল করে তুলতে পারেন তবে ভাল be আমি চেষ্টা, এবং চেষ্টা এবং চেষ্টা এবং কিছুই। এটি কীভাবে করবেন তা সম্পর্কে কোনও ধারণা আছে? জিনিসটি হ'ল জসন মডিউলটি আপনার ক্লাসটি অজগর প্রকারের মধ্যে নির্মিত পরীক্ষা করে এবং এমনকি কাস্টম ক্লাসগুলির জন্য বলে যে আপনার এনকোডার তৈরি করুন :)। এটা কি নকল হতে পারে? সুতরাং আমি আমার ক্লাসে কিছু করতে পারলাম যাতে এটি জাসন মডিউলের সরল তালিকার মতো আচরণ করে? আমি সাবক্লাস চেক এবং ইনস্ট্যান্স চেক চেষ্টা করছি তবে কিছুই নয়।
বোজন রাদোজিয়েভিক

@ অ্যাড্রেইনলিনিং আপনি প্রাথমিক ধরণের (সম্ভবত ডিক) থেকে উত্তরাধিকারী হতে পারেন, যদি সমস্ত শ্রেণীর বৈশিষ্ট্য মানগুলি ক্রমিক হয় এবং আপনি হ্যাকগুলিতে আপত্তি করেন না। আপনি জাসনপিকল বা জসন_ট্রিক্স বা মানকটির পরিবর্তে কিছু ব্যবহার করতে পারেন (এখনও একটি কাস্টম এনকোডার, তবে আপনার লিখতে বা কল করার প্রয়োজন নেই)। পূর্বের আচার উদাহরণস্বরূপ, পরবর্তীকালে এটি গুণকের ডিক হিসাবে সংরক্ষণ করে, যা আপনি প্রয়োগ করে __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

JCONEncoder.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)এখানে
সোমটিটাইপফু

23

আপনি যদি পাইথন 3.5 ব্যবহার করেন তবে আপনি ব্যবহার করতে পারেন jsons। এটি আপনার বস্তুকে (এবং এর সমস্ত গুণাবলী পুনরাবৃত্তভাবে) একটি ডিককে রূপান্তর করবে।

import jsons

a_dict = jsons.dump(your_object)

অথবা আপনি যদি একটি স্ট্রিং চেয়েছিলেন:

a_str = jsons.dumps(your_object)

বা যদি আপনার শ্রেণি প্রয়োগ করা হয় jsons.JsonSerializable:

a_dict = your_object.json

3
আপনি যদি পাইথন ৩.7+ ব্যবহার করতে সক্ষম হন তবে আমি দেখতে পেয়েছি যে পাইথন ক্লাসকে ডিক্টস এবং জেএসওএন স্ট্রিংগুলিতে রূপান্তর করার সবচেয়ে পরিষ্কার সমাধানটি (এবং বিপরীতমুখী) jsonsলাইব্রেরিটি ডেটা ক্লাসের সাথে মিশ্রিত করা । এখনও পর্যন্ত, আমার জন্য এত ভাল!
জুলুক 26'19

3
এটি একটি বাহ্যিক গ্রন্থাগার, স্ট্যান্ডার্ড পাইথন ইনস্টল-এ অন্তর্নির্মিত নয়।
নওম্যানন

কেবল ক্লাসের জন্য যার স্লট বৈশিষ্ট্য রয়েছে
ইহুদাহ

আপনি পারেন, তবে আপনার স্লট ব্যবহার করার দরকার নেই । নির্দিষ্ট শ্রেণীর স্বাক্ষর অনুযায়ী ডাম্পিং করার সময় কেবল আপনার স্লট প্রয়োজন । আসন্ন সংস্করণে 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
আমি এটিকে সরল করে দিয়েছি _একটি ল্যাম্বদা দিয়ে ফাংশন সরিয়ে json.dumps(User('alice', 'alice@mail.com'), default=lambda x: x.__dict__)
JustEngland

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


আমি এই পদ্ধতিটি সবচেয়ে বেশি পছন্দ করেছি। সদস্যপদগুলি / পদ্ধতিগুলি সিরিয়ালযোগ্য নয় এমন আরও জটিল বস্তুগুলিকে সিরিয়াল করার চেষ্টা করার সময় আমি সমস্যার মধ্যে পড়েছিলাম। এখানে আমার বাস্তবায়ন যা আরও বেশি অবজেক্টে কাজ করে: Ser `` শ্রেণি সিরিয়ালাইজার (অবজেক্ট): @ স্ট্যাটিকমেডোস্ট ডিফ সিরিয়ালাইজ (অবজেক্ট): ডিএফ চেক (ও): কে, ভি ইন ও .__ ডিক __। আইটেম (): চেষ্টা করুন: _ = জেএসন .ডাম্প (ভি) ও .__ ডিক __ [কে] = ভি টাইপ এরর বাদে: ও .__ ডিক __ [কে] = টিআর (ভি) রিটার্ন ও রিটার্ন জেসন.ডাম্পস (চেক (আপত্তি) .__ ডিক__, ইনডেন্ট = 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)এমন একটি ফাংশন যা আপত্তি বা টাইপয়েরর উত্থাপনের ক্রমিক সংস্করণটি ফিরিয়ে আনে। ডিফল্ট 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__সম্পত্তি ব্যবহৃত হয় না।

এটা কত সাধারণ?

আল জোহরির পদ্ধতিটি ব্যবহার করে , আমি পদ্ধতির জনপ্রিয়তা যাচাই করি:

সিরিয়ালাইজেশন (পাইথন -> জেএসএন):

বিশৃঙ্খলা (জেএসএন -> পাইথন):


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

যদি আপনি এটির জন্য কোনও প্যাকেজ ইনস্টল করতে আপত্তি না করেন তবে আপনি জসন-ট্রিকস ব্যবহার করতে পারেন :

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

যা উদাহরণস্বরূপ বৈশিষ্ট্যের পরামিতিগুলির কেবলমাত্র একটি অংশকেই ক্রমিক করে তোলে।

এবং একটি নিখরচায় বোনাস হিসাবে, আপনি (আ) নমপি অ্যারে, তারিখ এবং সময়গুলির ক্রমিককরণ (অর্ডার) মানচিত্রের পাশাপাশি জসন-এ মন্তব্য অন্তর্ভুক্ত করার ক্ষমতা পাবেন।

দাবি অস্বীকার : আমি জেসন_ট্রিক্স তৈরি করেছি , কারণ আপনার মতো আমারও একই সমস্যা ছিল।


1
আমি সবেমাত্র জসন_ট্রিক্স পরীক্ষা করেছি এবং এটি সুন্দর করে কাজ করেছে (2019 সালে)
পলজোহন 32

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

আমি যখন পিগ্রির মডেলটি পোস্টগ্রিজ এসকিউএলে সংরক্ষণ করার চেষ্টা করেছি তখন আমি এই সমস্যার মধ্যে পড়েছিলাম JSONField

কিছুক্ষণ লড়াই করার পরে, এখানে সাধারণ সমাধান।

আমার সমাধানের মূলটি পাইথনের উত্স কোডের মধ্য দিয়ে যাচ্ছেন এবং বুঝতে পেরেছেন যে কোড ডকুমেন্টেশন ( এখানে বর্ণিত ) ইতিমধ্যে ব্যাখ্যা করে যে কীভাবে json.dumpsঅন্যান্য ডেটা ধরণের সমর্থন করতে বিদ্যমানটিকে প্রসারিত করতে হয়।

ধরুন আপনার বর্তমানের এমন একটি মডেল রয়েছে যার কিছু ক্ষেত্র রয়েছে যা 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পাইথন থেকে প্রাপ্ত প্রতিটি একক অভিযোগের জন্য, অপ্রয়োজনীয়-থেকে-জেএসওএন প্রকার (যেমন 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_model = WhateverPeeweeModel()
new_model = SomeClass()
new_model.json_field = model_to_dict(peewee_model)

যদিও উপরের কোডটি কিছুটা (কিছুটা) পেরুয়ের জন্য নির্দিষ্ট ছিল তবে আমি মনে করি:

  1. এটি অন্যান্য ওআরএম (জ্যাঙ্গো, ইত্যাদি) এর ক্ষেত্রে প্রযোজ্য
  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

এটি একটি ছোট লাইব্রেরি যা জেসসনে তার সমস্ত শিশুদের সাথে একটি বস্তুকে সিরিয়ালিত করে এবং এটিকে আবারও বিশ্লেষণ করে:

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 জন্য কল করা হয় for


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

অনুরের উত্তর ছাড়াও , আপনি সম্ভবত নীচের মতো ডেটটাইম ধরণের মোকাবেলা করতে চান।
(হ্যান্ডেল করার জন্য: 'ডেটটাইম.ডেটটাইম' অবজেক্টের কোনও ' ডিক ' ব্যতিক্রম নেই))

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- কমপ্লায়েন্ট করা দরকার, যাতে আমরা স্ট্যান্ডার্ড 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

উপর নির্মাণের Quinten কাবো 'র উত্তর :

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. শুধু পরিবর্তে কোনো iterable জন্য কাজ করে listএবং tuple(এটা NumPy অ্যারে, ইত্যাদি জন্য কাজ করে)
  2. গতিশীল ধরণের (যেগুলিতে একটি রয়েছে __dict__) এর জন্য কাজ করে।
  3. নেটিভ প্রকারগুলি অন্তর্ভুক্ত করে floatএবং Noneতাই তারা স্ট্রিংয়ে রূপান্তরিত হয় না।

পাঠকের কাছে অনুশীলন হিসাবে বাম হ'ল __slots__, এমন ক্লাসগুলি যা উভয়ই পুনরাবৃত্তিযোগ্য এবং সদস্য রয়েছে, ক্লাস যা অভিধান রয়েছে এবং সদস্যও রয়েছে ইত্যাদি।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.