জিসসনে পাইথন নামের এক পাইথন সিরিয়ালিয়াল করা


87

namedtupleক্ষেত্রের নামগুলি বজায় রেখে জ টু জসনকে সিরিয়ালকরণের প্রস্তাবিত উপায় কী ?

একটিতে জসনকে সিরিয়ালকরণ করা namedtupleহলে ফলাফলগুলি কেবল সিরিয়ালাইজড হয়ে যায় এবং ক্ষেত্রের নামগুলি অনুবাদে হারিয়ে যায়। আমি চাই ক্ষেত্রগুলিও যখন জসন-আইাইজড হয়ে থাকে এবং তাই নিম্নলিখিতটি করা হয়:

class foobar(namedtuple('f', 'foo, bar')):
    __slots__ = ()
    def __iter__(self):
        yield self._asdict()

উপরের সিরিয়ালগুলি জসনকে যেমন প্রত্যাশা করা হয়েছে এবং আমি namedtupleঅন্যান্য জায়গাগুলির মতো আচরণ করি (অ্যাট্রিবিউট অ্যাক্সেস ইত্যাদি), যেমন এটির পুনরুক্তি করার সময় ফলাফলগুলি (যেমন আমার ব্যবহারের ক্ষেত্রে জরিমানা) বাদ দেয় non

ক্ষেত্রের নামগুলি বজায় রেখে জসনে রূপান্তরিত করার "সঠিক উপায়" কী?


: পাইথন 2.7 জন্য stackoverflow.com/questions/16938456/...
lowtech

উত্তর:


55

এটি বেশ জটিল, যেহেতু namedtuple()একটি কারখানা যা থেকে প্রাপ্ত নতুন ধরণের ফিরে আসে tuple। একটি পদ্ধতির ক্ষেত্রে আপনার শ্রেণিটি উত্তরাধিকার সূত্রে প্রাপ্ত হওয়াও হবে UserDict.DictMixinতবে tuple.__getitem__এটি ইতিমধ্যে সংজ্ঞায়িত হয়েছে এবং এটির বৈশিষ্ট্যের নাম নয় বরং কোনও সংখ্যার উপাদানটির অবস্থান নির্দেশ করে বলে প্রত্যাশা করে:

>>> f = foobar('a', 1)
>>> f[0]
'a'

এর হৃদয়ে নেডটুপলটি জেএসএনের জন্য একটি স্বতন্ত্র ফিট, যেহেতু এটি সত্যিই একটি কাস্টম-বিল্ট টাইপ যার মূল নামগুলি টাইপ সংজ্ঞার অংশ হিসাবে স্থির করা হয়েছে , যেখানে অভিধানের মধ্যে মূল নামগুলি সংরক্ষণ করা হয় এমন একটি অভিধানের মত নয়। এটি আপনাকে একটি নেমডটুপলকে "রাউন্ড-ট্রিপিং" বাধা দেয়, যেমন আপনি ডিকের মধ্যে অ্যাপ্লিকেশন নির্দিষ্ট ধরণের মার্কার মতো কোনও ডিকশনারিকে কোনও নামটুপলে আবার ডিকোড করতে পারবেন না {'a': 1, '#_type': 'foobar'}যা কিছুটা হ্যাকি।

এটি আদর্শ নয়, তবে আপনার যদি কেবল অভিধানগুলিতে নেমটুপলগুলি এনকোড করা দরকার , তবে অন্য পদ্ধতিটি হল আপনার জেএসএন এনকোডারকে এই ধরণের বিশেষ ক্ষেত্রে প্রসারিত বা সংশোধন করতে। পাইথন সাবক্লাসিংয়ের উদাহরণ এখানে json.JSONEncoder। নেস্টেড নেমেডটুপলসকে অভিধানে যথাযথ রূপান্তর করা হয়েছে তা নিশ্চিত করার সমস্যাটি এটি সমাধান করে:

from collections import namedtuple
from json import JSONEncoder

class MyEncoder(JSONEncoder):

    def _iterencode(self, obj, markers=None):
        if isinstance(obj, tuple) and hasattr(obj, '_asdict'):
            gen = self._iterencode_dict(obj._asdict(), markers)
        else:
            gen = JSONEncoder._iterencode(self, obj, markers)
        for chunk in gen:
            yield chunk

