एक अजगर वर्ग जो तानाशाही की तरह काम करता है


113

मैं एक कस्टम वर्ग लिखना चाहता हूं जो ऐसा व्यवहार करता है dict- इसलिए, मुझे विरासत में मिला है dict

मेरा प्रश्न, हालांकि, यह है: क्या मुझे dictअपनी __init__()विधि में एक निजी सदस्य बनाने की आवश्यकता है ? मैं इस बात को नहीं देखता, क्योंकि मेरे पास पहले से ही dictव्यवहार है अगर मुझे बस विरासत में मिला है dict

क्या कोई इंगित कर सकता है कि अधिकांश विरासत वाले स्निपेट नीचे के समान क्यों दिखते हैं?

class CustomDictOne(dict):
   def __init__(self):
      self._mydict = {} 

   # other methods follow

सरल के बजाय ...

class CustomDictTwo(dict):
   def __init__(self):
      # initialize my other stuff here ...

   # other methods follow

वास्तव में, मुझे लगता है कि मुझे इस सवाल का जवाब देने में संदेह है कि उपयोगकर्ता सीधे आपके शब्दकोश तक नहीं पहुंच सकते (यानी उन्हें आपके द्वारा प्रदान की गई एक्सेस विधियों का उपयोग करना होगा)।

हालांकि, ऐरे एक्सेस ऑपरेटर के बारे में क्या []? कोई इसे कैसे लागू करेगा? अब तक, मैंने एक उदाहरण नहीं देखा है जो दिखाता है कि []ऑपरेटर को कैसे ओवरराइड करना है।

इसलिए यदि []कस्टम क्लास में एक्सेस फंक्शन नहीं दिया गया है, तो वंशानुगत आधार विधियाँ एक अलग शब्दकोष पर संचालित होंगी?

मैंने पायथन वंशानुक्रम की मेरी समझ का परीक्षण करने के लिए निम्नलिखित स्निपेट की कोशिश की:

class myDict(dict):
    def __init__(self):
        self._dict = {}

    def add(self, id, val):
        self._dict[id] = val


md = myDict()
md.add('id', 123)
print md[id]

मुझे निम्नलिखित त्रुटि मिली:

KeyError: <बिल्ट-इन फंक्शन आईडी>

ऊपर दिए गए कोड में क्या गलत है?

मैं कक्षा को कैसे सही करूं myDictताकि मैं इस तरह कोड लिख सकूं?

md = myDict()
md['id'] = 123

[संपादित करें]

मैंने अपनी डेस्क से धराशायी होने से पहले की गई मूर्खतापूर्ण त्रुटि से छुटकारा पाने के लिए ऊपर दिए गए कोड नमूने को संपादित किया है। यह एक टाइपो था (मुझे इसे त्रुटि संदेश से देखा जाना चाहिए था)।

जवाबों:



105
class Mapping(dict):

    def __setitem__(self, key, item):
        self.__dict__[key] = item

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

    def __repr__(self):
        return repr(self.__dict__)

    def __len__(self):
        return len(self.__dict__)

    def __delitem__(self, key):
        del self.__dict__[key]

    def clear(self):
        return self.__dict__.clear()

    def copy(self):
        return self.__dict__.copy()

    def has_key(self, k):
        return k in self.__dict__

    def update(self, *args, **kwargs):
        return self.__dict__.update(*args, **kwargs)

    def keys(self):
        return self.__dict__.keys()

    def values(self):
        return self.__dict__.values()

    def items(self):
        return self.__dict__.items()

    def pop(self, *args):
        return self.__dict__.pop(*args)

    def __cmp__(self, dict_):
        return self.__cmp__(self.__dict__, dict_)

    def __contains__(self, item):
        return item in self.__dict__

    def __iter__(self):
        return iter(self.__dict__)

    def __unicode__(self):
        return unicode(repr(self.__dict__))


o = Mapping()
o.foo = "bar"
o['lumberjack'] = 'foo'
o.update({'a': 'b'}, c=44)
print 'lumberjack' in o
print o

