从字典创建类实例属性?

Riz*_*sim 55 python class komodo

我正在从CSV导入并大致以格式获取数据

{ 'Field1' : 3000, 'Field2' : 6000, 'RandomField' : 5000 }
Run Code Online (Sandbox Code Playgroud)

字段的名称是动态的.(好吧,他们很有活力,因为可能会有超过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
Run Code Online (Sandbox Code Playgroud)

有什么建议?至于为什么 - 我希望能够利用代码提示,并将数据导入到一个名为data"我一直在做的字典"的字典中并不能为我提供任何帮助.

(由于变量名称直到运行时才被解析,我仍然需要向Komodo扔骨头 - 我认为self.Field1 = None应该足够了.)

那么 - 我该怎么做我想要的?还是我咆哮着一棵设计糟糕的非蟒蛇树?

Ste*_*202 92

您可以使用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
Run Code Online (Sandbox Code Playgroud)

编辑:让我解释一下上面代码和SilentGhost的答案之间的区别.上面的代码片段创建了一个类,其实例属性基于给定的字典.SilentGhost的代码创建一个类,其类属性基于给定的字典.

根据您的具体情况,这些解决方案中的任何一种都可能更合适.你明白要创建一个或多个类实例吗?如果答案是1,你也可以完全跳过对象创建,只构造类型(因此请使用SilentGhost的答案).

  • 带有奖励编辑的代码解释了两个好答案之间的差异,真的很有帮助,谢谢! (2认同)

Sil*_*ost 32

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

文档type解释了这里发生了什么(请参阅用作构造函数).

编辑:如果您需要实例变量,以下也适用:

>>> a = q()             # first instance
>>> a.Field1
3000
>>> a.Field1 = 1
>>> a.Field1
1
>>> q().Field1           # second instance
3000
Run Code Online (Sandbox Code Playgroud)

  • 好吧我猜他的名字*是*"SilentGhost" (6认同)
  • +1,但我认为你应该向OP解释这段代码的作用和/或提供文档的链接. (4认同)

Cat*_*lus 9

您也可以使用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
Run Code Online (Sandbox Code Playgroud)


tru*_*ppo 6

使用 setattr 来实现漂亮的方式。快速而肮脏的方法是更新实例内部字典:

>>> class A(object):
...    pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
Run Code Online (Sandbox Code Playgroud)


Mat*_*son 6

您可以创建一个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
Run Code Online (Sandbox Code Playgroud)

如果您尝试查找dict已经具有(例如keysget)的属性,您将获得dict该类属性(一个方法)。如果您要求的密钥在dict类中不存在,则该__getattr__方法将被调用并执行您的密钥查找。


Rap*_*rre 5

使用命名元组(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
Run Code Online (Sandbox Code Playgroud)