2010-06-13 14 views
6

Varias veces (incluso varias seguidas) Me ha picado el error de defaultdict: olvidar que algo es en realidad un default y tratarlo como un diccionario normal.¿Cómo puedo hacer que un fallo predeterminado sea seguro para los clientes no habituales?

d = defaultdict(list) 

... 

try: 
    v = d["key"] 
except KeyError: 
    print "Sorry, no dice!" 

Para aquellos que han sido mordidos también, el problema es evidente: cuando d no tiene 'clave' clave, el v = d["key"] crea mágicamente una lista vacía y lo asigna a ambos d["key"] y v en lugar de lanzar una excepción. Lo cual puede ser bastante difícil de rastrear si d viene de algún módulo cuyos detalles uno no recuerda muy bien.

Estoy buscando una manera de quitarle el aguijón a este error. Para mí, la mejor solución sería deshabilitar de algún modo la magia de un defecto predeterminado antes de devolverlo al cliente.

Respuesta

5

Puede evitar la creación de valores por defecto mediante la asignación de d.default_factory = None. Sin embargo, no me gusta la idea de que el objeto cambie repentinamente el comportamiento. Preferiría copiar valores al nuevo dict a menos que imponga una penalización severa de rendimiento.

+0

Muchas gracias por ponerme en el camino correcto con esto. No tengo ningún problema particular con el cambio del comportamiento de este tipo de objeto porque creo que es mucho mejor comprobar si un objeto admite un protocolo en particular que verificar su tipo. En este caso, simplemente cheching si es compatible con el protocolo de mapeo es mucho mejor que verificar a la defensiva si un diccionario podría ser un default y cambiar el comportamiento del cliente en consecuencia. – user354193

+0

¿Qué quiere decir con "no me gusta la idea de un objeto que cambia repentinamente de comportamiento"? Si digo 'd = dict (d)' en vez de 'd.default_factory = None', a menos que pase la referencia a la antigua 'd' es funcionalmente equivalente y no fuerza la creación de un nuevo diccionario. Mientras el código subsiguiente no intente restaurar la fábrica (suena loco) es un pato. –

7

utilización idioma diferente:

if 'key' not in d: 
    print "Sorry, no dice!" 
+0

eso es pedir permiso, sin embargo. – badp

+0

@bp: entonces, ¿qué? – SilentGhost

+0

+1 Creo que probar con 'in' es un estilo mucho mejor que' excepto KeyError', no solo para los valores predeterminados. –

14

Usted todavía puede convertirlo en un dict normal.

d = collections.defaultdict(list) 
d = dict(d) 
2

Ese es exactamente el comportamiento que desea de defaultdict y no error. Si no lo quieres, no uses un default.

Si sigue olvidando qué tipo de variables tienen, entonces nómbrelas apropiadamente, por ejemplo, sufija sus nombres de default con "_ddict". idea

+0

Tenía la esperanza de poder olvidarme de este giro húngaro usando Python :-) Prefiero ponerle nombre a un pato potencial si grazna a propagar un cambio de nombre a un montón de código si decido en un momento convertirlo en un estante por ejemplo ... – user354193

1

El uso de rkhayrov de restablecer self.default_factory, aquí hay una subclase conmutable de defaultdict:

class ToggleableDefaultdict(collections.defaultdict): 
    def __init__(self,default_factory): 
     self._default_factory=default_factory 
     super(ToggleableDefaultdict,self).__init__(default_factory) 
    def off(self): 
     self.default_factory=None 
    def on(self): 
     self.default_factory=self._default_factory 

Por ejemplo:

d=ToggleableDefaultdict(list) 
d['key'].append(1) 
print(d) 
# defaultdict(<type 'list'>, {'key': [1]}) 

d.off() 
d['newkey'].append(2) 
# KeyError: 'newkey' 

d.on() 
d['newkey'].append(2) 
# defaultdict(<type 'list'>, {'newkey': [2], 'key': [1]}) 
Cuestiones relacionadas