在 python 中设置 dictionary 的属性

有没有可能从 python 中的 dictionary 创建一个对象,使得每个键都是该对象的一个属性?

就像这样:

 d = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }


e = Employee(d)
print e.name # Oscar
print e.age + 10 # 42

我认为这和这个问题的答案正好相反: 来自对象字段的 Python 字典

120878 次浏览

当然,就像这样:

class Employee(object):
def __init__(self, initial_data):
for key in initial_data:
setattr(self, key, initial_data[key])

更新

正如 Brent Nash 建议的那样,你可以通过允许关键字参数来使这个过程更加灵活:

class Employee(object):
def __init__(self, *initial_data, **kwargs):
for dictionary in initial_data:
for key in dictionary:
setattr(self, key, dictionary[key])
for key in kwargs:
setattr(self, key, kwargs[key])

然后你可以这样称呼它:

e = Employee({"name": "abc", "age": 32})

或者像这样:

e = Employee(name="abc", age=32)

甚至像这样:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)

您可以使用 __dict__访问对象的属性,并在其上调用 update 方法:

>>> class Employee(object):
...     def __init__(self, _dict):
...         self.__dict__.update(_dict)
...




>>> dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }


>>> e = Employee(dict)


>>> e.name
'Oscar'


>>> e.age
32

我认为,如果你真的需要支持 dict,那么使用 settattr来回答这个问题是可行的。

但是如果 Employee对象只是一个结构,您可以使用点语法(.name)而不是 dict 语法(['name'])来访问它,那么您可以像下面这样使用 命名元组:

from collections import namedtuple


Employee = namedtuple('Employee', 'name age')
e = Employee('noname01', 6)
print e
#>> Employee(name='noname01', age=6)


# create Employee from dictionary
d = {'name': 'noname02', 'age': 7}
e = Employee(**d)
print e
#>> Employee(name='noname02', age=7)
print e._asdict()
#>> {'age': 7, 'name': 'noname02'}

您确实有 _asdict()方法以字典的形式访问所有属性,但是 不能以后只在构造过程中添加其他属性。

以这种方式设置属性几乎肯定不是解决问题的最佳方法:

  1. 你知道所有领域都应该提前做好准备。在这种情况下,可以显式地设置所有属性。这看起来像是

    class Employee(object):
    def __init__(self, name, last_name, age):
    self.name = name
    self.last_name = last_name
    self.age = age
    
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(**d)
    
    
    print e.name # Oscar
    print e.age + 10 # 42
    

    或者

  2. 你不知道所有的领域应该提前。在这种情况下,应该将数据存储为 dict,而不是污染对象名称空间。属性用于静态访问。这个案子看起来

    class Employee(object):
    def __init__(self, data):
    self.data = data
    
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(d)
    
    
    print e.data['name'] # Oscar
    print e.data['age'] + 10 # 42
    

Another solution that is basically equivalent to case 1 is to use a collections.namedtuple. See van's answer for how to implement that.

为什么不直接使用属性名作为字典的键呢?

class StructMyDict(dict):


def __getattr__(self, name):
try:
return self[name]
except KeyError as e:
raise AttributeError(e)


def __setattr__(self, name, value):
self[name] = value

可以使用命名参数、元组列表、字典或 个人属性赋值,例如:

nautical = StructMyDict(left = "Port", right = "Starboard") # named args


nautical2 = StructMyDict({"left":"Port","right":"Starboard"}) # dictionary


nautical3 = StructMyDict([("left","Port"),("right","Starboard")]) # tuples list


nautical4 = StructMyDict()  # fields TBD
nautical4.left = "Port"
nautical4.right = "Starboard"


for x in [nautical, nautical2, nautical3, nautical4]:
print "%s <--> %s" % (x.left,x.right)

或者,可以不引发属性错误,而是为未知值返回 Nothing。(web2py 存储类中使用的一个技巧)

就像使用 dict 一样,你可以像这样使用 kwargs:

class Person:
def __init__(self, **kwargs):
self.properties = kwargs


def get_property(self, key):
return self.properties.get(key, None)


def main():
timmy = Person(color = 'red')
print(timmy.get_property('color')) #prints 'red'

比如说

class A():
def __init__(self):
self.x=7
self.y=8
self.z="name"

如果您希望立即设置属性

d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)

如果你不介意使用图书馆的话:

pip install domonic

然后你可以做:

from domonic.javascript import Object


class Employee(Object):
pass


d = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }


e = Employee(d)
print(e.name)
print(e['name'])
print(e)


# {'name': 'Oscar', 'lastName': 'Reyes', 'age': 32}


它应该按要求行事。