2010-03-06 2 views
56

Ich bin etwas Code debuggen und ich möchte herausfinden, wenn ein bestimmtes Wörterbuch zugegriffen wird. Nun, es ist eigentlich eine Klasse der Unterklasse dict und implementiert ein paar zusätzliche Funktionen. Wie auch immer, was ich gerne tun würde, ist die Unterklasse dict selbst und hinzufügen Override __getitem__ und __setitem__, um einige Debugging-Ausgabe zu erzeugen. Gerade jetzt, ich habeWie dict und override richtig abgeleitet werden __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' ein Schlüssel ist, die schließlich eingestellt werden, dass ich verwenden möchte, um die Ausgabe zu identifizieren. Ich habe dann die Klasse, die ich instrumentiere, in die Unterklasse DictWatch anstelle von dict geändert und den Aufruf des Superconstructors geändert. Trotzdem scheint nichts zu passieren. Ich dachte, ich wäre clever, aber ich frage mich, ob ich in eine andere Richtung gehen sollte.

Danke für die Hilfe!

+0

Haben Sie versucht, Drucken statt Protokoll zu verwenden? Könnten Sie auch erklären, wie Sie Ihr Protokoll erstellen/konfigurieren? – pajton

+0

Nimmt 'dict .__ init__' '' args' nicht an? –

+1

Sieht ein bisschen wie ein guter Kandidat für einen Dekorateur aus. –

Antwort

24

Was Sie tun, sollte absolut funktionieren. Ich habe Ihre Klasse getestet, und abgesehen von einer fehlenden öffnenden Klammer in Ihren Log-Anweisungen funktioniert das problemlos. Ich kann nur an zwei Dinge denken. Erstens: Ist die Ausgabe Ihrer Log-Anweisung korrekt eingestellt? Sie müssen möglicherweise eine logging.basicConfig(level=logging.DEBUG) an der Spitze Ihres Skripts setzen.

Zweitens werden __getitem__ und __setitem__ nur während [] Zugriffe aufgerufen. So stellen Sie sicher, dass Sie nur DictWatch über d[key] zugreifen, anstatt d.get() und d.set()

+0

Eigentlich ist es nicht extra parens, aber eine fehlende öffnung paren um '(str (dict.get (self, 'name_label')), str (schlüssel), str (val)))' – cobbal

+3

Wahr. Zum OP: Für zukünftige Referenz können Sie einfach einloggen.info ('% s% s% s', a, b, c) anstelle eines Python-String-Formatierungsoperators. – BrainCore

+0

Ich finde nur die String-Formatierung natürlicher, da ich es in vielen Fällen mache. Was die Klammern betrifft, habe ich mich hier vertippt, weil Python keine Fehler meldet. –

7

Das ist nicht wirklich das Ergebnis ändern sollte (was für eine gute Protokollierung Schwellwerten arbeiten, sollten): Ihre init sollte sein:

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

statt, denn wenn Sie Ihre Methode mit DictWatch ([(1,2), (2,3)]) oder DictWatch (a = 1, b = 2) aufrufen, wird dies fehlschlagen.

(oder, besser, nicht definieren einen Konstruktor für diese)

+0

Ich mache mir nur Sorgen wegen der 'dict [key]' Form des Zugriffs, das ist also kein Problem. –

54

Ein weiteres Problem bei der dict Subklassen ist, dass die eingebaute in __init__ nicht update nicht nennen, und die eingebaute in update nicht nennen __setitem__. Also, wenn Sie alle SetItem Operationen durch Ihre __setitem__ Funktion gehen wollen, sollten Sie sicherstellen, dass es selbst aufgerufen wird:

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 
+0

Wenn Sie Python 3 verwenden, sollten Sie dieses Beispiel so ändern, dass 'print' die' print() '-Funktion ist und die' update() '-Methode' items() 'anstelle von' iteritems() 'verwendet . –

0

Alle müssen Sie tun, ist

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

Eine Probe Nutzung für mein persönlicher Gebrauch

### 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") 

Hinweis: nur in python3 getestet

Verwandte Themen