कैसे सही ढंग से उपवर्गों को उप-विभाजित करें और __getitem__ & __setitem__ को ओवरराइड करें


84

मैं कुछ कोड डिबग कर रहा हूं और मैं यह पता लगाना चाहता हूं कि किसी विशेष शब्दकोश को कब एक्सेस किया जाए। खैर, यह वास्तव में एक वर्ग है जो उप- dictअतिरिक्त और कुछ अतिरिक्त सुविधाओं को लागू करता है। वैसे भी, मैं जो करना चाहूंगा वह dictखुद को उप-वर्ग करना और ओवरराइड जोड़ना __getitem__और __setitem__कुछ डिबगिंग आउटपुट का उत्पादन करना है। अभी, मेरे पास है

class DictWatch(dict):
    def __init__(self, *args):
        dict.__init__(self, args)

    def __getitem__(self, key):
        val = dict.__getitem__(self, key)
        log.info("GET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
        return val

    def __setitem__(self, key, val):
        log.info("SET %s['%s'] = %s" % str(dict.get(self, 'name_label')), str(key), str(val)))
        dict.__setitem__(self, key, val)

' name_label'एक कुंजी है जो अंततः सेट हो जाएगी कि मैं आउटपुट की पहचान करने के लिए उपयोग करना चाहता हूं। मैंने तब वर्ग को बदल दिया है जो मैं उपवर्ग के DictWatchबजाय साधन कर रहा हूं dictऔर कॉल को सुपरकंस्ट्रक्टर में बदल दिया। फिर भी कुछ होता नहीं दिख रहा है। मुझे लगा कि मैं चालाक हो रहा हूं, लेकिन मुझे आश्चर्य है कि क्या मुझे एक अलग दिशा में जाना चाहिए।

सहायता के लिए धन्यवाद!


क्या आपने लॉग के बजाय प्रिंट का उपयोग करने की कोशिश की? इसके अलावा, क्या आप बता सकते हैं कि आप लॉग कैसे बनाते / कॉन्फ़िगर करते हैं?
पजटन

2
नहीं dict.__init__लेता है *args?
टॉम रसेल

4
एक डेकोरेटर के लिए एक अच्छे उम्मीदवार की तरह दिखता है।
टॉम रसेल

जवाबों:


39

आप जो कर रहे हैं वह बिल्कुल काम करना चाहिए। मैंने आपकी कक्षा का परीक्षण किया, और आपके लॉग स्टेटमेंट में एक गुम उद्घाटन कोष्ठक से अलग, यह ठीक काम करता है। केवल दो चीजें हैं जिनके बारे में मैं सोच सकता हूं। पहला, क्या आपके लॉग स्टेटमेंट का आउटपुट सही तरीके से सेट है? आपको logging.basicConfig(level=logging.DEBUG)अपनी स्क्रिप्ट के शीर्ष पर रखने की आवश्यकता हो सकती है ।

दूसरा, __getitem__और __setitem__केवल []एक्सेस के दौरान कहा जाता है । इसलिए सुनिश्चित करें कि आप केवल के बजाय के DictWatchमाध्यम d[key]से d.get()और का उपयोग करते हैंd.set()


दरअसल यह एक्स्ट्रा (str(dict.get(self, 'name_label')), str(key), str(val)))
पैरेंस

3
सच। ओपी के लिए: भविष्य के संदर्भ के लिए, आप केवल पायथन स्ट्रिंग प्रारूपण ऑपरेटर के बजाय log.info ('% s% s% s', a, b, c) कर सकते हैं।
ब्रेनकोर

लॉगिंग स्तर मुद्दा बन गया। मैं किसी और के कोड को डिबग कर रहा हूं और मैं मूल रूप से किसी अन्य फ़ाइल में परीक्षण कर रहा हूं जो अलग स्तर के डिबगिंग सेट का प्रमुख है। धन्यवाद!
माइकल मिओर

73

एक और मुद्दा जब सबक्लासिंग dictहोता है, तो अंतर्निहित __init__कॉल नहीं करता है update, और अंतर्निहित updateकॉल नहीं करता है __setitem__। इसलिए, यदि आप चाहते हैं कि सभी सेटिमिटी ऑपरेशंस आपके __setitem__फंक्शन से गुजरें, तो आपको यह सुनिश्चित करना चाहिए कि यह अपने आप हो जाए:

class DictWatch(dict):
    def __init__(self, *args, **kwargs):
        self.update(*args, **kwargs)

    def __getitem__(self, key):
        val = dict.__getitem__(self, key)
        print 'GET', key
        return val

    def __setitem__(self, key, val):
        print 'SET', key, val
        dict.__setitem__(self, key, val)

    def __repr__(self):
        dictrepr = dict.__repr__(self)
        return '%s(%s)' % (type(self).__name__, dictrepr)

    def update(self, *args, **kwargs):
        print 'update', args, kwargs
        for k, v in dict(*args, **kwargs).iteritems():
            self[k] = v

