नेस्टेड पायथन को ऑब्जेक्ट में परिवर्तित करें?


537

मैं कुछ नेस्टेड dicts और सूचियों (यानी जावास्क्रिप्ट-शैली ऑब्जेक्ट सिंटैक्स) के साथ एक तानाशाही पर विशेषता का उपयोग करके डेटा प्राप्त करने के लिए एक सुंदर तरीके की खोज कर रहा हूं।

उदाहरण के लिए:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

इस तरह से सुलभ होना चाहिए:

>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
bar

मुझे लगता है, यह पुनरावृत्ति के बिना संभव नहीं है, लेकिन डाइट के लिए एक वस्तु शैली प्राप्त करने का एक अच्छा तरीका क्या होगा?


6
मैं हाल ही में ऐसा ही कुछ करने की कोशिश कर रहा था, लेकिन एक आवर्ती शब्दकोश कुंजी ("से" - जो कि पायथन कीवर्ड है) ने मुझे इसके साथ जाने से रोका। क्योंकि जैसे ही आपने उस विशेषता तक पहुंचने के लिए "x.from" का उपयोग करने की कोशिश की, आपको एक सिंटैक्स त्रुटि मिलेगी।
दाऊजी स्ट्रॉस

3
यह वास्तव में एक समस्या है, लेकिन बड़े तानाशाहों तक पहुँचने में जीवन को आसान बनाने के लिए "से" पर छोड़ सकता हूं :) टाइपिंग x ['a'] ['d'] [१] [f foo ’] वास्तव में कष्टप्रद है, इसलिए xad [१] .फू नियम। यदि आपको जरूरत है, तो आप इसे गेटैट (एक्स, 'से') तक पहुंचा सकते हैं या इसके बजाय विशेषता के रूप में _from का उपयोग कर सकते हैं।
मार्क

5
from_पीईपी 8 के_from अनुसार के बजाय ।
कोस

1
आप getattr(x, 'from')विशेषता का नाम बदलने के बजाय उपयोग कर सकते हैं ।
जॉर्ज वी। रीली

3
इनमें से अधिकांश "समाधान" काम नहीं करते हैं (यहां तक ​​कि स्वीकार किए जाते हैं, नेस्टेड की अनुमति नहीं देता है d1.b.c), मुझे लगता है कि यह स्पष्ट है कि आपको लाइब्रेरी से कुछ का उपयोग करना चाहिए, जैसे संग्रह से नामांकित , जैसा कि यह उत्तर बताता है, ।। ।
एंडी हेडन

जवाबों:


659

अपडेट: पायथन 2.6 और उसके बाद, विचार करें कि क्या namedtupleडेटा संरचना आपकी आवश्यकताओं के अनुरूप है:

>>> from collections import namedtuple
>>> MyStruct = namedtuple('MyStruct', 'a b d')
>>> s = MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s
MyStruct(a=1, b={'c': 2}, d=['hi'])
>>> s.a
1
>>> s.b
{'c': 2}
>>> s.c
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'MyStruct' object has no attribute 'c'
>>> s.d
['hi']

वैकल्पिक (मूल उत्तर सामग्री) है:

class Struct:
    def __init__(self, **entries):
        self.__dict__.update(entries)

फिर, आप उपयोग कर सकते हैं:

>>> args = {'a': 1, 'b': 2}
>>> s = Struct(**args)
>>> s
<__main__.Struct instance at 0x01D6A738>
>>> s.a
1
>>> s.b
2

19
यहाँ भी - यह विशेष रूप से MongoDB जैसे दस्तावेज़ उन्मुख डेटाबेस से पायथन ऑब्जेक्ट्स के पुनर्निर्माण के लिए उपयोगी है।
मिकमेकाना

13
प्रिटियर प्रिंटिंग ऐड पाने के लिए: repr __ (सेल्फ): रिटर्न '<% s>'% str ('\ n') .join ('% s:% s'% (k, repr (v)) for (k, v) ) स्व। में। तानाशाही .iteritems ())
छः

15
क्या यह नेस्टेड शब्दकोशों के साथ काम करेगा? और वस्तुओं और या सूची आदि युक्त dicts क्या कोई कैच है?
सैम स्टोइलिंगा

5
@ एसम एस: यह Structनेस्टेड शब्दकोशों से नेस्टेड एस नहीं बनाएगा , लेकिन सामान्य तौर पर मूल्य का प्रकार कुछ भी हो सकता है। कुंजी एक वस्तु स्लॉट के लिए उपयुक्त होने के लिए प्रतिबंधित है
एली बेन्द्स्की

51
-1 क्योंकि एक) यह नेस्टेड dicts, जो स्पष्ट रूप से सवाल के लिए कहा, और ख लिए काम नहीं करता) ही कार्यक्षमता वर्तमान में मानक पुस्तकालयों में मौजूद है argparse.Namespace(जो भी परिभाषित किया गया है __eq__, __ne__, __contains__)।
विम

110
class obj(object):
    def __init__(self, d):
        for a, b in d.items():
            if isinstance(b, (list, tuple)):
               setattr(self, a, [obj(x) if isinstance(x, dict) else x for x in b])
            else:
               setattr(self, a, obj(b) if isinstance(b, dict) else b)

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = obj(d)
>>> x.b.c
2
>>> x.d[1].foo
'bar'

7
अच्छा! मैं .items () .iteritems () द्वारा प्रतिस्थापित करूंगा, हालांकि, एक छोटी मेमोरी पदचिह्न के लिए।
एरिक ओ लेबिगॉट

