एक वस्तु के खेतों से पायथन शब्दकोश


343

क्या आप जानते हैं कि एक मनमानी वस्तु से एक शब्दकोश बनाने के लिए एक अंतर्निहित फ़ंक्शन है? मैं ऐसा कुछ करना चाहता हूं:

>>> class Foo:
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> props(f)
{ 'bar' : 'hello', 'baz' : 'world' }

नोट: इसमें विधियाँ शामिल नहीं होनी चाहिए। केवल खेतों।

जवाबों:


421

ध्यान दें कि पायथन 2.7 में सबसे अच्छा अभ्यास नई शैली की कक्षाओं (पायथन 3 के साथ आवश्यक नहीं) का उपयोग करना है, अर्थात

class Foo(object):
   ...

इसके अलावा, 'ऑब्जेक्ट' और 'क्लास' के बीच अंतर है। एक मनमानी वस्तु से एक शब्दकोश बनाने के लिए , यह उपयोग करने के लिए पर्याप्त है __dict__। आमतौर पर, आप कक्षा स्तर पर अपने तरीकों और उदाहरण के स्तर पर अपनी विशेषताओं की घोषणा करेंगे, इसलिए __dict__ठीक होना चाहिए। उदाहरण के लिए:

>>> class A(object):
...   def __init__(self):
...     self.b = 1
...     self.c = 2
...   def do_nothing(self):
...     pass
...
>>> a = A()
>>> a.__dict__
{'c': 2, 'b': 1}

एक बेहतर दृष्टिकोण ( टिप्पणियों में रॉबर्ट द्वारा सुझाया गया ) बिलिन varsफ़ंक्शन है:

>>> vars(a)
{'c': 2, 'b': 1}

वैकल्पिक रूप से, आप क्या करना चाहते हैं, इस पर निर्भर करते हुए, यह विरासत से अच्छा हो सकता है dict। फिर आपकी कक्षा पहले से ही एक शब्दकोश है, और यदि आप चाहते हैं कि आप ओवरराइड कर सकते हैं getattrऔर / या setattrकॉल कर सकते हैं और तानाशाही को सेट कर सकते हैं । उदाहरण के लिए:

class Foo(dict):
    def __init__(self):
        pass
    def __getattr__(self, attr):
        return self[attr]

    # etc...

3
यदि ए की विशेषता में से कोई एक कस्टम गेट्टर है तो क्या होता है? (एक समारोह @property डेकोरेटर के साथ)? क्या यह अभी भी ____dict____ में दिखाई देता है? इसका मूल्य क्या होगा?
zakdances

11
__dict__यदि ऑब्जेक्ट स्लॉट्स का उपयोग कर रहा है (या C मॉड्यूल में परिभाषित) काम नहीं करेगा।
एंटीमनी

1
क्या कक्षा की वस्तुओं के लिए इस पद्धति के बराबर है? IE के बजाय f = Foo () का उपयोग कर रहे हैं और फिर f .__ dict__ कर रहे हैं, सीधे Foo .__ dict__ करें।
शिफा

49
क्षमा करें, मुझे यह देर से आ रहा है, लेकिन vars(a)ऐसा नहीं करना चाहिए ? मेरे लिए यह __dict__सीधे आह्वान करने के लिए बेहतर है ।
रॉबर्ट

2
दूसरे उदाहरण के __getattr__ = dict.__getitem__लिए व्यवहार को ठीक से दोहराने के लिए करना बेहतर होगा , तो आप भी चाहेंगे __setattr__ = dict.__setitem__और __delattr__ = dict.__delitem__पूर्ण-नेस के लिए।
तदह मैकडॉनल्ड्स-जेनसेन

141

इसके बजाय x.__dict__, यह वास्तव में उपयोग करने के लिए अधिक पायथोनिक है vars(x)


3
माना। ध्यान दें कि आप टाइप करके दूसरे तरीके (तानाशाही-> वर्ग) को भी बदल सकते हैं MyClass(**my_dict), यह मानकर कि आपने एक ऐसे पैरामीटर के साथ एक कंस्ट्रक्टर को परिभाषित किया है जो क्लास की विशेषताओं को प्रतिबिंबित करता है। निजी विशेषताओं तक पहुँचने या तानाशाही को ओवरराइड करने की आवश्यकता नहीं है।
tvt173

