在Python中覆盖{}

3 投票
2 回答
1483 浏览
提问于 2025-04-17 09:26

我想创建一个可以像这样访问的字典:

>>> 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

撰写回答