Создание свойств экземпляра класса из словаря?
Я импортирую из CSV и получаю данные примерно в формате
{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
Имена полей являются динамическими. (Ну, они динамичны в том, что может быть больше Field1 и Field2, но я знаю, что Field1
и Field2
всегда будут там.
Я бы хотел пропустить этот словарь в моем классе allMyFields
, чтобы я мог обращаться к вышеуказанным данным как к свойствам.
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 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
Любые предложения? Что касается причин - я хотел бы иметь возможность воспользоваться подсказкой кода и импортировать данные в словарь под названием data
, как я это делал, не дает мне ничего такого.
(Поскольку имена переменных не разрешены до времени выполнения, мне все равно придется бросать кость в Комодо - я думаю, что self.Field1 = None
должно быть достаточно.)
Итак - как мне сделать то, что я хочу? Или я лаяю плохо спроектированное дерево без питона?
Ответы
Ответ 1
Вы можете использовать setattr
(будьте осторожны: не каждая строка является допустимым именем атрибута!):
>>> 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
Изменить: позвольте мне объяснить разницу между приведенным выше кодом и SilentGhost answer. Вышеприведенный фрагмент кода создает класс атрибутов экземпляра на основе данного словаря. Код SilentGhost создает класс, атрибуты класса которого основаны на данном словаре.
В зависимости от конкретной ситуации любое из этих решений может быть более подходящим. Вы просто создаете один или несколько экземпляров класса? Если ответ один, вы можете полностью пропустить создание объекта и только построить его тип (и, следовательно, пойти с ответом SilentGhost).
Ответ 2
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000
docs для type
хорошо объясняют, что происходит здесь (см. использование в качестве конструктора).
edit: в случае, если вам нужны переменные экземпляра, также работает следующее:
>>> a = q() # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1 # second instance
3000
Ответ 3
Вы также можете использовать dict.update
вместо ручного циклирования по items
(и если вы выполняете цикл, iteritems
лучше).
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
Ответ 4
Использование именованных кортежей (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
Ответ 5
Вы можете создать подкласс dict
, который позволяет искать атрибуты для ключей:
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
Если вы попытаетесь найти атрибут, который dict
уже имеет (скажем keys
или get
), вы получите атрибут класса dict
(метод). Если запрашиваемый ключ не существует в классе dict
, тогда метод __getattr__
будет вызван и будет выполнять поиск по ключевым словам.
Ответ 6
Используйте setattr для красивого пути. Быстрый n-грязный способ - обновить внутренний словарь экземпляра:
>>> class A(object):
... pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
Ответ 7
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__)
Ответ 8
Или вы можете попробовать это
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)
Ответ 9
улучшен подкласс dict
повторение dict работает!
class AttributeDict(dict):
"""/info/149123/creating-class-instance-properties-from-a-dictionary/871747#871747"""
def __getattr__(self, name):
return self[name] if not isinstance(self[name], dict) \
else AttributeDict(self[name])
if __name__ == '__main__':
d = {"hello": 1, "world": 2, "cat": {"dog": 5}}
d = AttributeDict(d)
print(d.cat)
print(d.cat.dog)
print(d.cat.items())
"""
{'dog': 5}
5
dict_items([('dog', 5)])
"""