2
क्या आप बता सकते हैं कि यह अधिक पायथोनिक क्यों है?
ह्यूग डब्ल्यू

1
सबसे पहले, पायथन आम तौर पर कॉलिंग डंडर आइटम को सीधे हिलाता है, और इसे अप्रत्यक्ष रूप से एक्सेस करने के लिए लगभग हमेशा एक विधि या फ़ंक्शन (या ऑपरेटर) होता है। सामान्य तौर पर, डंडर विशेषताएँ और विधियाँ एक कार्यान्वयन विवरण हैं, और "आवरण" फ़ंक्शन का उपयोग करके आप दोनों को अलग कर सकते हैं। दूसरा, इस तरह से आप varsफ़ंक्शन को ओवरराइड कर सकते हैं और ऑब्जेक्ट को बदले बिना अतिरिक्त कार्यक्षमता का परिचय दे सकते हैं ।
बेरिस्लाव लोपैक

1
यह तब भी विफल रहता है जब आपकी कक्षा उपयोग करती __slots__है।
cz

यह सही है, और मैंने हमेशा महसूस किया कि "स्लैटेड" वर्गों के varsबराबर लौटने के लिए इसका विस्तार करने के लिए एक अच्छी दिशा होगी __dict__। अभी के लिए, इसे एक __dict__संपत्ति जोड़कर अनुकरण किया जा सकता है जो वापस लौटता है {x: getattr(self, x) for x in self.__slots__}(यह सुनिश्चित नहीं है कि यह किसी भी तरह से प्रदर्शन या व्यवहार को प्रभावित करता है)।
बेरिस्लाव लोपैक

59

dirBuiltin आप सभी ऑब्जेक्ट के गुण, जैसे विशेष उपाय अपना सकते हैं दे देंगे __str__, __dict__और दूसरों को जो शायद आप नहीं चाहते की एक पूरी गुच्छा। लेकिन आप कुछ ऐसा कर सकते हैं:

>>> class Foo(object):
...     bar = 'hello'
...     baz = 'world'
...
>>> f = Foo()
>>> [name for name in dir(f) if not name.startswith('__')]
[ 'bar', 'baz' ]
>>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__')) 
{ 'bar': 'hello', 'baz': 'world' }

तो propsइस तरह से अपने फ़ंक्शन को परिभाषित करके, केवल डेटा विशेषताओं को वापस करने के लिए और विधियों को नहीं बढ़ा सकते हैं :

import inspect

def props(obj):
    pr = {}
    for name in dir(obj):
        value = getattr(obj, name)
        if not name.startswith('__') and not inspect.ismethod(value):
            pr[name] = value
    return pr

1
इस कोड में विधियाँ शामिल हैं। क्या तरीकों को बाहर करने का एक तरीका है? मुझे केवल वस्तु के क्षेत्र की आवश्यकता है। साभार
जूलियो सेसर

ismethodकार्यों को नहीं पकड़ता है। उदाहरण: inspect.ismethod(str.upper)inspect.isfunctionहालांकि ज्यादा मददगार नहीं है। निश्चित नहीं है कि इसे तुरंत कैसे प्राप्त किया जाए।
एहतेश चौधरी

मैंने कुछ गुनगुनाहट की पुनरावृत्ति की और सभी त्रुटियों को यहाँ एक गहराई तक अनदेखा कर दिया, धन्यवाद! gist.github.com/thorsummoner/bf0142fd24974a0ced77878768a33a3069
ThorSummoner

26

मैंने दोनों उत्तरों के संयोजन के साथ समझौता किया है:

dict((key, value) for key, value in f.__dict__.iteritems() 
    if not callable(value) and not key.startswith('__'))

यह भी काम करता है, लेकिन ध्यान रखें कि यह आपको केवल उदाहरण पर सेट की गई विशेषताएँ देगा, न कि कक्षा पर (आपके उदाहरण में वर्ग फू की तरह) ...
dF।