In [187]: run mapping.py
True
{'a': 'b', 'lumberjack': 'foo', 'foo': 'bar', 'c': 44}

37
यदि आप उपवर्ग पर जा रहे हैं dict, तो आपको superउदाहरण के लिए केवल निर्दिष्ट करने के बजाय ऑब्जेक्ट (स्वयं का उपयोग करना ) का उपयोग करना चाहिए __dict__- जिसका अनिवार्य रूप से मतलब है कि आप हर उदाहरण के लिए दो dicts बना रहे हैं।
हारून हॉल

8
आत्म .__ डिक्ट्री__ वास्तविक शब्दकोश सामग्री के समान नहीं है। प्रत्येक अजगर वस्तु, उसके प्रकार की परवाह किए बिना, _dict__जिसमें सभी वस्तु विशेषताएँ (विधियाँ, क्षेत्र आदि) समाहित हैं। आप इसके साथ गड़बड़ नहीं करना चाहते हैं जब तक कि आप खुद को संशोधित करने वाला कोड नहीं लिखना चाहते ...
Raik

85

ऐशे ही

class CustomDictOne(dict):
   def __init__(self,*arg,**kw):
      super(CustomDictOne, self).__init__(*arg, **kw)

अब आप अंतर्निहित कार्यों का उपयोग कर सकते हैं, जैसे dict.get()कि self.get()

आपको छिपे हुए को लपेटने की आवश्यकता नहीं है self._dict। आपकी कक्षा पहले से ही एक तानाशाही है।


3
यह। dictइसके निर्माता को बिना बुलाए पहले से विरासत में लेने का कोई मतलब नहीं है ।
सिरकोरा

1
ध्यान दें कि आपके विरासत में dictवास्तव में 2 तानाशाही उदाहरण हैं: 1 विरासत में मिला कंटेनर है, और दूसरा वर्ग-विशेषताओं को रखने वाला तानाशाह है - आप स्लॉट का उपयोग करके इससे बच सकते हैं ।
एकॉस्टिस

1
__dict__वास्तव में इतनी के रूप में लंबे समय के उपयोगकर्ताओं के लिए यह उपयोग करने का प्रयास नहीं करते हैं, यह ठीक ही जब वह पहली बार पहुंचने पर बनाई गई है। __slots__हालांकि अच्छा होगा।
आरोन हॉल

9
रिक्त स्थान का उपयोग करें अल्पविराम के बाद आप बर्बरता करो! ;-)
जेम्स बर्क

10

पूर्णता की खातिर, यहाँ नवीनतम पायथन 2.x (लेखन के समय के रूप में 2.7.7) के लिए @ björn-pollex द्वारा उल्लिखित दस्तावेज़ का लिंक दिया गया है:

कंटेनर प्रकार का अनुकरण

(टिप्पणी फ़ंक्शन का उपयोग नहीं करने के लिए क्षमा करें, मुझे स्टैकओवरफ़्लो द्वारा ऐसा करने की अनुमति नहीं है।)


3

इस कोड के साथ समस्या:

class myDict(dict):
    def __init__(self):
        self._dict = {}

    def add(id, val):
        self._dict[id] = val


md = myDict()
md.add('id', 123)

... यह है कि आपकी 'जोड़' विधि (... और कोई भी विधि जिसे आप एक वर्ग का सदस्य बनना चाहते हैं) को अपने पहले तर्क के रूप में स्पष्ट 'स्व' घोषित करने की आवश्यकता है, जैसे:

def add(self, 'id', 23):

कुंजी द्वारा आइटम तक पहुंचने के लिए ऑपरेटर को ओवरलोडिंग को लागू करने के लिए, जादू विधियों के लिए डॉक्स में देखें __getitem__और __setitem__