9
आप अजगर 3 का उपयोग कर रहे हैं, तो आप इतना है कि इस उदाहरण को बदलने के लिए चाहता हूँ printहै print()समारोह और update()विधि का उपयोग करता items()बजाय iteritems()
अल स्वेगार्ट

मैंने आपके सोल की कोशिश की है, लेकिन ऐसा लगता है कि यह केवल एक स्तर के अनुक्रमण के
एंड्रयू

d [key1] कुछ देता है, शायद एक शब्दकोश। दूसरा प्रमुख सूचकांक जो। यह तकनीक तब तक काम नहीं कर सकती जब तक कि लौटी हुई चीज घड़ी के व्यवहार का भी समर्थन नहीं करती।
मैट एंडरसन

1
@AndrewNaguib: नेस्टेड सरणियों के साथ काम क्यों करना चाहिए? नेस्टेड सरणी सामान्य अजगर के साथ काम नहीं करती है या तो
तानाशाह

1
@AndrewNaguib: __getitem__परीक्षण valऔर केवल सशर्त रूप से करने की आवश्यकता होगी - यानीif isinstance(val, dict): ...
martineau

14

उपवर्ग UserDictया पर विचार करें UserList। इन कक्षाओं जबकि सामान्य subclassed करने जा करना है dictऔर listनहीं हैं, और अनुकूलन होते हैं।


9
संदर्भ के लिए, पायथन 3.6 में दस्तावेज़ीकरण कहता है, "इस वर्ग की आवश्यकता को आंशिक रूप से सीधे उपवर्ग की क्षमता द्वारा दबाया गया है; हालांकि, इस वर्ग के साथ काम करना आसान हो सकता है क्योंकि अंतर्निहित शब्दकोश एक विशेषता के रूप में सुलभ है"।
सीन

@andrew एक उदाहरण सहायक हो सकता है।
वसंत गणेश के


9

यह वास्तव में परिणाम को नहीं बदलना चाहिए (जो कि अच्छे लॉगिंग थ्रेशोल्ड वैल्यू के लिए काम करना चाहिए): आपका इनिट होना चाहिए:

def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs) 

इसके बजाय, क्योंकि यदि आप अपने तरीके को डिक्टवॉच ([1,2), (2,3)]) या डिक्टवॉच (a = 1, b = 2) के साथ कहते हैं तो यह विफल हो जाएगा।

(या, बेहतर है, इसके लिए एक कंस्ट्रक्टर को परिभाषित न करें)


मैं केवल dict[key]पहुंच के रूप के बारे में चिंतित हूं , इसलिए यह कोई समस्या नहीं है।
बजे माइकल मिओर

1

आपको बस इतना करना होगा

class BatchCollection(dict):
    def __init__(self, inpt={}):
        super(BatchCollection, self).__init__(inpt)

मेरे व्यक्तिगत उपयोग के लिए एक नमूना उपयोग

### EXAMPLE
class BatchCollection(dict):
    def __init__(self, inpt={}):
        super(BatchCollection, self).__init__(inpt)

    def __setitem__(self, key, item):
        if (isinstance(key, tuple) and len(key) == 2
                and isinstance(item, collections.Iterable)):
            # self.__dict__[key] = item
            super(BatchCollection, self).__setitem__(key, item)
        else:
            raise Exception(
                "Valid key should be a tuple (database_name, table_name) "
                "and value should be iterable")

नोट : केवल अजगर 3 में परीक्षण किया गया


0

पट उत्तर को पूरा करने के लिए, यहाँ एक उदाहरण दिया गया है dictऔर UserDict:

यह सही ढंग से अधिलेखित करने के लिए मुश्किल है:

class MyDict(dict):

  def __setitem__(self, key, value):
    super().__setitem__(key, value * 10)


d = MyDict(a=1, b=2)  # Bad! MyDict.__setitem__ not called
d.update(c=3)  # Bad! MyDict.__setitem__ not called
d['d'] = 4  # Good!
print(d)  # {'a': 1, 'b': 2, 'c': 3, 'd': 40}

UserDictसे वारिस collections.abc.MutableMapping, इसलिए अनुकूलित करना बहुत आसान है:

class MyDict(collections.UserDict):

  def __setitem__(self, key, value):
    super().__setitem__(key, value * 10)


d = MyDict(a=1, b=2)  # Good: MyDict.__setitem__ correctly called
d.update(c=3)  # Good: MyDict.__setitem__ correctly called
d['d'] = 4  # Good
print(d)  # {'a': 10, 'b': 20, 'c': 30, 'd': 40}

इसी तरह, आप केवल लागू करना __getitem__स्वचालित रूप से संगत होने के लिए key in my_dict, my_dict.get...

नोट: UserDictएक उपवर्ग नहीं है dict, इसलिए isinstance(UserDict(), dict)विफल होगा (लेकिन isinstance(UserDict(), collections.abc.MutableMapping)काम करेगा)

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