तो, jarsrascal, आप एक कोड जैसे प्रॉपर () में उपरोक्त कोड को लपेटने से बेहतर हैं, तो आप प्रॉप्स (एफ) या प्रॉप्स (फू) को कॉल कर सकते हैं। ध्यान दें कि आप 'इनलाइन' कोड लिखने के बजाय एक फ़ंक्शन लिखना लगभग हमेशा बेहतर होते हैं।
quamrana

अच्छा, btw नोट यह python2.7 के लिए है, बस आइटम के साथ python3 relpace iteritems () के लिए है।
मोर्टेन

और किस बारे में staticmethod? यह नहीं है callable
एलेक्स

17

मुझे लगा कि मैं आपको दिखाने के लिए कुछ समय लूंगा कि आप किसी वस्तु को किस तरह से लिख सकते हैं dict(obj)

class A(object):
    d = '4'
    e = '5'
    f = '6'

    def __init__(self):
        self.a = '1'
        self.b = '2'
        self.c = '3'

    def __iter__(self):
        # first start by grabbing the Class items
        iters = dict((x,y) for x,y in A.__dict__.items() if x[:2] != '__')

        # then update the class items with the instance items
        iters.update(self.__dict__)

        # now 'yield' through the items
        for x,y in iters.items():
            yield x,y

a = A()
print(dict(a)) 
# prints "{'a': '1', 'c': '3', 'b': '2', 'e': '5', 'd': '4', 'f': '6'}"

इस कोड का प्रमुख भाग __iter__फ़ंक्शन है।

जैसा कि टिप्पणियां बताती हैं, पहली चीज जो हम करते हैं वह है क्लास की वस्तुओं को पकड़ना और '__' से शुरू होने वाली किसी भी चीज को रोकना।

एक बार जब आप इसे बना लेते हैं dict, तो आप updateकमांड का उपयोग कर सकते हैं और उदाहरण में पास कर सकते हैं __dict__

ये आपको सदस्यों का एक पूरा वर्ग + उदाहरण शब्दकोश देंगे। अब जो कुछ बचा है वह उन पर पुनरावृति करना है और रिटर्न प्राप्त करना है।

इसके अलावा, यदि आप इसे बहुत उपयोग करने की योजना बनाते हैं, तो आप एक @iterableक्लास डेकोरेटर बना सकते हैं ।

def iterable(cls):
    def iterfn(self):
        iters = dict((x,y) for x,y in cls.__dict__.items() if x[:2] != '__')
        iters.update(self.__dict__)

        for x,y in iters.items():
            yield x,y

    cls.__iter__ = iterfn
    return cls

@iterable
class B(object):
    d = 'd'
    e = 'e'
    f = 'f'

    def __init__(self):
        self.a = 'a'
        self.b = 'b'
        self.c = 'c'

b = B()
print(dict(b))

यह सभी तरीकों को भी पकड़ लेगा, लेकिन हमें केवल क्लास + इंस्टेंस फ़ील्ड की आवश्यकता है। शायद dict((x, y) for x, y in KpiRow.__dict__.items() if x[:2] != '__' and not callable(y))इसे हल करेंगे? लेकिन अभी भी staticतरीके हो सकते हैं :(
एलेक्स

15

एक मनमानी वस्तु से एक शब्दकोश बनाने के लिए , यह उपयोग करने के लिए पर्याप्त है __dict__

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

class c(object):
    x = 3
a = c()

hasattr (a, 'x') सत्य है, लेकिन 'x' a .__ डिक्ट्री में दिखाई नहीं देता है।


इस मामले में समाधान क्या है? चूंकि vars()काम नहीं करता है
should_be_working

@should_be_working dirइस मामले में समाधान है। उस बारे में अन्य जवाब देखें।
अल्बर्ट

8

देर से जवाब लेकिन पूर्णता के लिए प्रदान की और googlers का लाभ:

def props(x):
    return dict((key, getattr(x, key)) for key in dir(x) if key not in dir(x.__class__))

यह कक्षा में परिभाषित तरीकों को नहीं दिखाएगा, लेकिन यह अभी भी उन क्षेत्रों को दिखाएगा जिनमें लैम्बदास को सौंपा गया है या वे जो एक डबल अंडरस्कोर के साथ शुरू करते हैं।


6

मुझे लगता है कि कक्षा के लिए गेटीम विशेषता बनाने का सबसे आसान तरीका है । यदि आपको ऑब्जेक्ट पर लिखने की आवश्यकता है, तो आप एक कस्टम सेटट्रा बना सकते हैं । यहाँ एक उदाहरण के लिए getitem है :

class A(object):
    def __init__(self):
        self.b = 1
        self.c = 2
    def __getitem__(self, item):
        return self.__dict__[item]

# Usage: 
a = A()
a.__getitem__('b')  # Outputs 1
a.__dict__  # Outputs {'c': 2, 'b': 1}
vars(a)  # Outputs {'c': 2, 'b': 1}

तानाशाह वस्तुओं को एक डिक्शनरी में बताता है और डिक्शनरी ऑब्जेक्ट का इस्तेमाल आपकी ज़रूरत की वस्तु को पाने के लिए किया जा सकता है।


इस उत्तर के बाद भी स्पष्ट नहीं है कि किसी वस्तु से शब्दकोश कैसे प्राप्त किया जाए। गुण नहीं, लेकिन संपूर्ण शब्दकोश;)
मैक्सकोरियोकोव

