10

मेरे पहले दो शब्दकोशों की सुविधाओं गठबंधन करने के लिए collections मॉड्यूल में प्रयास एक वर्ग है कि उन्हें विरासत में बनाने के लिए किया गया था:मैं ऑर्डर्ड डिक्ट और डिफॉल्टडिंट को विरासत में डिफ़ॉल्ट, आदेशित आदेश क्यों नहीं बना सकता?

from collections import OrderedDict, defaultdict 

class DefaultOrderedDict(defaultdict, OrderedDict): 
    def __init__(self, default_factory=None, *a, **kw): 
     super().__init__(default_factory, *a, **kw) 

हालांकि, मैं इस शब्दकोश के लिए एक आइटम असाइन नहीं कर सकते:

d = DefaultOrderedDict(lambda: 0) 
d['a'] = 1 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "/usr/lib64/python3.3/collections/__init__.py", line 64, in __setitem__ 
    self.__map[key] = link = Link() 
AttributeError: 'DefaultOrderedDict' object has no attribute '_OrderedDict__map' 

दरअसल, this question about how to create a similar object में ऐसे उत्तर हैं जो OrderedDict कक्षा को विस्तारित करके प्राप्त करते हैं और defaultdict प्रदान की गई अतिरिक्त विधियों को मैन्युअल रूप से पुन: कार्यान्वित करते हैं। एकाधिक विरासत का उपयोग क्लीनर होगा। यह क्यों काम नहीं करता है?

+0

एक अलग रूप में के रूप में सही पर वर्गों पर ध्यान नहीं देता अजगर विधि संकल्प क्रम बाएं से दाएं चला जाता है, आप 'डिफ़ॉल्ट डिक्ट (lambda: 0) 'के बजाय' डिफ़ॉल्ट डिक्ट (int) 'का उपयोग कर सकते हैं। –

उत्तर

3

कारण यह है कि बजाय एमआरओ में अगली कक्षा के __init__ बुलाने की init method of defaultdictPyDict_Type की init इसलिए __map जैसी विशेषताओं कि OrderedDict's __init__ में स्थापित कर रहे हैं में से कुछ से प्रारंभ नहीं किया जाता है कहता है, इसलिए त्रुटि है।

>>> DefaultOrderedDict.mro() 
[<class '__main__.DefaultOrderedDict'>, 
<class 'collections.defaultdict'>, 
<class 'collections.OrderedDict'>, 
<class 'dict'>, <class 'object'>] 

और defaultdict अपने स्वयं के __setitem__ विधि की जरूरत नहीं है:

>>> defaultdict.__setitem__ 
<slot wrapper '__setitem__' of 'dict' objects> 
>>> dict.__setitem__ 
<slot wrapper '__setitem__' of 'dict' objects> 
>>> OrderedDict.__setitem__ 
<unbound method OrderedDict.__setitem__> 

इसलिए, जब आप d['a'] = 1 कहा जाता है, __setitem__ अजगर की तलाश में पहुंच गया OrdereredDict के __setitem__ और अप्रारंभीकृत __map विशेषता के उनके उपयोग त्रुटि उठाई:


एक फिक्स होगा दोनों defaultdict पर __init__ और OrderedDict स्पष्ट रूप से कहते हैं:

class DefaultOrderedDict(defaultdict, OrderedDict): 
    def __init__(self, default_factory=None, *a, **kw): 
     for cls in DefaultOrderedDict.mro()[1:-2]: 
      cls.__init__(self, *a, **kw) 
+1

आप केवल बेस क्लास के ऑर्डर को स्वैप क्यों नहीं कर सकते: 'क्लास ऑर्डर्ड डिफॉल्ट डिक्ट (ऑर्डर्ड डिक्ट, डिफॉल्टडिक्ट):', और उसके बाद आपका '__init __ (self, default_factory = none, * args, ** kwargs)' में दो पंक्तियां हैं : 'सुपर (ऑर्डरर्ड डीफॉल्ट डिक्ट, स्वयं) .__ init __ (* args, ** kwargs)' और 'self.default_dict = default_dict'? – Sam

+1

मैंने सैम के सुझाव की कोशिश की और यह काम किया। (ठीक है, मैंने डिफ़ॉल्ट_डिक्ट को default_factory में बदल दिया है!) – samwyse

4

शायद आप एक जावा पृष्ठभूमि से आ रहे हैं, लेकिन एकाधिक वंशानुक्रम आपकी आशा से यह अजगर में करता है नहीं करता है। defaultOrderedDict की init से कॉलिंग सुपर defaultdict की init और OrderedDict की कभी नहीं init के रूप में सुपर() कहते हैं। नक्शा विशेषता पहली बार OrderedDict के __init फ़ंक्शन में परिभाषित की गई है। कार्यान्वयन निम्नलिखित है (स्रोत से):

def __init__(self, *args, **kwds): 
    '''Initialize an ordered dictionary. The signature is the same as 
    regular dictionaries, but keyword arguments are not recommended because 
    their insertion order is arbitrary. 

    ''' 
    if len(args) > 1: 
     raise TypeError('expected at most 1 arguments, got %d' % len(args)) 
    try: 
     self.__root 
    except AttributeError: 
     self.__root = root = []      # sentinel node 
     root[:] = [root, root, None] 
     self.__map = {} 
    self.__update(*args, **kwds) 

ध्यान दें कि यह विशेषता निजी होने के साथ नहीं है। एकाधिक विरासत के साथ एक न्यूनतम उदाहरण इसे स्पष्ट कर सकते हैं:

class Foo: 
    def __init__(self): 
     self.foo=2 

class Bar: 
    def __init__(self): 
     self.bar=1 

class FooBar(Foo,Bar): 
    def __init__(self): 
     super().__init__() 

fb = FooBar() 

fb.foo 
>>2 
fb.bar 
>>AttributeError: 'FooBar' object has no attribute 'bar' 

तो, बार के निर्माता कभी नहीं बुलाया गया था। जब तक यह समारोह नाम यह चाहता है के साथ एक कक्षा पाता है (इस मामले init में) और फिर अन्य सभी (इस मामले में बार)

संबंधित मुद्दे