Создание свойств экземпляра класса из словаря?

StackOverflow https://stackoverflow.com/questions/1639174

  •  08-07-2019
  •  | 
  •  

Вопрос

Я импортирую из 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 то, чем я занимался до сих пор, не позволяет мне ничего из этого.

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

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

Это было полезно?

Решение

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

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

Другие советы

>>> q = { 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
>>> q = type('allMyFields', (object,), q)
>>> q.Field1
3000

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

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

>>> a = q()             # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1           # second instance
3000

Вы также можете использовать 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

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

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

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

>>> 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__)

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

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)
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top