在Python中访问OrderedDict键(如属性)

2024-04-25 08:37:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我想写一个容器类

  1. 允许索引(在字典样式中),例如data['a']和类似属性的访问,例如data.a;这是寻址的here
  2. 保留添加条目的顺序,例如通过子类化collections.OrderedDict;这是针对here

我把解决方案改为1。子类collections.OrderedDict而不是dict,但它不起作用;请参见下文。在

from collections import OrderedDict

class mydict(OrderedDict):
    def __init__(self, *args, **kwargs):
        super(mydict, self).__init__(*args, **kwargs)
        self.__dict__ = self

D = mydict(a=1, b=2)

#D['c'] = 3 # fails
D.d    = 4

#print D    # fails

带有失败注释的两行将导致以下错误:

^{pr2}$

以及

    D['c'] = 3
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/collections.py", line 58, in __setitem__
    root = self.__root
AttributeError: 'mydict' object has no attribute '_OrderedDict__root'

有解决办法吗?__init__函数可以修补吗?在


Tags: selfdata字典hereinitargs样式root
1条回答
网友
1楼 · 发布于 2024-04-25 08:37:20

首先,如果你只是想让它正常工作,而不知道你的尝试有什么问题,那么在PyPI、ActiveState等上有多个“AttrDict”实现。搜索其中一个并查看其代码,或者只安装并使用它。在


这不是你想要的。我知道人们推荐它,但它有一些基本的主要问题。其中一个问题正是你所看到的。在

特别是,这意味着您现在已经丢失了所有现有的属性,包括OrderedDict本身使用的内部属性(例如,__root您正在得到的错误)和附加到所有对象的特殊属性(比如__class__)。在

当您仅仅使用dict时,您至少在CPython中没有注意到这个问题,因为dict是用C实现的,它需要操作的特殊成员存储在一个C结构中,而不是存储在__dict__中,因此您不会丢失它们。但是对于用Python实现的任何需要特殊成员的类,问题就变得显而易见了。在


Python对customizing attribute access有特殊的方法。您要做的是实现这些方法:

class AttrDict(OrderedDict):
    def __getattr__(self, name):
        return self[name]
    def __setattr__(self, name, value):
        self[name] = value
    def __delattr__(self, name):
        del self[name]

但是,在这种情况下,即使这样也不能解决所有问题,因为当OrderedDict中的代码试图使用__root时,仍然会调用重写!要解决这个问题,您只需要将这些方法中的一些调用转发到dict,而不需要将所有调用转发到dict。在

而“一些”是复杂的,很难得到正确的答案。更简单的解决方案是只封装并委托给OrderedDict,而不是继承:

^{pr2}$

或者,更简单地说,只需使用OrderedDict作为__dict__-这是元类的范例,但是如果您想快速地完成这项工作,可以使用__init__或{}来完成。在


后一种解决方案只是使您成为一个普通对象,其属性恰好是有序的,而不是映射。但是转发映射方法也很容易。实现__getitem____setitem____delitem____iter__、和{}转发到{},并从{a2}继承以填充API的其余部分。在

现在,如果您回过头去查看PyPI上的“AttrDict”并单击实现,您将看到这正是它们所做的:它们将__getattr__和{}转发给OrderedDict的{},依此类推。在

相关问题 更多 >