7
यदि ओपी आवश्यकता नहीं है, तो यह एक मुद्दा नहीं है - लेकिन ध्यान दें कि यह पुनरावर्ती रूप से सूचियों में सूची में वस्तुओं को संसाधित नहीं करेगा।
Anon

3
मुझे लगता है कि यह एक पुराना उत्तर है, लेकिन इन दिनों उस बदसूरत लाइन के बजाय एक अमूर्त आधार वर्ग का उपयोग करना बेहतर होगाif isinstance(b, (list, tuple)):
wim

4
सुझाव: पठनीय स्ट्रिंग प्रतिनिधित्व जैसी अतिरिक्त सुविधाओं के लिए objवर्ग से विरासत में मिला है argparse.Namespace
सेरानो

2
उपयोग के मामले के आधार पर, आम तौर पर हम जाँच करेगा कि यह है नहीं कोई स्ट्रिंग प्रकार है, लेकिन यह है कि है एक अनुक्रम प्रकार
विम

107

आश्चर्यजनक रूप से किसी ने बंच का उल्लेख नहीं किया है । यह लाइब्रेरी विशेष रूप से तानाशाह वस्तुओं को विशेषता शैली की पहुंच प्रदान करने के लिए है और यह वही करता है जो ओपी चाहता है। प्रदर्शन:

>>> from bunch import bunchify
>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = bunchify(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'

एक पायथन 3 पुस्तकालय https://github.com/Infinidat/munch पर उपलब्ध है - क्रेडिट कोडी में जाता है


16
और एक अजगर है 3 संगत (प्रतीत होता है 2.6-3.4 प्रतीत होता है) बंच की शाखा का नाम
मुंच

बंच इन सब का सबसे अच्छा समाधान है क्योंकि यह कई प्रकार के क्रमांकन का अच्छी तरह से समर्थन करता है, और बनाए रखा जाता है। बहुत बहुत धन्यवाद। काश python3 संस्करण को एक ही चीज़ का नाम दिया जाता, buecause क्यों नहीं।
जोनाथन

4
तो बस एक पूर्वाभास, बंच और आकर्षण के साथ ही उस मामले के लिए बहुत धीमी गति से कर रहे हैं। जब उन्होंने हमारे आवेदन में लगातार उपयोग देखा, तो उन्होंने क्रमशः मेरे अनुरोध समय के 1/3 और 1/2 का उपभोग किया। निश्चित रूप से अनदेखी करने के लिए कुछ नहीं। इसके बारे में अधिक बात करें stackoverflow.com/a/31569634/364604
JayD3e

हालांकि, यह ऑब्जेक्ट्स जैसी एक्सेस की अनुमति देता है, यह getattr के माध्यम से ऐसा करता है । यह IPYthon जैसे स्मार्ट REPLs में आत्मनिरीक्षण को कठिन बनाता है।
GDorn

जिज्ञासु की तुलना में जिज्ञासु की यह सलाह है कि github.com/kennknowles/python-jsonpath-rw
MarkHu

64
x = type('new_dict', (object,), d)

फिर इस पर पुनरावृत्ति जोड़ें और आपका काम हो गया।

इसे संपादित करें कि मैं इसे कैसे लागू करूंगा:

>>> d
{'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> def obj_dic(d):
    top = type('new', (object,), d)
    seqs = tuple, list, set, frozenset
    for i, j in d.items():
        if isinstance(j, dict):
            setattr(top, i, obj_dic(j))
        elif isinstance(j, seqs):
            setattr(top, i, 
                type(j)(obj_dic(sj) if isinstance(sj, dict) else sj for sj in j))
        else:
            setattr(top, i, j)
    return top

>>> x = obj_dic(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'

1
आप टाइप-ऑब्जेक्ट क्यों बना रहे हैं और उन्हें इंस्टेंट नहीं कर रहे हैं? क्या यह अधिक तार्किक नहीं होगा? मेरा मतलब है, क्यों नहीं करते हैं top_instance = top()और लौटते हैं कि आप कहाँ लौटते हैं top?
पैनकेक

6
"पत्ती" डेटा के लिए अच्छा है, लेकिन उदाहरण आसानी से "टहनियाँ" छोड़ देते हैं जैसे xऔर x.bजो बदसूरत लौट आते हैं<class '__main__.new'>
मार्कहु

46

एक संग्रह सहायक कहा जाता है namedtuple, जो आपके लिए यह कर सकता है:

from collections import namedtuple

d_named = namedtuple('Struct', d.keys())(*d.values())

In [7]: d_named
Out[7]: Struct(a=1, b={'c': 2}, d=['hi', {'foo': 'bar'}])

In [8]: d_named.a
Out[8]: 1

28
यह नेस्टेड dicts के लिए पुनरावृत्ति के प्रश्न का उत्तर नहीं देता है।
derigible

4
आप नामांकितों को संशोधित नहीं कर सकते।
मैक्स

क्या हम इस बात की गारंटी दे सकते हैं कि सूची का क्रम कुंजियों () और मूल्यों () क्रम से मेल खाता है? मेरा मतलब है, अगर यह एक आदेश दिया गया है, हाँ। लेकिन एक मानक तानाशाही? मुझे पता है कि CPython 3.6+ और PyPy "कॉम्पैक्ट" डाइक का आदेश दिया गया है, लेकिन दस्तावेज़ीकरण के हवाले से: "इस नए कार्यान्वयन के आदेश-संरक्षण पहलू को कार्यान्वयन विवरण माना जाता है और इस पर भरोसा नहीं किया जाना चाहिए"
हॉकोक

38
class Struct(object):
    """Comment removed"""
    def __init__(self, data):
        for name, value in data.iteritems():
            setattr(self, name, self._wrap(value))

    def _wrap(self, value):
        if isinstance(value, (tuple, list, set, frozenset)): 
            return type(value)([self._wrap(v) for v in value])
        else:
            return Struct(value) if isinstance(value, dict) else value

किसी भी गहराई के किसी भी अनुक्रम / तानाशाही / मूल्य संरचना के साथ इस्तेमाल किया जा सकता है।


4
इसका उत्तर होना चाहिए। यह नेस्टिंग के लिए अच्छा काम करता है। आप इसे json.load () के लिए एक object_hook के रूप में भी उपयोग कर सकते हैं।
010110110101

2
2009 से साइलेंटगॉस्ट के कार्यात्मक उत्तर के समान - पत्ती नोड डेटा सुलभ है, लेकिन अभिभावक / टहनियाँ वस्तु संदर्भ के रूप में प्रदर्शित होते हैं। सुंदर प्रिंट करने के लिए,def __repr__(self): return '{%s}' % str(', '.join("'%s': %s" % (k, repr(v)) for (k, v) in self.__dict__.iteritems()))
मार्क

5
पायथन 3.x उपयोगकर्ता: यह लाइन 4 के .items()बजाय बस है .iteritems()। (फ़ंक्शन का नाम बदल दिया गया था, लेकिन यह आवश्यक रूप से समान है )
नव पोस्ट आधुनिक

नेस्टेड वस्तुओं के लिए एकदम सही काम करता है, धन्यवाद! मैं, python3 iteritems के लिए () के रूप में एक टिप्पणी newbies के रूप में आइटम करने के लिए परिवर्तित किया जाना चाहिए ()
20scar Andreu

31

मुझे जो महसूस हो रहा है वह पिछले उदाहरणों का सबसे अच्छा पहलू है, यहां बताया गया है कि मैं क्या लेकर आया हूं:

class Struct:
  '''The recursive class for building and representing objects with.'''
  def __init__(self, obj):
    for k, v in obj.iteritems():
      if isinstance(v, dict):
        setattr(self, k, Struct(v))
      else:
        setattr(self, k, v)
  def __getitem__(self, val):
    return self.__dict__[val]
  def __repr__(self):
    return '{%s}' % str(', '.join('%s : %s' % (k, repr(v)) for
      (k, v) in self.__dict__.iteritems()))

ध्यान दें कि कंस्ट्रक्टर को छोटा किया जा सकता है: def __init__(self, dct): for k, v in dct.iteritems(): setattr(self, k, isinstance(v, dict) and self.__class__(v) or v) जो स्पष्ट कॉल को भी हटा देता हैStruct
जॉर्ज वी। रेली

2
मैं इसके बजाय अपने स्वयं के उत्तर को कम नहीं करूंगा, लेकिन इस पर पीछे मुड़कर मैंने देखा है कि यह अनुक्रम प्रकारों में पुनरावृत्ति नहीं करता है। xd [1] .foo इस मामले में विफल रहता है।
अय्यानी

2
isinstance(v, dict)जांच के रूप में बेहतर होगा isinstance(v, collections.Mapping)तो यह चीजें dict की तरह भविष्य संभाल कर सकते हैं
hobs

29

यदि आपका तानाशाह से आ रहा है json.loads(), तो आप इसे एक पंक्ति में (बजाय एक तानाशाह के) एक वस्तु में बदल सकते हैं:

import json
from collections import namedtuple

json.loads(data, object_hook=lambda d: namedtuple('X', d.keys())(*d.values()))

यह भी देखें कि JSON डेटा को पायथन ऑब्जेक्ट में कैसे परिवर्तित करें


.loadsअगर आप एक बहुत बड़ा JSON ऑब्जेक्ट है तो नियमित रूप से बहुत धीमा लगता है
michaelsnowden

16

यदि आप एक वस्तु के रूप में (या मुश्किल कुंजियों के लिए एक तानाशाही) के रूप में तानाशाही कुंजी तक पहुँच प्राप्त करना चाहते हैं, तो इसे पुनरावर्ती रूप से करें, और मूल ताना को अद्यतन करने में भी सक्षम हों, आप कर सकते हैं:

class Dictate(object):
    """Object view of a dict, updating the passed in dict when values are set
    or deleted. "Dictate" the contents of a dict...: """

    def __init__(self, d):
        # since __setattr__ is overridden, self.__dict = d doesn't work
        object.__setattr__(self, '_Dictate__dict', d)

    # Dictionary-like access / updates
    def __getitem__(self, name):
        value = self.__dict[name]
        if isinstance(value, dict):  # recursively view sub-dicts as objects
            value = Dictate(value)
        return value

    def __setitem__(self, name, value):
        self.__dict[name] = value
    def __delitem__(self, name):
        del self.__dict[name]

    # Object-like access / updates
    def __getattr__(self, name):
        return self[name]

    def __setattr__(self, name, value):
        self[name] = value
    def __delattr__(self, name):
        del self[name]

    def __repr__(self):
        return "%s(%r)" % (type(self).__name__, self.__dict)
    def __str__(self):
        return str(self.__dict)

उदाहरण उपयोग:

d = {'a': 'b', 1: 2}
dd = Dictate(d)
assert dd.a == 'b'  # Access like an object
assert dd[1] == 2  # Access like a dict
# Updates affect d
dd.c = 'd'
assert d['c'] == 'd'
del dd.a
del dd[1]
# Inner dicts are mapped
dd.e = {}
dd.e.f = 'g'
assert dd['e'].f == 'g'
assert d == {'c': 'd', 'e': {'f': 'g'}}

13
>>> def dict2obj(d):
        if isinstance(d, list):
            d = [dict2obj(x) for x in d]
        if not isinstance(d, dict):
            return d
        class C(object):
            pass
        o = C()
        for k in d:
            o.__dict__[k] = dict2obj(d[k])
        return o


>>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
>>> x = dict2obj(d)
>>> x.a
1
>>> x.b.c
2
>>> x.d[1].foo
'bar'

12

मैंने कोशिश की कि अटॉर्नी और बीओटीएच की कोशिश की जाए बंच कीपुस्तकालयों और उन्हें मेरे उपयोग के लिए बहुत धीमी गति से मिल गया। एक दोस्त के बाद और मैंने इस पर गौर किया, हमने पाया कि इन पुस्तकालयों को लिखने का मुख्य तरीका पुस्तकालय में आक्रामक रूप से एक नेस्टेड ऑब्जेक्ट के माध्यम से पुनरावृत्ति करना है और पूरे शब्दकोश ऑब्जेक्ट की प्रतियां बनाना है। इसे ध्यान में रखते हुए, हमने दो महत्वपूर्ण बदलाव किए। 1) हमने विशेषताओं को आलसी लोड किया 2) एक शब्दकोश वस्तु की प्रतियां बनाने के बजाय, हम एक हल्के वजन वाली प्रॉक्सी वस्तु की प्रतियां बनाते हैं। यह अंतिम कार्यान्वयन है। इस कोड का उपयोग करने की प्रदर्शन वृद्धि अविश्वसनीय है। AttrDict या Bunch का उपयोग करते समय, इन दोनों पुस्तकालयों ने मेरे अनुरोध समय के क्रमशः 1/2 और 1/3 का उपभोग किया (क्या !?)। इस कोड ने उस समय को लगभग कुछ भी नहीं (कहीं-कहीं 0.5ms की सीमा में) घटा दिया। यह आपकी आवश्यकताओं पर निर्भर करता है,

class DictProxy(object):
    def __init__(self, obj):
        self.obj = obj

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

    def __getattr__(self, key):
        try:
            return wrap(getattr(self.obj, key))
        except AttributeError:
            try:
                return self[key]
            except KeyError:
                raise AttributeError(key)

    # you probably also want to proxy important list properties along like
    # items(), iteritems() and __len__

class ListProxy(object):
    def __init__(self, obj):
        self.obj = obj

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

    # you probably also want to proxy important list properties along like
    # __iter__ and __len__

def wrap(value):
    if isinstance(value, dict):
        return DictProxy(value)
    if isinstance(value, (tuple, list)):
        return ListProxy(value)
    return value

मूल कार्यान्वयन यहाँ देखें https://stackoverflow.com/users/704327/michael-merickel द्वारा ।

ध्यान देने वाली दूसरी बात यह है कि यह कार्यान्वयन बहुत सरल है और उन सभी तरीकों को लागू नहीं करता है जिनकी आपको आवश्यकता हो सकती है। आपको DictProxy या ListProxy ऑब्जेक्ट्स पर आवश्यकतानुसार लिखना होगा।


9

x.__dict__.update(d) ठीक करना चाहिए।


आपके उत्तर के लिए धन्यवाद, लेकिन x क्या है? तानाशाह या एक मानक वस्तु? क्या आप मुझे एक संकेत दे सकते हैं।
मार्क

x आपकी वस्तु है। हर वस्तु में एक हुकुम होता है । किसी ऑब्जेक्ट के तानाशाह को अपडेट करके आप वास्तव में उसमें महत्वपूर्ण संस्करण को अपडेट कर रहे हैं।
एलेक्स रोड्रिग्स

बोल्ड शब्द हैं _ _ तानाशाह _ _
एलेक्स रोड्रिग्स

15
यह नेस्टेड शब्दकोशों को हैंडल नहीं करेगा।
13

प्रत्येक वस्तु में एक __dict__: कोशिश नहीं है object().__dict__और आपको मिलेगाAttributeError: 'object' object has no attribute '__dict__'
विल मैनले

8

आप कस्टम ऑब्जेक्ट हुक के साथ मानक लाइब्रेरी के jsonमॉड्यूल का लाभ उठा सकते हैं :

import json

class obj(object):
    def __init__(self, dict_):
        self.__dict__.update(dict_)

def dict2obj(d):
    return json.loads(json.dumps(d), object_hook=obj)

उदाहरण उपयोग:

>>> d = {'a': 1, 'b': {'c': 2}, 'd': ['hi', {'foo': 'bar'}]}
>>> o = dict2obj(d)
>>> o.a
1
>>> o.b.c
2
>>> o.d[0]
u'hi'
>>> o.d[1].foo
u'bar'

और यह कड़ाई से केवल पढ़ने योग्य नहीं है क्योंकि यह है namedtuple, यानी आप मूल्यों को बदल सकते हैं - संरचना नहीं:

>>> o.b.c = 3
>>> o.b.c
3

1
अब तक का सर्वश्रेष्ठ उत्तर
कॉनर

मुझे नेस्टेड तत्वों के लिए जोंस लोडिंग तंत्र का उपयोग करने का विचार पसंद है। लेकिन हमारे पास पहले से ही एक तानाशाही है और मुझे यह पसंद नहीं है कि किसी को वस्तु में मैप करने के लिए उसमें से एक स्ट्रिंग बनाने की जरूरत है। मैं इसके बजाय एक ऐसा समाधान निकालना चाहूंगा जो वस्तुओं को सीधे एक तानाशाही से पैदा करता हो।
सैंड्रो

1
पहले स्ट्रिंग के रूप में परिवर्तित करने की आवश्यकता है, लेकिन बहुत सामान्य के रूप में एक के माध्यम से json.JSONEncoderऔर इसे बढ़ा सकता है object_hook
सैंड्रो

6

यह आपकी शुरुआत होनी चाहिए:

class dict2obj(object):
    def __init__(self, d):
        self.__dict__['d'] = d

    def __getattr__(self, key):
        value = self.__dict__['d'][key]
        if type(value) == type({}):
            return dict2obj(value)

        return value

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

x = dict2obj(d)
print x.a
print x.b.c
print x.d[1].foo

यह सूचियों के लिए काम नहीं करता है, फिर भी। आपको उपयोगकर्ता सूची में सूची को लपेटना होगा और __getitem__dicts को लपेटने के लिए अधिभार देना होगा।


2
इसे सूचियों के लिए काम करने के लिए, if isinstance(d, list)खंड के Anonउत्तर से उपयोग करें ।
विनय साजिप

6

मुझे पता है कि यहाँ पहले से ही बहुत सारे उत्तर पहले से ही हैं और मुझे पार्टी के लिए देर हो रही है, लेकिन यह विधि पुनरावर्ती होगी और 'जगह' एक शब्दकोश को ऑब्जेक्ट जैसी संरचना में बदल देगी ... वर्क्स इन 3.xx

def dictToObject(d):
    for k,v in d.items():
        if isinstance(v, dict):
            d[k] = dictToObject(v)
    return namedtuple('object', d.keys())(*d.values())

# Dictionary created from JSON file
d = {
    'primaryKey': 'id', 
    'metadata': 
        {
            'rows': 0, 
            'lastID': 0
        }, 
    'columns': 
        {
            'col2': {
                'dataType': 'string', 
                'name': 'addressLine1'
            }, 
            'col1': {
                'datatype': 'string', 
                'name': 'postcode'
            }, 
            'col3': {
                'dataType': 'string', 
                'name': 'addressLine2'
            }, 
            'col0': {
                'datatype': 'integer', 
                'name': 'id'
            }, 
            'col4': {
                'dataType': 'string', 
                'name': 'contactNumber'
            }
        }, 
        'secondaryKeys': {}
}

d1 = dictToObject(d)
d1.columns.col1 # == object(datatype='string', name='postcode')
d1.metadata.rows # == 0

आपका क्या मतलब है "वस्तु जैसी संरचना"?
MoralCode

1
बतख टाइपिंग सिद्धांत के कारण ऑब्जेक्ट-जैसे। मेरा मतलब है कि आप इसकी संपत्तियों तक पहुंच सकते हैं जैसे कि अगर यह एक वर्ग का उदाहरण होता। लेकिन यह उस अर्थ में एक वस्तु नहीं है, यह एक नामित टपल है।
ऐदन हदोन-राइट

5
from mock import Mock
d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
my_data = Mock(**d)

# We got
# my_data.a == 1

4

मुझे एक समाधान के बारे में बताएं जो मैंने लगभग कुछ समय पहले इस्तेमाल किया था। लेकिन सबसे पहले, कारण मुझे इस तथ्य से नहीं समझा गया है कि निम्नलिखित कोड:

d = {'from': 1}
x = dict2obj(d)

print x.from

यह त्रुटि देता है:

  File "test.py", line 20
    print x.from == 1
                ^
SyntaxError: invalid syntax

क्योंकि "से" एक पायथन कीवर्ड है, ऐसे कुछ शब्दकोष हैं जिनकी आप अनुमति नहीं दे सकते।


अब मेरा समाधान सीधे उनके नाम का उपयोग करके शब्दकोश आइटम तक पहुंचने की अनुमति देता है। लेकिन यह आपको "शब्दकोश शब्दार्थ" का उपयोग करने की भी अनुमति देता है। यहाँ उदाहरण उपयोग के साथ कोड है:

class dict2obj(dict):
    def __init__(self, dict_):
        super(dict2obj, self).__init__(dict_)
        for key in self:
            item = self[key]
            if isinstance(item, list):
                for idx, it in enumerate(item):
                    if isinstance(it, dict):
                        item[idx] = dict2obj(it)
            elif isinstance(item, dict):
                self[key] = dict2obj(item)

    def __getattr__(self, key):
        return self[key]

d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}

