在Python中覆盖{}
我想创建一个可以像这样访问的字典:
>>> my_dict["property'] = 3
>>> my_dict.property
3
所以我做了这个:
class DictAsMember(dict):
def __getattr__(self, name):
return self[name]
这个可以正常工作,但如果有嵌套的字典就不行了,比如:
my_dict = DictAsMember()
my_dict["property"] = {'sub': 1}
我可以访问 my_dict.property,但从逻辑上讲,我不能这样访问 my_dict.property.sub,因为 property 是一个默认字典。所以我想做的是覆盖这个默认字典,这样你就可以使用 {} 来访问。
这可能吗?
2 个回答
2
与其自己写一个类来实现 my_dict.property
这种写法(这叫做对象表示法),你可以选择使用命名元组。命名元组可以像对象一样通过属性来引用,也可以用标准的元组语法来使用。根据文档
命名元组用于创建类似元组的对象,这些对象的字段可以通过属性访问,同时也可以通过索引访问和迭代。
下面是它们用法的一个例子:
from collections import *
my_structure = namedtuple('my_structure', ['name', 'property'])
my_property = namedtuple('my_property', ['sub'])
s = my_structure('fred', my_property(1))
s # my_structure(name='fred', property=my_property(sub=1)) will be printed
s.name # 'fred' will be printed
s.property # my_property(sub=1) will be printed
s.property.sub # 1 will be printed
另外,可以查看这个问题的被接受答案,里面对命名元组有个很好的总结。
7
解决这个问题的一种方法是在返回默认字典之前,使用 DictAsMember
将它们包裹起来,这个操作是在 __getattr__
方法中进行的:
class DictAsMember(dict):
def __getattr__(self, name):
value = self[name]
if isinstance(value, dict):
value = DictAsMember(value)
elif isinstance(value, list):
value = [DictAsMember(element)
if isinstance(element, dict)
else element
for element in value]
return value
my_dict = DictAsMember()
my_dict["property"] = {'sub': 1}
print my_dict.property.sub # 1 will be printed
my_dict = DictAsMember()
my_dict["property"] = [{'name': 1}, {'name': 2}]
print my_dict.property[1].name # 2 will be printed