python字典怎么设置_在python中从字典设置属性

是否可以通过python中的字典创建对象,使得每个键都是该对象的属性?

像这样:

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

e = Employee(d)

print e.name # Oscar

print e.age + 10 # 42

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

当然,是这样的:

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)

如果您以def __init__(self,**initial_data)的形式传递初始数据,您将获得一个额外的好处,即拥有一个也可以执行关键字参数的init方法(例如" e = Employee(name = Oscar)")或仅接受字典(例如" e = Employee (**字典)")。

同时提供Employee(some_dict)和Employee(**some_dict) API是不一致的。应该提供哪个更好。

(此外,您的意思是if initial_data is not None;在非常奇怪的情况下,这可能会引入无法按预期工作的代码。此外,您现在不能使用其中一个API来使用键initial_data。)

如果将args默认设置为()而不是None,则可以这样做:def __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs)。

@Matt Anderson,这段代码对我来说似乎有点聪明。似乎更易读的解决方案是Ian使用的逻辑,或者更好的是选择一个一致的API。

@迈克·格雷厄姆:双方都同意。虽然提供这两个接口正是python dict构造函数所做的。香港专业教育学院更新了该示例以采用任意数量的映射对象,而无需保留任何名称(可能,除了自身)

@伊恩·克莱尔兰德(Ian Clelland),如果你问我的话,那就太丢脸了! ;)好点,但是。

对于键,initial_data.items()中的值:看起来更pythonic

我知道这是一个老问题,但我只想补充一点,可以用列表理解功能在两行中完成它,例如:[[setattr(self,key,d[key]) for key in d] for d in some_dict]

我很想知道为什么这不是以某种简单的方式内置到python中的。我用它来处理python GeoIP2 API抛出AddressNotFoundError的问题(在这种情况下,返回正确的数据,而不是炸毁)-我发疯了,在PHP((object) [x => y])中这么容易的事情需要花费很多精力Python

我试图找到一种方法来做到这一点,但是我很好奇如何将这些属性私有化。即使有巧妙的方法将下划线插入键名,您将如何为这些未知属性添加修饰符?

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

您知道所有字段都应该提前。在这种情况下,您可以显式设置所有属性。这看起来像

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

要么

您不知道所有字段都应该提前。在这种情况下,您应该将数据存储为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

基本上与情况1等效的另一种解决方案是使用collections.namedtuple。有关如何实现的信息,请参见van的答案。

您可以使用__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__是一个实现工件,不应使用。同样,这会忽略类中描述符的存在。

@Ignacio对"实现工件"是什么意思?我们不应该意识到的是什么?还是它可能不存在于不同的平台中? (例如Windows中的Python与Linux中的Python)可以接受的答案是什么?

我要说的是,不能保证给定的Python实现中存在它,但是在langref中多次引用了它。 Ians的答案涵盖了另一个问题,即将其传递给描述符而不是破坏它。

__dict__是该语言的文档部分,不是实现工件。

@Dave是这个吗? docs.python.org/library/stdtypes.html#special-attributes

如果您知道该类没有任何描述符,则__dict__.update是完全有效的-它是在标准库中的很多地方完成的。

使用setattr比直接访问__dict__更可取。您必须牢记很多事情,这些事情可能导致__dict__不在或使用__dict__时未做您想要的事情,但是setattr实际上与实际执行foo.bar = baz相同。

@DaveKirby:似乎建议不要使用__dict__:docs.python.org/tutorial/classes.html#id2

为什么不只使用属性名称作为字典的键?

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)

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

例如说

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)

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

我认为,如果确实需要支持dict,使用settattr的答案是可行的方法。

但是,如果Employee对象只是可以使用点语法(.name)而不是dict语法(['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'}

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

与使用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'

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值