x = dict2obj(d)

assert x.a == x['a'] == 1
assert x.b.c == x['b']['c'] == 2
assert x.d[1].foo == x['d'][1]['foo'] == "bar"

1
वर्ग संरचना: init ___ (स्व, ** प्रविष्टियाँ): स्व .__ तानाशाही .अपडेट (प्रविष्टियाँ)
केनेथ रिट्ज

4

पुराना क्यू एंड ए, लेकिन मुझे बात करने के लिए कुछ और मिलता है। लगता है कि कोई भी पुनरावर्ती तानाशाही के बारे में बात नहीं करता है। यह मेरा कोड है:

#!/usr/bin/env python

class Object( dict ):
    def __init__( self, data = None ):
        super( Object, self ).__init__()
        if data:
            self.__update( data, {} )

    def __update( self, data, did ):
        dataid = id(data)
        did[ dataid ] = self

        for k in data:
            dkid = id(data[k])
            if did.has_key(dkid):
                self[k] = did[dkid]
            elif isinstance( data[k], Object ):
                self[k] = data[k]
            elif isinstance( data[k], dict ):
                obj = Object()
                obj.__update( data[k], did )
                self[k] = obj
                obj = None
            else:
                self[k] = data[k]

    def __getattr__( self, key ):
        return self.get( key, None )

    def __setattr__( self, key, value ):
        if isinstance(value,dict):
            self[key] = Object( value )
        else:
            self[key] = value

    def update( self, *args ):
        for obj in args:
            for k in obj:
                if isinstance(obj[k],dict):
                    self[k] = Object( obj[k] )
                else:
                    self[k] = obj[k]
        return self

    def merge( self, *args ):
        for obj in args:
            for k in obj:
                if self.has_key(k):
                    if isinstance(self[k],list) and isinstance(obj[k],list):
                        self[k] += obj[k]
                    elif isinstance(self[k],list):
                        self[k].append( obj[k] )
                    elif isinstance(obj[k],list):
                        self[k] = [self[k]] + obj[k]
                    elif isinstance(self[k],Object) and isinstance(obj[k],Object):
                        self[k].merge( obj[k] )
                    elif isinstance(self[k],Object) and isinstance(obj[k],dict):
                        self[k].merge( obj[k] )
                    else:
                        self[k] = [ self[k], obj[k] ]
                else:
                    if isinstance(obj[k],dict):
                        self[k] = Object( obj[k] )
                    else:
                        self[k] = obj[k]
        return self