class foobar(namedtuple('f', 'foo, bar')):
    pass

enc = MyEncoder()
for obj in (foobar('a', 1), ('a', 1), {'outer': foobar('x', 'y')}):
    print enc.encode(obj)

{"foo": "a", "bar": 1}
["a", 1]
{"outer": {"foo": "x", "bar": "y"}}

12
এর হৃদয়ে নেডটুপলটি জেএসএনের জন্য একটি স্বতন্ত্র ফিট, যেহেতু এটি সত্যই একটি কাস্টম-বিল্ট টাইপ যার মূল নামগুলি টাইপ সংজ্ঞার অংশ হিসাবে স্থির করা হয়েছে, যেখানে অভিধানের মধ্যে মূল নামগুলি সংরক্ষণ করা হয় এমন একটি অভিধানের মত নয়। খুব অন্তর্দৃষ্টিপূর্ণ মন্তব্য। আমি এটা সম্পর্কে চিন্তা ছিল না। ধন্যবাদ আমি নেমটিপলসগুলিকে পছন্দ করি যেহেতু তারা নামকরণ সুবিধার সাথে একটি দুর্দান্ত অপরিবর্তনীয় কাঠামো সরবরাহ করে । আমি আপনার উত্তর গ্রহণ করব। এই কথাটি জানার পরে , জাভাটির সিরিয়ালাইজেশন প্রক্রিয়াটি কীভাবে বস্তুটি সিরিয়ালযুক্ত করা হয়েছে তার উপর আরও নিয়ন্ত্রণ সরবরাহ করে এবং আমি কেন জানতে আগ্রহী যে কেন এইরকম হুক পাইথনে নেই বলে মনে হয়।
ক্যালভিঙ্কৃষি

এটি আমার প্রথম পদ্ধতি ছিল, তবে এটি আসলে কাজ করে না (যাইহোক আমার জন্য)।
zeekay

4
>>> json.dumps(foobar('x', 'y'), cls=MyEncoder) <<< '["x", "y"]'
zeekay

19
আহ, পাইথন ২.7++ _iterencode আর JSONEncoder এর পদ্ধতি নয়।
zeekay

4
@ ক্যালভিন ধন্যবাদ, আমি নেমটিউটলটিকেও দরকারী বলে মনে করি, আশা করি এটি JSON এ পুনরাবৃত্তভাবে এনকোড করার আরও ভাল সমাধান হতে পারে। @ জেকি ইয়েপ, 2.7+ এ দেখে মনে হচ্ছে তারা এটিকে লুকিয়ে রাখে যাতে এটি আর আর ওভাররাইড করা যায় না। হতাশাজনক।
স্যাম্পলবায়াস

77

যদি namedtupleআপনি কেবলমাত্র সিরিয়ালাইজ করতে চান তবে এর _asdict()পদ্ধতিটি ব্যবহার করে (পাইথন> = 2.7 সহ) কাজ করবে

>>> from collections import namedtuple
>>> import json
>>> FB = namedtuple("FB", ("foo", "bar"))
>>> fb = FB(123, 456)
>>> json.dumps(fb._asdict())
'{"foo": 123, "bar": 456}'

4
আমি অ্যাট্রিবিউটআরার পাচ্ছি: উইন্ডোজটিতে পাইথন ২.7 (এক্স )৪) তে কোডটি চালানোর সময় 'এফবি' অবজেক্টটির কোনও ' ডিক ' বৈশিষ্ট্য নেই । তবে fb._asdict () ঠিকঠাক কাজ করে।
geographika

4
fb._asdict()বা vars(fb)আরও ভাল হবে।
jpmc26

4
@ jpmc26: আপনি varsএকটি ছাড়া কোনও অবজেক্টে ব্যবহার করতে পারবেন না __dict__
রাফলেউইন্ড

@Rufflewind আপনি ব্যবহার করতে পারবেন না __dict__তাদের উপর, নয়তো। =)
jpmc26

4
পাইথন 3 __dict__সরানো হয়েছে। _asdictউভয় কাজ করতে প্রদর্শিত হবে।
অ্যান্ডি হেডেন

21

