class - tools - python ide mac
¿Crear propiedades de instancia de clase de un diccionario? (6)
Podría hacer una subclase de dict
que permita la búsqueda de atributos para las claves:
class AttributeDict(dict):
def __getattr__(self, name):
return self[name]
q = AttributeDict({ ''Field1'' : 3000, ''Field2'' : 6000, ''RandomField'' : 5000 })
print q.Field1
print q.Field2
print q.RandomField
Si intentas buscar un atributo que ya tiene dict
(digamos keys
o get
), obtendrás ese atributo de clase dict
(un método). Si la clave solicitada no existe en la clase dict
, se __getattr__
método __getattr__
y se realizará la búsqueda de claves.
Importación desde un archivo CSV y obtengo datos aproximadamente en el formato
{ ''Field1'' : 3000, ''Field2'' : 6000, ''RandomField'' : 5000 }
Los nombres de los campos son dinámicos. (Bueno, son dinámicos porque puede haber más de Field1 y Field2, pero sé que Field1
y Field2
siempre estarán allí.
Me gustaría poder pasar este diccionario a mi clase allMyFields
para que pueda acceder a los datos anteriores como propiedades.
class allMyFields:
# I think I need to include these to allow hinting in Komodo. I think.
self.Field1 = None
self.Field2 = None
def __init__(self,dictionary):
for k,v in dictionary.items():
self.k = v
#of course, this doesn''t work. I''ve ended up doing this instead
#self.data[k] = v
#but it''s not the way I want to access the data.
q = { ''Field1'' : 3000, ''Field2'' : 6000, ''RandomField'' : 5000 }
instance = allMyFields(q)
# Ideally I could do this.
print q.Field1
¿Alguna sugerencia? En cuanto a por qué, me gustaría poder aprovechar la sugerencia del código e importar los datos en un diccionario llamado data
tal como he estado haciendo, no me permite nada de eso.
(Dado que los nombres de las variables no se resuelven hasta el tiempo de ejecución, todavía tendré que arrojarle un hueso a Komodo, creo que el self.Field1 = None
debería ser suficiente).
Entonces, ¿cómo hago lo que quiero? ¿O estoy ladrando a un árbol mal diseñado, no python?
Puedes usar setattr
(ten cuidado: no todas las cadenas son un nombre de atributo válido):
>>> class AllMyFields:
... def __init__(self, dictionary):
... for k, v in dictionary.items():
... setattr(self, k, v)
...
>>> o = AllMyFields({''a'': 1, ''b'': 2})
>>> o.a
1
Editar: déjame explicarte la diferencia entre el código anterior y la respuesta de SilentGhost . El fragmento de código anterior crea una clase de los atributos de instancia que se basan en un diccionario determinado. El código de SilentGhost crea una clase cuyos atributos de clase se basan en un diccionario determinado.
Dependiendo de su situación específica, cualquiera de estas soluciones puede ser más adecuada. ¿Crees que puedes crear una o más instancias de clase? Si la respuesta es una, también puedes omitir la creación de objetos por completo y solo construir el tipo (y así ir con la respuesta de SilentGhost).
También puede usar dict.update
lugar de hacer un bucle manual sobre los items
(y si está iteritems
, iteritems
es mejor).
class allMyFields(object):
# note: you cannot (and don''t have to) use self here
Field1 = None
Field2 = None
def __init__(self, dictionary):
self.__dict__.update(dictionary)
q = { ''Field1'' : 3000, ''Field2'' : 6000, ''RandomField'' : 5000 }
instance = allMyFields(q)
print instance.Field1 # => 3000
print instance.Field2 # => 6000
print instance.RandomField # => 5000
Usa setattr para la forma bonita. La forma rápida y sucia es actualizar el diccionario interno de la instancia:
>>> class A(object):
... pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
Usando tuplas con nombre (Python 2.6):
>>> from collections import namedtuple
>>> the_dict = {''Field1'': 3, ''Field2'': ''b'', ''foo'': 4.9}
>>> fields = '' ''.join(the_dict.keys())
>>> AllMyFields = namedtuple(''AllMyFields'', fields)
>>> instance = AllMyFields(**the_dict)
>>> print instance.Field1, instance.Field2, instance.foo
3 b 4.9
>>> q = { ''Field1'' : 3000, ''Field2'' : 6000, ''RandomField'' : 5000 }
>>> q = type(''allMyFields'', (object,), q)
>>> q.Field1
3000
los documentos para type
explican bien lo que está sucediendo aquí (ver uso como constructor).
editar : en caso de que necesite variables de instancia, lo siguiente también funciona:
>>> a = q() # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1 # second instance
3000