def test01():
    class UObject( Object ):
        pass
    obj = Object({1:2})
    d = {}
    d.update({
        "a": 1,
        "b": {
            "c": 2,
            "d": [ 3, 4, 5 ],
            "e": [ [6,7], (8,9) ],
            "self": d,
        },
        1: 10,
        "1": 11,
        "obj": obj,
    })
    x = UObject(d)


    assert x.a == x["a"] == 1
    assert x.b.c == x["b"]["c"] == 2
    assert x.b.d[0] == 3
    assert x.b.d[1] == 4
    assert x.b.e[0][0] == 6
    assert x.b.e[1][0] == 8
    assert x[1] == 10
    assert x["1"] == 11
    assert x[1] != x["1"]
    assert id(x) == id(x.b.self.b.self) == id(x.b.self)
    assert x.b.self.a == x.b.self.b.self.a == 1

    x.x = 12
    assert x.x == x["x"] == 12
    x.y = {"a":13,"b":[14,15]}
    assert x.y.a == 13
    assert x.y.b[0] == 14

def test02():
    x = Object({
        "a": {
            "b": 1,
            "c": [ 2, 3 ]
        },
        1: 6,
        2: [ 8, 9 ],
        3: 11,
    })
    y = Object({
        "a": {
            "b": 4,
            "c": [ 5 ]
        },
        1: 7,
        2: 10,
        3: [ 12 , 13 ],
    })
    z = {
        3: 14,
        2: 15,
        "a": {
            "b": 16,
            "c": 17,
        }
    }
    x.merge( y, z )
    assert 2 in x.a.c
    assert 3 in x.a.c
    assert 5 in x.a.c
    assert 1 in x.a.b
    assert 4 in x.a.b
    assert 8 in x[2]
    assert 9 in x[2]
    assert 10 in x[2]
    assert 11 in x[3]
    assert 12 in x[3]
    assert 13 in x[3]
    assert 14 in x[3]
    assert 15 in x[2]
    assert 16 in x.a.b
    assert 17 in x.a.c