দেখে মনে হচ্ছে আপনি সাবক্লাস করতে সক্ষম হয়েছিলেন simplejson.JSONEncoder এই কাজটি করতে তবে সর্বশেষ সিম্পলসন কোড সহ, এটি আর নেই: আপনাকে প্রকৃতপক্ষে প্রকল্পের কোডটি সংশোধন করতে হবে। আমি সিম্পজসন কেন নামটুপলসকে সমর্থন না করা উচিত তার কোন কারণ দেখছি না, তাই আমি প্রকল্পটি কাঁটাচামচ করেছিলাম, নামচতুষ্পিক সমর্থনটি যুক্ত করেছি, এবং আমি বর্তমানে আমার শাখাটি মূল প্রকল্পে ফিরে টানার জন্য অপেক্ষা করছি । যদি এখনই ঠিক করতে হয় তবে আমার কাঁটাচামচ থেকে টানুন।

সম্পাদনা : এর সর্বশেষ সংস্করণ মত দেখায় simplejsonএখন স্থানীয়ভাবে এই সঙ্গে সমর্থন namedtuple_as_objectবিকল্প, যা ডিফল্ট True


4
আপনার সম্পাদনাটি সঠিক উত্তর। সিম্পজসন জেসনের চেয়ে আলাদাভাবে নামফলকগুলি (আমার মতে: আরও ভাল) সিরিয়ালাইজ করে। এটি সত্যই প্যাটার্নটি তৈরি করে: "চেষ্টা করুন: সিম্পলসনকে জসন ছাড়া আমদানি করুন: আমদানি করুন জেসন", ঝুঁকিপূর্ণ, যেহেতু সিম্পলজসন ইনস্টল করা আছে কিনা তার উপর নির্ভর করে আপনি কিছু মেশিনে ভিন্ন আচরণ পেতে পারেন। যে কারণে, আমার এখন আমার প্রচুর সেটআপ ফাইলগুলিতে সিম্পজসন প্রয়োজন এবং সেই প্যাটার্নটি বর্জন করা।
75

4
@ মারআর 75 - এর জন্য ডিট্টো ujson, যা এ জাতীয় প্রান্তের ক্ষেত্রে আরও উদ্ভট এবং অবিশ্বাস্য ...
ম্যাক

আমি ব্যবহার করে একটি পুনরাবৃত্তির নামটুপল জেসসনে সিরিয়ালায়িত করতে simplejson.dumps(my_tuple, indent=4)
পেরেছিলাম

5

এটি করার জন্য আমি একটি লাইব্রেরি লিখেছি: https://github.com/ltworf/typedload

এটি থেকে নামকরণ-টিপল এবং ফিরে যেতে পারে।

এটি তালিকা, সেট, এনাম, ইউনিয়ন, ডিফল্ট মান সহ বেশ জটিল নেস্টেড স্ট্রাকচার সমর্থন করে। এটি সর্বাধিক সাধারণ ক্ষেত্রে আবশ্যক।

সম্পাদনা: গ্রন্থাগারটি ডেটাগ্লাস এবং অ্যাটার ক্লাসগুলিও সমর্থন করে


2

এটি পুনরাবৃত্তভাবে নামকৃত টিপল ডেটাটিকে জসন-এ রূপান্তর করে।

print(m1)
## Message(id=2, agent=Agent(id=1, first_name='asd', last_name='asd', mail='2@mai.com'), customer=Customer(id=1, first_name='asd', last_name='asd', mail='2@mai.com', phone_number=123123), type='image', content='text', media_url='h.com', la=123123, ls=4512313)

def reqursive_to_json(obj):
    _json = {}

    if isinstance(obj, tuple):
        datas = obj._asdict()
        for data in datas:
            if isinstance(datas[data], tuple):
                _json[data] = (reqursive_to_json(datas[data]))
            else:
                 print(datas[data])
                _json[data] = (datas[data])
    return _json

data = reqursive_to_json(m1)
print(data)
{'agent': {'first_name': 'asd',
'last_name': 'asd',
'mail': '2@mai.com',
'id': 1},
'content': 'text',
'customer': {'first_name': 'asd',
'last_name': 'asd',
'mail': '2@mai.com',
'phone_number': 123123,
'id': 1},
'id': 2,
'la': 123123,
'ls': 4512313,
'media_url': 'h.com',
'type': 'image'}

