82

我正在从 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应该足够了。)

那么 - 我该如何做我想做的事?还是我在咆哮一棵设计不佳的非蟒蛇树?

4

10 回答 10

131

您可以使用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 的答案)。

于 2009-10-28T18:31:01.150 回答
40
>>> 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
于 2009-10-28T18:32:56.587 回答
14

您也可以使用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
于 2009-10-28T18:37:28.187 回答
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

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

于 2009-10-28T19:46:35.613 回答
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
于 2009-10-28T19:05:09.940 回答
3

以漂亮的方式使用 setattr。quick-n-dirty 方法是更新实例内部字典:

>>> class A(object):
...    pass
...
>>> a = A()
>>> a.__dict__.update({"foo": 1, "bar": 2})
>>> a.foo
1
>>> a.bar
2
>>>
于 2009-10-28T18:37:31.760 回答
3
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__)
于 2018-11-26T11:51:45.027 回答
1

或者你可以试试这个

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)
于 2019-05-20T20:24:22.110 回答
1

dict子类的增强

重复字典有效!

class AttributeDict(dict):
    """https://stackoverflow.com/a/1639632/6494418"""

    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)])
    """
于 2019-07-25T18:34:36.193 回答
1

如果您愿意添加新库,那么 pydantic 是一个非常有效的解决方案。它使用python注解来构造对象并验证类型考虑以下代码:

from pydantic import BaseModel

class Person(BaseModel):
    name: str
    age: str


data = {"name": "ahmed", "age": 36}

p = Person(**data)

pydantic:https ://pydantic-docs.helpmanual.io/

于 2020-07-16T20:45:14.513 回答