if __name__ == '__main__':
    test01()
    test02()

4

इस छोटे से प्रतिमान के मेरे संस्करण को अपलोड करना चाहता था।

class Struct(dict):
  def __init__(self,data):
    for key, value in data.items():
      if isinstance(value, dict):
        setattr(self, key, Struct(value))
      else:   
        setattr(self, key, type(value).__init__(value))

      dict.__init__(self,data)

यह वर्ग में आयात किए जाने वाले प्रकार के लिए विशेषताओं को संरक्षित करता है। मेरी एकमात्र चिंता आपके पार्सिंग शब्दकोश के भीतर से लिखावट के तरीकों की होगी। लेकिन अन्यथा ठोस लगता है!


हालांकि एक अच्छा विचार है, यह ओपी के उदाहरण के लिए काम नहीं करता है, वास्तव में यह शब्दकोश में पारित संशोधित करने के लिए लगता है! वास्तव में, df.aकाम भी नहीं करता है।
एंडी हेडन

4

यह भी अच्छा काम करता है

class DObj(object):
    pass

dobj = Dobj()
dobj.__dict__ = {'a': 'aaa', 'b': 'bbb'}

print dobj.a
>>> aaa
print dobj.b
>>> bbb

3

साइलेंटगॉस्ट के मूल सुझाव को लागू करने का एक और तरीका यहां दिया गया है:

def dict2obj(d):
  if isinstance(d, dict):
    n = {}
    for item in d:
      if isinstance(d[item], dict):
        n[item] = dict2obj(d[item])
      elif isinstance(d[item], (list, tuple)):
        n[item] = [dict2obj(elem) for elem in d[item]]
      else:
        n[item] = d[item]
    return type('obj_from_dict', (object,), n)
  else:
    return d

3

मैंने उस मामले पर ठोकर खाई, जिसकी मुझे पुनरावृत्ति करने के लिए वस्तुओं की सूची में बदलने की आवश्यकता थी, इसलिए रॉबर्टो के स्निपेट के आधार पर यहां बताया गया कि मेरे लिए क्या काम किया गया था:

def dict2obj(d):
    if isinstance(d, dict):
        n = {}
        for item in d:
            if isinstance(d[item], dict):
                n[item] = dict2obj(d[item])
            elif isinstance(d[item], (list, tuple)):
                n[item] = [dict2obj(elem) for elem in d[item]]
            else:
                n[item] = d[item]
        return type('obj_from_dict', (object,), n)
    elif isinstance(d, (list, tuple,)):
        l = []
        for item in d:
            l.append(dict2obj(item))
        return l
    else:
        return d