6

उपयोग करने __dict__का एक नकारात्मक पक्ष यह है कि यह उथला है; यह किसी भी उपवर्ग को शब्दकोशों में परिवर्तित नहीं करेगा।

यदि आप Python3.5 या उच्चतर का उपयोग कर रहे हैं, तो आप उपयोग कर सकते हैं jsons:

>>> import jsons
>>> jsons.dump(f)
{'bar': 'hello', 'baz': 'world'}

3

यदि आप अपनी विशेषताओं के भाग को सूचीबद्ध करना चाहते हैं, तो ओवरराइड करें __dict__:

def __dict__(self):
    d = {
    'attr_1' : self.attr_1,
    ...
    }
    return d

# Call __dict__
d = instance.__dict__()

यह बहुत मदद करता है अगर आपके instanceकुछ बड़े ब्लॉक डेटा मिलते हैं और आप dसंदेश कतार की तरह रेडिस पर धकेलना चाहते हैं ।


__dict__एक विशेषता है, एक विधि नहीं है, इसलिए यह उदाहरण इंटरफ़ेस बदलता है (यानी आपको इसे कॉल करने योग्य के रूप में कॉल करने की आवश्यकता है), इसलिए यह इसे ओवरराइड नहीं कर रहा है।
बेरिस्लाव लोपैक

0

पायथन 3:

class DateTimeDecoder(json.JSONDecoder):

   def __init__(self, *args, **kargs):
        JSONDecoder.__init__(self, object_hook=self.dict_to_object,
                         *args, **kargs)

   def dict_to_object(self, d):
       if '__type__' not in d:
          return d

       type = d.pop('__type__')
       try:
          dateobj = datetime(**d)
          return dateobj
       except:
          d['__type__'] = type
          return d

def json_default_format(value):
    try:
        if isinstance(value, datetime):
            return {
                '__type__': 'datetime',
                'year': value.year,
                'month': value.month,
                'day': value.day,
                'hour': value.hour,
                'minute': value.minute,
                'second': value.second,
                'microsecond': value.microsecond,
            }
        if isinstance(value, decimal.Decimal):
            return float(value)
        if isinstance(value, Enum):
            return value.name
        else:
            return vars(value)
    except Exception as e:
        raise ValueError

अब आप अपनी कक्षा के अंदर उपरोक्त कोड का उपयोग कर सकते हैं:

class Foo():
  def toJSON(self):
        return json.loads(
            json.dumps(self, sort_keys=True, indent=4, separators=(',', ': '), default=json_default_format), cls=DateTimeDecoder)


Foo().toJSON() 

0

vars() महान है, लेकिन वस्तुओं के नेस्टेड वस्तुओं के लिए काम नहीं करता है

ऑब्जेक्ट्स के नेस्टेड ऑब्जेक्ट को तानाशाही में बदलें:

def to_dict(self):
    return json.loads(json.dumps(self, default=lambda o: o.__dict__))
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.