ध्यान दें कि क्योंकि पायथन डक टंकण का उपयोग करता है, इसलिए वास्तव में भाषा के तानाशाह वर्ग से अपने कस्टम तानाशाह वर्ग को प्राप्त करने का कोई कारण नहीं हो सकता है - आप क्या करने की कोशिश कर रहे हैं, इसके बारे में अधिक जानकारी के बिना (उदाहरण के लिए, यदि आपको इस का एक उदाहरण पारित करने की आवश्यकता है वर्ग में कुछ जगह है कि जब तक टूट जाएगा isinstance(MyDict(), dict) == True), तुम सिर्फ एपीआई लागू करने से बेहतर हो सकता है कि अपने वर्ग को पर्याप्त रूप से तानाशाही की तरह है और वहाँ रोक रहा है।


3

यहाँ एक वैकल्पिक समाधान है:

class AttrDict(dict):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.__dict__ = self

a = AttrDict()
a.a = 1
a.b = 2

यह बुरा है क्योंकि आप किसी भी कस्टम विधि को परिभाषित नहीं करते हैं और अन्य समस्याएं भी हैं जैसा कि अन्य उत्तर में कहा गया है।
शीतल शाह

मुझे ठीक इसी की आवश्यकता थी। धन्यवाद!
जेकब्रिंकमैन

2

मैं वास्तव में कहीं भी इस का सही जवाब नहीं देखता

class MyClass(dict):
    
    def __init__(self, a_property):
        self[a_property] = a_property

आप वास्तव में क्या कर रहे हैं अपने खुद को परिभाषित करते हैं __init__- कि वास्तव में यह सब है भी।

एक और उदाहरण (थोड़ा और जटिल):

class MyClass(dict):

    def __init__(self, planet):
        self[planet] = planet
        info = self.do_something_that_returns_a_dict()
        if info:
            for k, v in info.items():
                self[k] = v

    def do_something_that_returns_a_dict(self):
        return {"mercury": "venus", "mars": "jupiter"}

जब आप किसी प्रकार के तर्क को एम्बेड करना चाहते हैं तो यह अंतिम उदाहरण आसान है।

वैसे भी ... संक्षेप class GiveYourClassAName(dict)में, आपकी कक्षा को एक तानाशाह की तरह बनाने के लिए पर्याप्त है। आपके द्वारा किया जाने वाला कोई भी तानाशाही ऑपरेशन selfएक नियमित तानाशाह की तरह ही होगा।


1

यह मेरा सबसे अच्छा उपाय है। मैंने कई बार इसका इस्तेमाल किया।

class DictLikeClass:
    ...
    def __getitem__(self, key):
        return getattr(self, key)

    def __setitem__(self, key, value):
        setattr(self, key, value)
    ...

आप इस तरह का उपयोग कर सकते हैं:

>>> d = DictLikeClass()
>>> d["key"] = "value"
>>> print(d["key"])

0

पायथन से अंतर्निहित विरासत में कभी भी मत बनो! उदाहरण के लिए updateविधि का उपयोग नहीं किया __setitem__, वे अनुकूलन के लिए बहुत कुछ करते हैं। UserDict का उपयोग करें।

from collections import UserDict

class MyDict(UserDict):
    def __delitem__(self, key):
        pass
    def __setitem__(self, key, value):
        pass

1
इस आधार पर कि किसी को कभी भी अंतर्निहित तानाशाह से विरासत में नहीं मिलना चाहिए? दस्तावेज़ीकरण ( docs.python.org/3/library/collections.html#collections.UserDict ) से: "इस वर्ग की आवश्यकता को आंशिक रूप से सीधे से स्पष्ट करने की क्षमता के द्वारा दबाया गया है; हालाँकि, यह वर्ग आसान हो सकता है। काम क्योंकि अंतर्निहित शब्दकोश एक विशेषता के रूप में सुलभ है। " एक ही पृष्ठ पर: संग्रह मॉड्यूल "संस्करण 3.3 के बाद से हटा दिया गया है, संस्करण 3.9 में हटा दिया जाएगा: संग्रह मॉड्यूल के लिए मूव्ड कलेक्शन एब्सट्रैक्ट बेस क्लासेस।" ... जिसमें यूजरडिक्ट नहीं है।
न्यूमेसुंगिस

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