Criando propriedades de instância de classe a partir de um dicionário?
Pergunta
Eu estou importando de um arquivo CSV e obtenção de dados mais ou menos no formato
{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
Os nomes dos campos são dinâmicos. (Bem, eles são dinâmicos em que pode haver mais de Field1 e Field2, mas sei Field1
e Field2
são sempre vai estar lá.
Eu gostaria de ser capaz de passar neste dicionário em meu allMyFields
classe para que eu possa acessar os dados acima como propriedades.
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
Todas as sugestões? Tanto quanto isso -. Eu gostaria de ser capaz de tirar proveito de dicas de código, e importar os dados em um dicionário chamado data
como tenho vindo a fazer não me pagar nada disso
(Uma vez que os nomes de variáveis ??não são resolvidos até tempo de execução, estou ainda vai ter que jogar um osso para Komodo -. Eu acho que o self.Field1 = None
deve ser suficiente)
Assim - como eu faço o que eu quero? Ou eu sou latindo um mal projetado árvore, não-python?
Solução
Você pode usar setattr
(ter cuidado, porém: não cada corda é um nome 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: deixe-me explicar a diferença entre o código acima e o SilentGhost resposta . O trecho de código acima cria uma classe de que atributos da instância são baseados em um determinado dicionário. código de SilentGhost cria uma classe cujos atributos class são baseados em um determinado dicionário.
Dependendo da sua situação específica qualquer uma destas soluções pode ser mais adequada. Você simples para criar uma ou mais instâncias de classe? Se a resposta é uma só, assim como você pode ignorar a criação de objeto inteiramente e só construir o tipo (e, portanto, ir com a resposta de SilentGhost).
Outras dicas
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000
docs para type
explicar bem o que está acontecendo aqui (veja o uso como um construtor ).
editar : caso você precisa variáveis ??de instância, o também seguintes obras:
>>> a = q() # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1 # second instance
3000
Você também pode usar dict.update
em vez de loop manualmente sobre items
(e se você estiver looping, iteritems
é melhor).
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
Usando tuplas nomeadas (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
Você poderia fazer uma subclasse de dict
que permite acessar atributos para as chaves:
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
Se você tentar olhar para cima um atributo que dict
já tem (keys
dizer ou get
), você vai ter que atributo de classe dict
(um método). Se a chave que você pedir para não existe na classe dict
, então o método __getattr__
será chamado e vai fazer sua pesquisa de chave.
Use setattr pela maneira bonita. A maneira rápida-n-sujo é atualizar o dicionário interno exemplo:
>>> class A(object):
... pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
class SomeClass:
def __init__(self,
property1,
property2):
self.property1 = property1
self.property2 = property2
property_dict = {'property1': 'value1',
'property2': 'value2'}
sc = SomeClass(**property_dict)
print(sc.__dict__)
Ou você pode tentar este
class AllMyFields:
def __init__(self, field1, field2, random_field):
self.field1 = field1
self.field2 = field2
self.random_field = random_field
@classmethod
def get_instance(cls, d: dict):
return cls(**d)
a = AllMyFields.get_instance({'field1': 3000, 'field2': 6000, 'random_field': 5000})
print(a.field1)