El hasattr de Python en la lista de valores de los diccionarios siempre devuelve falso?

Tengo un diccionario que a veces recibe llamadas para claves no existentes, así que trato de usar hasattr y getattr para manejar estos casos:

 key_string = 'foo' print "current info:", info print hasattr(info, key_string) print getattr(info, key_string, []) if hasattr(info, key_string): array = getattr(info, key_string, []) array.append(integer) info[key_string] = array print "current info:", info 

La primera vez que esto se ejecuta con integer = 1 :

 current info: {} False [] current info: {'foo': [1]} 

Ejecutando este código de nuevo con integer = 2 :

 instance.add_to_info("foo", 2) current info: {'foo': [1]} False [] current info: {'foo': [2]} 

La primera ejecución es claramente exitosa ( {'foo': [1]} ), pero hasattr devuelve false y getattr usa la matriz en blanco predeterminada la segunda vez, ¡perdiendo el valor de 1 en el proceso! ¿Por qué es esto?

hasattr no prueba para miembros de un diccionario. Use el operador in lugar, o el método .has_key :

 >>> example = dict(foo='bar') >>> 'foo' in example True >>> example.has_key('foo') True >>> 'baz' in example False 

Pero tenga en cuenta que dict.has_key() ha quedado en desuso, la guía de estilo PEP 8 lo recomienda y se elimina en Python 3.

Por cierto, se encontrará con problemas al utilizar una variable de clase mutable:

 >>> class example(object): ... foo = dict() ... >>> A = example() >>> B = example() >>> A.foo['bar'] = 'baz' >>> B.foo {'bar': 'baz'} 

__init__ en tu __init__ en su lugar:

 class State(object): info = None def __init__(self): self.info = {} 

Una clave de diccionario no es lo mismo que un atributo de objeto

 thing1 = {'a', 123} hasattr(thing1, 'a') # False class c: pass thing2 = c() thing2.a = 123 hasattr(thing2, 'a') # True 

Para probar los elementos en una lista / diccionario, use in . Para usar los valores predeterminados, puede usar dict.get :

 def add_to_info(self, key_string, integer): array = self.info.get(key_string, []) array.append(integer) self.info[key_string] = array 

O use defaultdict:

 from collections import defaultdict class State(object): info = defaultdict(list) def add_to_info(self, key_string, integer): self.info[key_string].append(integer) 

Parece que todo lo que necesitas es una línea:

 def add_to_info(self, key_string, integer): self.info.setdefault(key_string, []).append(integer) 

Es útil haber definido un getAttr reflexivo que obtiene atributos o claves de un objeto.

 def getAttr(obj, attribute, default=''): # like getattr, but also check the keys of obj, and can return a default, if no key or no attribute was found. # note there's a priority to attribute if both attribute and key exist. result = getattr(obj, attribute) if hasattr(obj, attribute) else None if result is None: result = obj.get(attribute, default) if isinstance(obj, dict) else default return result