ध्यान दें कि स्पष्ट कारणों के लिए किसी भी टपल को इसकी सूची के समतुल्य परिवर्तित किया जाएगा।

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


3

क्या सिर्फ एक खाली वस्तु को अपने असाइन dictकरने के बारे में __dict__?

class Object:
    """If your dict is "flat", this is a simple way to create an object from a dict

    >>> obj = Object()
    >>> obj.__dict__ = d
    >>> d.a
    1
    """
    pass

बेशक यह आपके नेस्टेड उदाहरण पर विफल हो जाता है जब तक कि आप तानाशाही से फिर से न चलें:

# For a nested dict, you need to recursively update __dict__
def dict2obj(d):
    """Convert a dict to an object

    >>> d = {'a': 1, 'b': {'c': 2}, 'd': ["hi", {'foo': "bar"}]}
    >>> obj = dict2obj(d)
    >>> obj.b.c
    2
    >>> obj.d
    ["hi", {'foo': "bar"}]
    """
    try:
        d = dict(d)
    except (TypeError, ValueError):
        return d
    obj = Object()
    for k, v in d.iteritems():
        obj.__dict__[k] = dict2obj(v)
    return obj

और आपका उदाहरण सूची तत्व संभवतः Mappingइस तरह से (की, मूल्य) जोड़े की एक सूची होने का मतलब था :

>>> d = {'a': 1, 'b': {'c': 2}, 'd': [("hi", {'foo': "bar"})]}
>>> obj = dict2obj(d)
>>> obj.d.hi.foo
"bar"

2

यहाँ एक और कार्यान्वयन है:

class DictObj(object):
    def __init__(self, d):
        self.__dict__ = d

def dict_to_obj(d):
    if isinstance(d, (list, tuple)): return map(dict_to_obj, d)
    elif not isinstance(d, dict): return d
    return DictObj(dict((k, dict_to_obj(v)) for (k,v) in d.iteritems()))

[संपादित करें] सूचियों के भीतर भी dicts से निपटने के बारे में थोड़ा याद किया, न केवल अन्य dicts। जोड़ा गया फिक्स।


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

@ मर्क: दरअसल, डिक्टोजब के लिए हर बार एक नया शब्दकोश पारित किया जा रहा है, न कि केवल एक ही तरह की वस्तु से गुजरने के कारण, इसलिए यह वास्तव में नहीं होगा। ऐसा करने के लिए यह आवश्यक है, क्योंकि मुझे एक शब्दकोश में मूल्यों का अनुवाद करने की आवश्यकता है , इसलिए इसे स्वयं को म्यूट किए बिना मूल तानाशाही वस्तु से गुजरना असंभव होगा।
ब्रायन

इसके लिए कुछ उत्तर दिए गए हैं, स्वीकृत उत्तर ऐसा नहीं लगता है कि यह पुनरावर्ती होगा या सूचियों को संभाल सकेगा। मैंने उन सभी के माध्यम से पढ़ा और यह पहली नजर में सबसे सरल लग रहा था, मैंने परीक्षण किया और यह काम किया। बहुत बढ़िया जवाब।
ऑलवेजट्रेनिंग

2
class Struct(dict):
    def __getattr__(self, name):
        try:
            return self[name]
        except KeyError:
            raise AttributeError(name)

    def __setattr__(self, name, value):
        self[name] = value

    def copy(self):
        return Struct(dict.copy(self))

उपयोग:

points = Struct(x=1, y=2)
# Changing
points['x'] = 2
points.y = 1
# Accessing
points['x'], points.x, points.get('x') # 2 2 2
points['y'], points.y, points.get('y') # 1 1 1
# Accessing inexistent keys/attrs 
points['z'] # KeyError: z
points.z # AttributeError: z
# Copying
points_copy = points.copy()
points.x = 2
points_copy.x # 1

2

इस बारे में कैसा है:

from functools import partial
d2o=partial(type, "d2o", ())

यह तो इस तरह इस्तेमाल किया जा सकता है:

>>> o=d2o({"a" : 5, "b" : 3})
>>> print o.a
5
>>> print o.b
3

2

मुझे लगता है कि एक तानाशाह में संख्या, स्ट्रिंग और तानाशाही सबसे अधिक होती है। इसलिए मैं उस स्थिति को नजरअंदाज करता हूं जो ट्यूल, सूचियों और अन्य प्रकारों में एक तानाशाही के अंतिम आयाम में दिखाई नहीं देती है।

विरासत को ध्यान में रखते हुए, पुनरावृत्ति के साथ संयुक्त, यह प्रिंट समस्या को आसानी से हल करता है और डेटा को क्वेरी करने के दो तरीके भी प्रदान करता है, एक डेटा को संपादित करने का एक तरीका।

नीचे दिया गया उदाहरण देखें, एक तानाशाह जो छात्रों के बारे में कुछ जानकारी बताता है:

group=["class1","class2","class3","class4",]
rank=["rank1","rank2","rank3","rank4","rank5",]
data=["name","sex","height","weight","score"]

#build a dict based on the lists above
student_dic=dict([(g,dict([(r,dict([(d,'') for d in data])) for r in rank ]))for g in group])

#this is the solution
class dic2class(dict):
    def __init__(self, dic):
        for key,val in dic.items():
            self.__dict__[key]=self[key]=dic2class(val) if isinstance(val,dict) else val


student_class=dic2class(student_dic)

#one way to edit:
student_class.class1.rank1['sex']='male'
student_class.class1.rank1['name']='Nan Xiang'

