Создание свойств экземпляра класса из словаря? - PullRequest
52 голосов
/ 28 октября 2009

Я импортирую из 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'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

Есть предложения? Что касается того, почему - я хотел бы иметь возможность воспользоваться подсказками кода, а импорт данных в словарь под названием data, как я делал, не позволяет мне ничего из этого.

(Поскольку имена переменных не разрешаются до времени выполнения, мне все равно придется бросить кость Комодо - думаю, self.Field1 = None должно быть достаточно.)

Итак - как мне делать то, что я хочу? Или я лаю плохо спроектированное, не питонское дерево?

Ответы [ 8 ]

87 голосов
/ 28 октября 2009

Вы можете использовать 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 . Приведенный выше фрагмент кода создает класс, в котором атрибуты экземпляра основаны на данном словаре. Код SilentGhost создает класс, чьи атрибуты класса основаны на данном словаре.

В зависимости от вашей конкретной ситуации любое из этих решений может быть более подходящим. Вы можете создать один или несколько экземпляров класса? Если ответ один, вы можете также полностью пропустить создание объекта и создать только тип (и, следовательно, использовать ответ SilentGhost).

30 голосов
/ 28 октября 2009
>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000

документы для type хорошо объясняют, что здесь происходит (см. Использование в качестве конструктора).

edit : если вам нужны переменные экземпляра, также работает следующее:

>>> a = q()             # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1           # second instance
3000
9 голосов
/ 28 октября 2009

Вы также можете использовать 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 голосов
/ 28 октября 2009

Использование именованных кортежей (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
3 голосов
/ 28 октября 2009

Вы можете создать подкласс 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__, который выполнит поиск ключа.

2 голосов
/ 28 октября 2009

Используйте setattr для красивого способа. Быстрый способ - обновить внутренний словарь экземпляра:

>>> class A(object):
...    pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
0 голосов
/ 20 мая 2019

Или вы можете попробовать это

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)
0 голосов
/ 26 ноября 2018
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__)
...