Ich debugge Code und möchte herausfinden, wann auf ein bestimmtes Wörterbuch zugegriffen wird. Nun, es ist eigentlich eine Klasse, die eine Unterklasse bildet dict
und einige zusätzliche Funktionen implementiert. Was ich jedenfalls tun möchte, ist, dict
mich selbst zu unterordnen und Override hinzuzufügen __getitem__
und __setitem__
eine Debugging-Ausgabe zu erzeugen. Gerade habe ich
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'
ist ein Schlüssel, der irgendwann gesetzt wird, mit dem ich die Ausgabe identifizieren möchte. Ich habe dann die Klasse, die ich instrumentiere, in Unterklasse DictWatch
anstatt dict
geändert und den Aufruf an den Superkonstruktor geändert. Trotzdem scheint nichts zu passieren. Ich dachte, ich wäre schlau, aber ich frage mich, ob ich eine andere Richtung einschlagen sollte.
Danke für die Hilfe!
quelle
dict.__init__
nehmen*args
?Antworten:
Was Sie tun, sollte unbedingt funktionieren. Ich habe Ihre Klasse getestet und abgesehen von einer fehlenden öffnenden Klammer in Ihren Protokollanweisungen funktioniert es einwandfrei. Ich kann mir nur zwei Dinge vorstellen. Ist die Ausgabe Ihrer Protokollanweisung korrekt eingestellt? Möglicherweise müssen Sie ein
logging.basicConfig(level=logging.DEBUG)
oben in Ihr Skript einfügen.Zweitens
__getitem__
und__setitem__
werden nur während der[]
Zugriffe aufgerufen . Stellen Sie also sicher, dass Sie nurDictWatch
überd[key]
und nicht überd.get()
und zugreifend.set()
quelle
(str(dict.get(self, 'name_label')), str(key), str(val)))
Ein weiteres Problem bei der Unterklasse
dict
besteht darin, dass das integrierte__init__
Gerät nicht aufruftupdate
und das integrierteupdate
Gerät nicht aufruft__setitem__
. Wenn Sie also möchten, dass alle Setitem-Operationen Ihre__setitem__
Funktion durchlaufen , sollten Sie sicherstellen, dass sie selbst aufgerufen werden: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
quelle
print
dieprint()
Funktion und dieupdate()
Methodeitems()
anstelle von verwendet werdeniteritems()
.__getitem__
müsste testenval
und nur bedingt tun - dhif isinstance(val, dict): ...
Betrachten Sie Unterklassen
UserDict
oderUserList
. Diese Klassen sollen in Unterklassen unterteilt werden, während die normalendict
undlist
nicht, und Optimierungen enthalten.quelle
Das sollte das Ergebnis nicht wirklich ändern (was für gute Protokollierungsschwellenwerte funktionieren sollte): Ihr Init sollte sein:
def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs)
Stattdessen schlägt dies fehl, wenn Sie Ihre Methode mit DictWatch ([(1,2), (2,3)]) oder DictWatch (a = 1, b = 2) aufrufen.
(oder besser, definieren Sie keinen Konstruktor dafür)
quelle
dict[key]
Form des Zugriffs, daher ist dies kein Problem.Alles was Sie tun müssen, ist
class BatchCollection(dict): def __init__(self, inpt={}): super(BatchCollection, self).__init__(inpt)
Ein Beispiel für die Verwendung für meinen persönlichen 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
quelle
Um die Antwort von Andrew Pate zu vervollständigen, ist hier ein Beispiel, das einen Unterschied zwischen
dict
und zeigtUserDict
:Es ist schwierig, das Diktat richtig zu überschreiben:
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
erben voncollections.abc.MutableMapping
, ist also viel einfacher anzupassen: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}
Ebenso müssen Sie nur implementieren,
__getitem__
um automatisch mit ,, ... kompatibel zu seinkey in my_dict
.my_dict.get
Hinweis:
UserDict
ist keine Unterklasse vondict
,isinstance(UserDict(), dict)
wird also fehlschlagen (wird aberisinstance(UserDict(), collections.abc.MutableMapping)
funktionieren)quelle