2010-03-06 14 views
56

Estoy depurando algún código y quiero saber cuándo se accede a un diccionario en particular. Bueno, en realidad es una clase que subclase dict e implementa un par de características adicionales. De todos modos, lo que me gustaría hacer es crear la subclase dict y agregar el reemplazo __getitem__ y __setitem__ para producir algún resultado de depuración. En este momento, no tengoCómo subclasificar adecuadamente el dictado y anular __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' es una clave que eventualmente pueden establecer que quiero usar para identificar la salida. Luego cambié la clase que estoy instrumentando a la subclase DictWatch en lugar de dict y cambié la llamada al superconstructor. Aún así, nada parece estar sucediendo. Pensé que estaba siendo inteligente, pero me pregunto si debería ir en otra dirección.

¡Gracias por la ayuda!

+0

¿Intentó utilizar imprimir en lugar de registrar? Además, ¿podría explicar cómo se crea/configura el registro? – pajton

+0

¿No 'dict .__ init__' toma' * args'? –

+1

Parece un poco como un buen candidato para un decorador. –

Respuesta

24

Lo que estás haciendo debería funcionar. Probé tu clase, y aparte de un paréntesis de apertura faltante en tus instrucciones de registro, funciona bien. Solo hay dos cosas en las que puedo pensar. Primero, ¿el resultado de su declaración de registro está configurado correctamente? Es posible que deba colocar un logging.basicConfig(level=logging.DEBUG) en la parte superior de la secuencia de comandos.

En segundo lugar, __getitem__ y __setitem__ solo se llaman durante los accesos []. Así que asegúrese de que sólo accede a DictWatch través d[key], en lugar de d.get() y d.set()

+0

En realidad no son paréntesis adicionales, sino una paren de apertura faltante alrededor de '(str (dict.get (self, 'name_label')), str (clave), str (val)))' – cobbal

+3

True. Para el OP: para referencia futura, simplemente puede hacer log.información ('% s% s% s', a, b, c), en lugar de un operador de formato de cadenas Python. – BrainCore

+0

Acabo de encontrar el formato de cadena más natural ya que lo hago en muchos casos. En cuanto al paréntesis, escribí mal aquí, porque Python no se queja de ningún error. –

7

que en realidad no debería cambiar el resultado (que debe trabajar, para obtener buenos valores de umbral de registro): su init debe ser:

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

en su lugar, porque si llama a su método con DictWatch ([(1,2), (2,3)]) o DictWatch (a = 1, b = 2), esto fallará.

(o, mejor, no se define un constructor para esta)

+0

Solo me preocupa la forma de acceso 'dict [key]', así que esto no es un problema. –

54

Otro problema cuando la subclasificación dict es que la incorporada en __init__ no llama update y la incorporada en update no llama __setitem__. Por lo tanto, si desea que todas las operaciones SetItem que ir a través de su función de __setitem__, usted debe asegurarse de que se llama a sí 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 
+0

Si está usando Python 3, querrá cambiar este ejemplo para que 'print' sea la función' print() 'y el método' update() 'use' items() 'en lugar de' iteritems() ' . –

0

Todo lo que tendrá que hacer es

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

Un ejemplos de uso de 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 sólo en python3

Cuestiones relacionadas