我发现它更方便访问字典键作为obj。foo而不是obj['foo'],所以我写了这个片段:

class AttributeDict(dict):
    def __getattr__(self, attr):
        return self[attr]
    def __setattr__(self, attr, value):
        self[attr] = value

然而,我认为一定有一些原因,Python没有提供开箱即用的功能。以这种方式访问字典键的注意事项和缺陷是什么?


当前回答

如果你想要一个方法的键,比如__eq__或__getattr__呢?

而且不能有一个不以字母开头的条目,因此使用0343853作为键是无效的。

如果你不想使用字符串呢?

其他回答

一般情况下它不成立。不是所有有效的dict键都有可寻址的属性(“键”)。所以,你要小心。

Python对象基本上都是字典。所以我怀疑会有什么表现或其他惩罚。

以这种方式访问字典键的注意事项和缺陷是什么?

正如@Henry所指出的,在dict中不能使用点访问的一个原因是,它将dict键名限制为python有效变量,从而限制了所有可能的名称。

下面是一些例子,说明为什么在给定字典d的情况下,点点访问通常没有帮助:

有效性

以下属性在Python中是无效的:

d.1_foo                           # enumerated names
d./bar                            # path names
d.21.7, d.12:30                   # decimals, time
d.""                              # empty strings
d.john doe, d.denny's             # spaces, misc punctuation 
d.3 * x                           # expressions  

风格

PEP8约定将对属性命名施加软约束:

A.保留关键字(或内置函数)名称:

d.in
d.False, d.True
d.max, d.min
d.sum
d.id

如果函数参数的名称与保留关键字冲突,通常最好在后面添加一个下划线…

B.方法和变量名的大小写规则:

变量名遵循与函数名相同的约定。

d.Firstname
d.Country

使用函数命名规则:小写字母,单词之间用下划线分隔,以提高可读性。


有时,在pandas这样的库中会出现这些问题,这些库允许按名称点访问DataFrame列。解决命名限制的默认机制也是数组表示法——括号中的字符串。

如果这些约束不适用于您的用例,那么在点访问数据结构上有几个选项。

很抱歉再添加一个,但这一个解决了subdicts和纠正AttributeError,尽管非常简单:

class DotDict(dict):
    def __init__(self, d: dict = {}):
        super().__init__()
        for key, value in d.items():
            self[key] = DotDict(value) if type(value) is dict else value
    
    def __getattr__(self, key):
        if key in self:
            return self[key]
        raise AttributeError(key) #Set proper exception, not KeyError

    __setattr__ = dict.__setitem__
    __delattr__ = dict.__delitem__

没有必要自己写 Setattr()和getattr()已经存在。

类对象的优势可能在类定义和继承中发挥作用。

从另一个SO问题中,有一个很好的实现示例,可以简化现有的代码。如何:

class AttributeDict(dict):
    __slots__ = () 
    __getattr__ = dict.__getitem__
    __setattr__ = dict.__setitem__

更加简洁,并且不会为将来的__getattr__和__setattr__函数留下任何额外的麻烦空间。