Estoy depurando un código y quiero saber cuándo se accede a un diccionario en particular. Bueno, en realidad es una clase que es una subclase dict
e implementa un par de características adicionales. De todos modos, lo que me gustaría hacer es subclasificarme dict
y agregar override __getitem__
y __setitem__
producir una salida de depuración. Ahora mismo, tengo
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'
es una clave que eventualmente se establecerá y que quiero usar para identificar la salida. Luego cambié la clase que estoy instrumentando a subclase en DictWatch
lugar de dict
y cambié la llamada al superconstructor. Aún así, parece que no pasa nada. Pensé que estaba siendo inteligente, pero me pregunto si debería ir en una dirección diferente.
¡Gracias por la ayuda!
python
dictionary
Michael Mior
fuente
fuente
dict.__init__
toma*args
?Respuestas:
Lo que estás haciendo debería funcionar absolutamente. Probé tu clase y, aparte de un paréntesis de apertura que falta en tus declaraciones de registro, funciona bien. Solo puedo pensar en dos cosas. Primero, ¿la salida de su declaración de registro está configurada correctamente? Es posible que deba poner un
logging.basicConfig(level=logging.DEBUG)
al principio de su secuencia de comandos.En segundo lugar,
__getitem__
y__setitem__
solo se llaman durante los[]
accesos. Así que asegúrese de acceder solo aDictWatch
través ded[key]
, en lugar ded.get()
yd.set()
fuente
(str(dict.get(self, 'name_label')), str(key), str(val)))
Otro problema al crear subclases
dict
es que el integrado__init__
no llamaupdate
y el integradoupdate
no llama__setitem__
. Por lo tanto, si desea que todas las operaciones de setitem pasen por su__setitem__
función, debe asegurarse de que se llame usted mismo: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
fuente
print
sea laprint()
función y elupdate()
método use enitems()
lugar deiteritems()
.__getitem__
necesitaría probarval
y solo hacerlo condicionalmente, es decirif isinstance(val, dict): ...
Considere la posibilidad de subclasificar
UserDict
oUserList
. Estas clases están diseñadas para ser subclasificadas mientras que las normalesdict
ylist
no lo son, y contienen optimizaciones.fuente
Eso realmente no debería cambiar el resultado (que debería funcionar, para buenos valores de umbral de registro): su init debería ser:
def __init__(self,*args,**kwargs) : dict.__init__(self,*args,**kwargs)
en cambio, porque si llama a su método con DictWatch ([(1,2), (2,3)]) o DictWatch (a = 1, b = 2), esto fallará.
(o, mejor, no defina un constructor para esto)
fuente
dict[key]
forma de acceso, por lo que esto no es un problema.Todo lo que tendrás que hacer es
class BatchCollection(dict): def __init__(self, inpt={}): super(BatchCollection, self).__init__(inpt)
Un uso de muestra para mi uso personal
### 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")
Nota : probado solo en python3
fuente
Para completar la respuesta de andrew pate, aquí hay un ejemplo que muestra una diferencia entre
dict
yUserDict
:Es complicado sobrescribir correctamente dict:
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
heredarcollections.abc.MutableMapping
, por lo que es mucho más fácil de personalizar: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}
Del mismo modo, es suficiente con aplicar
__getitem__
para ser compatible con automáticamentekey in my_dict
,my_dict.get
...Nota:
UserDict
no es una subclase dedict
, porisinstance(UserDict(), dict)
lo que fallará (peroisinstance(UserDict(), collections.abc.MutableMapping)
funcionará)fuente