在python中设置字典中的属性

Osc*_*Ryz 89 python attributes dictionary initialization properties

是否可以在python中从字典创建一个对象,使每个键都是该对象的属性?

像这样的东西:

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

 e = Employee(d) 
 print e.name # Oscar 
 print e.age + 10 # 42 
Run Code Online (Sandbox Code Playgroud)

我认为这几乎与这个问题相反:来自对象字段的Python字典

Ian*_*and 148

当然,这样的事情:

class Employee(object):
    def __init__(self, initial_data):
        for key in initial_data:
            setattr(self, key, initial_data[key])
Run Code Online (Sandbox Code Playgroud)

更新

正如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])
Run Code Online (Sandbox Code Playgroud)

然后你可以像这样调用它:

e = Employee({"name": "abc", "age": 32})
Run Code Online (Sandbox Code Playgroud)

或者像这样:

e = Employee(name="abc", age=32)
Run Code Online (Sandbox Code Playgroud)

或者甚至喜欢这样:

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)
Run Code Online (Sandbox Code Playgroud)

  • 如果你将初始数据作为`def __init __(self,**initial_data)`传递,你会得到一个额外的好处,即拥有一个也可以执行关键字参数的init方法(例如"e = Employee(name ='Oscar')"或者只是拿一本字典(例如"e = Employee(**dict)"). (4认同)
  • 如果你将arg的默认设置为`()`而不是`None`,你可以这样做:`def __init __(self,iterable =(),**kwargs):self .__ dict __.update(iterable,**kwargs)`. (4认同)
  • 我知道这是一个古老的问题,但我只想补充说它可以用列表理解的两行来完成,例如:`[[setattr(self,key,d [key])for d in d] in d in some_dict]` (3认同)
  • 提供`Employee(some_dict)`和`Employee(**some_dict)`API是不一致的.应该提供哪个更好. (2认同)
  • (另外,你的意思是“如果initial_data不是None”;在一种足够奇怪的情况下,这可能会引入无法按预期工作的代码。此外,你现在不能使用键“initial_data”之一蜜蜂。) (2认同)
  • 我很想知道为什么这不是以某种简单的方式内置到 python 中。我正在使用它来处理 Python GeoIP2 API 抛出 `AddressNotFoundError` 的问题(在这种情况下返回更正的数据,而不是炸毁) - 我发现 PHP 中的某些东西如此简单(`(对象)[' x' => 'y']`) 在 Python 中需要如此多的繁琐 (2认同)

Mik*_*ham 40

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

  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 
    
    Run Code Online (Sandbox Code Playgroud)

    要么

  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 
    
    Run Code Online (Sandbox Code Playgroud)

另一种基本上与案例1相同的解决方案是使用a collections.namedtuple.请参阅van的答案,了解如何实现这一点.


Dav*_*rby 13

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

>>> 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
Run Code Online (Sandbox Code Playgroud)

  • `__dict__`是语言的文档部分,而不是实现工件. (11认同)
  • `__dict__`是一个实现工件,不应该使用.此外,这忽略了类中描述符的存在. (3认同)
  • 使用`setattr`比直接访问`__dict__`更可取.当你使用`__dict__`时,你必须记住很多可能导致`__dict__`不存在或没有做你想要的事情,但是`setattr`实际上与`foo.bar =实际相同baz`. (3认同)
  • @DaveKirby:似乎建议不要使用“__dict__”:https://docs.python.org/tutorial/classes.html#id2 (3认同)
  • @Ignacio 你所说的“实现工件”是什么意思?有什么是我们不应该不知道的呢?或者它可能不存在于不同的平台中?(例如 Windows 中的 Python 与 Linux 上的 Python)可接受的答案是什么? (2认同)

Ruf*_*sVS 7

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

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
Run Code Online (Sandbox Code Playgroud)

您可以使用命名参数,元组列表或字典或单个属性分配进行初始化,例如:

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)
Run Code Online (Sandbox Code Playgroud)

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


van*_*van 6

settattr如果您真的需要支持,我认为使用答案是可行的方法dict.

但是如果Employeeobject只是一个你可以使用dot syntax(.name)而不是dict syntax(['name'])访问的结构,你可以像这样使用namedtuple:

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'}
Run Code Online (Sandbox Code Playgroud)

你有_asdict()方法来访问所有属性的字典,但你不能只在施工以后添加附加属性.


isl*_*zat 6

比如说

class A():
    def __init__(self):
        self.x=7
        self.y=8
        self.z="name"
Run Code Online (Sandbox Code Playgroud)

如果要一次设置属性

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

  • 为方便起见,您可以使用键/值:`a.__dict__.update(x=100, y=300, z="blah")` (2认同)