4
+1 আমি প্রায় একই তৈরি করেছি। তবে আপনার রিটার্ন জেসন নয় ডিক্টর। আপনার কাছে অবশ্যই "না ', এবং যদি আপনার বস্তু একটি মান একটি বুলিয়ান, এটা সত্য রূপান্তরিত করা হবে না আমি মনে করি এটা অভি রুপান্তর, তারপর JSON মধ্যে রূপান্তর করতে json.dumps ব্যবহার
ফ্রেড লরেন্ট

2

আরও বেশি সুবিধাজনক সমাধান হ'ল সাজসজ্জার ব্যবহার করা (এটি সুরক্ষিত ক্ষেত্র ব্যবহার করে _fields)।

পাইথন ২.7++:

import json
from collections import namedtuple, OrderedDict

def json_serializable(cls):
    def as_dict(self):
        yield OrderedDict(
            (name, value) for name, value in zip(
                self._fields,
                iter(super(cls, self).__iter__())))
    cls.__iter__ = as_dict
    return cls

#Usage:

C = json_serializable(namedtuple('C', 'a b c'))
print json.dumps(C('abc', True, 3.14))

# or

@json_serializable
class D(namedtuple('D', 'a b c')):
    pass

print json.dumps(D('abc', True, 3.14))

পাইথন ৩.6..6++:

import json
from typing import TupleName

def json_serializable(cls):
    def as_dict(self):
        yield {name: value for name, value in zip(
            self._fields,
            iter(super(cls, self).__iter__()))}
    cls.__iter__ = as_dict
    return cls

# Usage:

@json_serializable
class C(NamedTuple):
    a: str
    b: bool
    c: float

print(json.dumps(C('abc', True, 3.14))

এটি করবেন না, তারা সমস্ত সময় অভ্যন্তরীণ এপিআই পরিবর্তন করে। আমার টাইপডলোড লাইব্রেরিতে বিভিন্ন পাই সংস্করণের জন্য বেশ কয়েকটি কেস রয়েছে।
LtWorf

হ্যাঁ, এটা পরিষ্কার। তবে, পরীক্ষা না করে কারওরও নতুন পাইথন সংস্করণে মাইগ্রেট করা উচিত নয়। এবং, অন্যান্য সমাধানগুলি ব্যবহার করে _asdict, এটি একটি "সুরক্ষিত" শ্রেণীর সদস্যও।
দিমিত্রি টি।

4
এলটি ওয়ার্ফ, আপনার গ্রন্থাগারটি জিপিএল এবং হিমশীতল নিয়ে কাজ করে না
টমাস

4
@ এলটি ওয়ার্ফ আপনার গ্রন্থাগারটিও _fields;-) github.com/ltworf/typedload/blob/master/typedload/datadumper.py ব্যবহার করে, এটি নামটুপলের পাবলিক এপিআই এর অংশ, আসলে: ডকস.পিথন.আর.৩./ / লিবারি / মানুষ এতে বিভ্রান্ত হয় আন্ডারস্কোর (কোন আশ্চর্য!)। এটি খারাপ নকশা, তবে তাদের কী কী পছন্দ ছিল তা আমি জানি না।
কোয়ান্ট_দেব

4
কি জিনিস? কখন? আপনি কি রিলিজ নোট উদ্ধৃত করতে পারেন?
কোয়ান্ট_দেব

2

Jsonplus গ্রন্থাগার NamedTuple দৃষ্টান্ত একটি serializer প্রদান করে। প্রয়োজনে সাধারণ অবজেক্টগুলি আউটপুট করতে তার সামঞ্জস্যতা মোডটি ব্যবহার করুন, তবে ডিফল্টটিকে পছন্দ করুন কারণ এটি পিছনে ডিকোডিংয়ের জন্য সহায়ক।


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

1

নেটিভটপলসকে দেশীয় পাইথন জেসন লাইব্রেরির মাধ্যমে সঠিকভাবে সিরিয়ালাইজ করা অসম্ভব। এটি সর্বদা তালিকাগুলি হিসাবে টিপলস দেখতে পাবেন এবং এই আচরণটি পরিবর্তন করতে ডিফল্ট সিরিয়ালটিকে ওভাররাইড করা অসম্ভব। যদি জিনিসগুলি বাসা বাঁধে তবে এটি আরও খারাপ।

অর্জসনের মতো আরও দৃust় লাইব্রেরি ব্যবহার করা আরও ভাল :

import orjson
from typing import NamedTuple