#two ways to query:
print student_class.class1.rank1
print student_class.class1['rank1']
print '-'*50
for rank in student_class.class1:
    print getattr(student_class.class1,rank)

परिणाम:

{'score': '', 'sex': 'male', 'name': 'Nan Xiang', 'weight': '', 'height': ''}
{'score': '', 'sex': 'male', 'name': 'Nan Xiang', 'weight': '', 'height': ''}
--------------------------------------------------
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
{'score': '', 'sex': 'male', 'name': 'Nan Xiang', 'weight': '', 'height': ''}
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}
{'score': '', 'sex': '', 'name': '', 'weight': '', 'height': ''}

2

आमतौर पर आप अपनी पदानुक्रम में तानाशाही पदानुक्रम को दर्पण करना चाहते हैं, लेकिन सूची या ट्यूपल नहीं जो आमतौर पर सबसे निचले स्तर पर होते हैं। तो यह है कि मैंने ऐसा कैसे किया:

class defDictToObject(object):

    def __init__(self, myDict):
        for key, value in myDict.items():
            if type(value) == dict:
                setattr(self, key, defDictToObject(value))
            else:
                setattr(self, key, value)

तो हम करते हैं:

myDict = { 'a': 1,
           'b': { 
              'b1': {'x': 1,
                    'y': 2} },
           'c': ['hi', 'bar'] 
         }

और पाओ:

x.b.b1.x 1

x.c ['हाय', 'बार']


1

मेरा शब्दकोश इस प्रारूप का है:

addr_bk = {
    'person': [
        {'name': 'Andrew', 'id': 123, 'email': 'andrew@mailserver.com',
         'phone': [{'type': 2, 'number': '633311122'},
                   {'type': 0, 'number': '97788665'}]
        },
        {'name': 'Tom', 'id': 456,
         'phone': [{'type': 0, 'number': '91122334'}]}, 
        {'name': 'Jack', 'id': 7788, 'email': 'jack@gmail.com'}
    ]
}

जैसा कि देखा जा सकता है, मेरे पास डिक्शनरी और डिक्सेस की सूची है । इसका कारण यह है कि addr_bk को प्रोटोकॉल बफर डेटा से डिकोड किया गया था जो कि lwpb.cnec का उपयोग करके एक अजगर के रूप में परिवर्तित हो गया। वैकल्पिक क्षेत्र हैं (उदाहरण के लिए ईमेल => जहां कुंजी अनुपलब्ध हो सकती है) और दोहराया क्षेत्र (जैसे फोन => तानाशाह की सूची में परिवर्तित)।

मैंने उपरोक्त सभी प्रस्तावित समाधानों की कोशिश की। कुछ नेस्टेड शब्दकोशों को अच्छी तरह से संभाल नहीं करता है। अन्य लोग वस्तु विवरण आसानी से नहीं छाप सकते हैं।

केवल समाधान, डौवी स्ट्रॉस द्वारा डिक्टेड 2 बीओबी (तानाशाही) सबसे अच्छा काम करता है।

जब कुंजी नहीं मिल सकती है तो मैंने इसे संभालने के लिए इसे थोड़ा बढ़ाया है:

# Work the best, with nested dictionaries & lists! :)
# Able to print out all items.
class dict2obj_new(dict):
    def __init__(self, dict_):
        super(dict2obj_new, self).__init__(dict_)
        for key in self:
            item = self[key]
            if isinstance(item, list):
                for idx, it in enumerate(item):
                    if isinstance(it, dict):
                        item[idx] = dict2obj_new(it)
            elif isinstance(item, dict):
                self[key] = dict2obj_new(item)

    def __getattr__(self, key):
        # Enhanced to handle key not found.
        if self.has_key(key):
            return self[key]
        else:
            return None

फिर, मैंने इसका परीक्षण किया:

# Testing...
ab = dict2obj_new(addr_bk)

for person in ab.person:
  print "Person ID:", person.id
  print "  Name:", person.name
  # Check if optional field is available before printing.
  if person.email:
    print "  E-mail address:", person.email

  # Check if optional field is available before printing.
  if person.phone:
    for phone_number in person.phone:
      if phone_number.type == codec.enums.PhoneType.MOBILE:
        print "  Mobile phone #:",
      elif phone_number.type == codec.enums.PhoneType.HOME:
        print "  Home phone #:",
      else:
        print "  Work phone #:",
      print phone_number.number

1

" अजगर: मेरे लिए संपत्ति को गतिशील रूप से कैसे जोड़ें? "

class data(object):
    def __init__(self,*args,**argd):
        self.__dict__.update(dict(*args,**argd))

def makedata(d):
    d2 = {}
    for n in d:
        d2[n] = trydata(d[n])
    return data(d2)

def trydata(o):
    if isinstance(o,dict):
        return makedata(o)
    elif isinstance(o,list):
        return [trydata(i) for i in o]
    else:
        return o

आप makedataउस शब्दकोश पर कॉल करते हैं जिसे आप रूपांतरित करना चाहते हैं, या हो सकता trydataहै कि आप इनपुट के रूप में जो उम्मीद करते हैं उसके आधार पर, और यह एक डेटा ऑब्जेक्ट को बाहर निकालता है।

टिप्पणियाँ:

  • trydataयदि आपको अधिक कार्यक्षमता की आवश्यकता है, तो आप एलिफ जोड़ सकते हैं ।
  • यदि आप चाहते हैं x.a = {}या इसी तरह स्पष्ट रूप से यह काम नहीं करेगा ।
  • यदि आप एक आसानी से संस्करण चाहते हैं, तो मूल उत्तर से वर्ग डेटा का उपयोग करें ।
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.