class Rectangle(NamedTuple):
    width: int
    height: int

def default(obj):
    if hasattr(obj, '_asdict'):
        return obj._asdict()

rectangle = Rectangle(width=10, height=20)
print(orjson.dumps(rectangle, default=default))

=>

{
    "width":10,
    "height":20
}

4
আমি orjsonখুব ভক্ত ।
সার্কেলঅনক্রাইক্লস

0

এটি একটি পুরানো প্রশ্ন। যাহোক:

একই প্রশ্নযুক্ত সকলের জন্য একটি পরামর্শ, ব্যক্তিগত এবং অভ্যন্তরীণ বৈশিষ্ট্যগুলির যে NamedTupleকোনওটির আগে ব্যবহার করার বিষয়ে সাবধানতার সাথে ভাবুন কারণ তাদের আগে রয়েছে এবং সময়ের সাথে সাথে আবার পরিবর্তন হবে।

উদাহরণস্বরূপ, যদি আপনার NamedTuple ফ্ল্যাট ভ্যালু অবজেক্ট হয় এবং আপনি কেবল এটির ক্রমিকায়িত করতে আগ্রহী হন এবং এটি অন্য কোনও বস্তুর মধ্যে বাসা বাঁধার ক্ষেত্রে নয় তবে আপনি যে __dict__সমস্যাগুলি সরিয়ে বা _as_dict()পরিবর্তনের সাথে সাথে আসে এবং এজাতীয় কিছু করতে পারেন তা এড়াতে পারেন (এবং হ্যাঁ এটি পাইথন 3 কারণ এই উত্তরটি বর্তমানের জন্য):

from typing import NamedTuple

class ApiListRequest(NamedTuple):
  group: str="default"
  filter: str="*"

  def to_dict(self):
    return {
      'group': self.group,
      'filter': self.filter,
    }

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

কল পাওয়া যায় তবে কলটি করার জন্য defaultকাওয়ার্গ ব্যবহার করার চেষ্টা করেছি , তবে এটি তালিকায় রূপান্তরযোগ্য হিসাবে কল হয় নি ।dumpsto_dict()NamedTuple


4
_asdictনামযুক্ত জনসাধারণের API এর অংশ part তারা আন্ডারস্কোর ডকস.পাইথন.আর.৩.৩./ / লাইব্রেরি / এর আন্ডারস্কোরের কারণ ব্যাখ্যা করেছেন: "টিপলস থেকে উত্তরাধিকার সূত্রে প্রাপ্ত পদ্ধতিগুলি ছাড়াও, নামকৃত তিনটি অতিরিক্ত পদ্ধতি এবং দুটি বৈশিষ্ট্য সমর্থন করে field ক্ষেত্রের নাম, পদ্ধতি এবং বৈশিষ্ট্যের নামগুলির সাথে দ্বন্দ্ব রোধ করতে একটি আন্ডারস্কোর দিয়ে শুরু করুন। "
কোয়ান্ট_দেব

@ কোয়ান্ট_দেব ধন্যবাদ, আমি এই ব্যাখ্যাটি দেখতে পাইনি। এটি এপিআই স্থিতিশীলতার গ্যারান্টি নয়, তবে এই পদ্ধতিগুলি আরও বিশ্বাসযোগ্য করে তুলতে সহায়তা করে। আমি স্পষ্টভাবে_ডিক্ট পাঠযোগ্যতার মতোই করি, তবে আমি দেখতে পাচ্ছি যে এটি পুনরায় বাস্তবায়নের মতো মনে হচ্ছে _াস_ডিক্ট
dlamblin

0

সমস্যাটি আমার এখানে দেওয়া। এটি নেমডটপলকে সিরিয়ালাইজ করে, ভাঁজ করা নামডটপলস এবং তাদের ভিতরে তালিকাগুলির যত্ন নেয়

def recursive_to_dict(obj: Any) -> dict:
_dict = {}

if isinstance(obj, tuple):
    node = obj._asdict()
    for item in node:
        if isinstance(node[item], list): # Process as a list
            _dict[item] = [recursive_to_dict(x) for x in (node[item])]
        elif getattr(node[item], "_asdict", False): # Process as a NamedTuple
            _dict[item] = recursive_to_dict(node[item])
        else: # Process as a regular element
            _dict[item] = (node[item])
return _dict

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