Python 为什么覆盖包含中断OrderedDict.keys?

Python 为什么覆盖包含中断OrderedDict.keys?,python,python-2.7,Python,Python 2.7,我将OrderedDict(Cpython,2.7.3)子类化以表示数据文件\uuuu getitem\uuuu从数据文件中提取一个字段,并在当前实例上设置它,类似于我在下面发布的代码。现在,如果字段在字典中或磁盘上的文件中,我想重写\uuuu contains\uu以返回True,因为它可以以任何方式读取。然而,这似乎破坏了OrderedDict检查其密钥的能力 from collections import OrderedDict dictclass = OrderedDict clas

我将OrderedDict(Cpython,2.7.3)子类化以表示数据文件
\uuuu getitem\uuuu
从数据文件中提取一个字段,并在当前实例上设置它,类似于我在下面发布的代码。现在,如果字段在字典中或磁盘上的文件中,我想重写
\uuuu contains\uu
以返回
True
,因为它可以以任何方式读取。然而,这似乎破坏了
OrderedDict
检查其密钥的能力

from collections import OrderedDict

dictclass = OrderedDict

class Foo(dictclass):
    def __getitem__(self,key):
        try:
            return dictclass.__getitem__(self,key)
        except KeyError:
            pass

        data = key*2
        self[key] = data
        return data

    def __contains__(self,whatever):
        return dictclass.__contains__(self,whatever) or 'bar' in whatever

a = Foo()
print a['bar']
print a.keys()
如果运行上述代码,您将获得以下输出:

barbar
[]
请注意,如果在上述代码中更改
dictclass=dict
,它似乎仍然有效(给出以下输出)


我做错了什么吗?

Foo.\uuu包含\uuuu
未定义时:

a['bar']
调用
Foo.\uuuu getitem\uuuu
,执行

    self[key] = data
这将调用
OrderedDict.\uuuu setitem\uuuuu
,其定义如下:

def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
    'od.__setitem__(i, y) <==> od[i]=y'
    # Setting a new item creates a new link at the end of the linked list,
    # and the inherited dictionary is updated with the new key/value pair.
    if key not in self:
        root = self.__root
        last = root[PREV]
        last[NEXT] = root[PREV] = self.__map[key] = [last, root, key]
    dict_setitem(self, key, value)
这是真的。因此,该键被正确地添加到
self.\uu root
self.\uu map


当定义了
Foo.\uuuu包含\uuu

    if key not in self:
如果是假的。因此,该键未正确添加到
self.\uu root
self.\uu map
Foo.\uuuuu包含有效的傻瓜
OrderedDict.\uuuu设置项\uuuuu
认为
'bar'
键已经添加


我发现使用以下代码很有帮助(在
\uuuuuu setitem\uuuuuuu
\uuuuuuu iter\uuuuuuu
中添加打印语句):

产生

a = Foo()
print a['bar']
# barbar

print a.keys()
# ['bar']

即使定义了
\uuuu包含

破坏代码的是
中的“bar”。如果您删除它,它将与您提到的更改
dictclass=dict
一样工作

\uuuu setitem\uuuu
实现的
orderedict
是:

def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
    'od.__setitem__(i, y) <==> od[i]=y'
    # Setting a new item creates a new link at the end of the linked list,
    # and the inherited dictionary is updated with the new key/value pair.
    if key not in self:
        root = self.__root
        last = root[0]
        last[1] = root[0] = self.__map[key] = [last, root, key]
    return dict_setitem(self, key, value)

由于用于检索值的代码使用此迭代器和
self.\u root
不包含
“bar”
,这个具体的键无法在值中返回。

我正在阅读,但我仍然很难弄清楚这一点……我正在这样做,我想你的问题在哪里:看看
\uuuuuuuuuu setitem\uuuuuu
\uuuuuuuu iter\uuuuuuuuuuuu
@a.Rodas--是的,这就是我在找的地方。也许我太累了,但我很难把所有的逻辑都理顺。谢谢。就是这样--我花了太多时间关注于
self.\uuu root
以及它是如何初始化的--思考--
self.\uuuu root=root=[];root[:]=[root,root,None]
发生了什么事???:XMy解决问题的方法非常低俗——它通常由许多打印语句组成。:)是的,就是这样。谢谢+1.当然,在我的代码中,
中的
或“bar”是更复杂的东西,我不想删除。我认为要使它正常工作,对OrderedDict进行黑客攻击太困难了。我想我只是将一个常规dict子类化,并保留一个单独的
\uu order
列表。@mgilson:也许让
Foo
拥有-a
OrderedDict
,而不是be-a
OrderedDict
?@unutbu--我希望它是一个映射类型,这样我就可以将其解包。。。我可以自己跟踪订单。@mgilson:是的,我想你可以通过将
Foo
作为
集合的子类来实现。可变映射
,但将
\uu getitem\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。
OrderedDict
行为将保持原始状态,而您可以在
\uuu getitem\uuuuu
\uuu包含
@mgilson中做自己的事情:如果您子类化
可变映射
,则至少必须重写
\uu getitem\uuuuuuu
\uuuuuu setitem\uuuuuuu
\uuuu len\uuuu
\uu包含
from collections import OrderedDict

dictclass = OrderedDict

class Foo(dictclass):
    def __getitem__(self,key):
        try:
            return dictclass.__getitem__(self,key)
        except KeyError:
            pass

        data = key*2
        self[key] = data
        return data

    def __contains__(self,whatever):
        print('contains: {}'.format(whatever))
        return dictclass.__contains__(self,whatever) or 'bar' in whatever

    def __setitem__(self, key, value, PREV=0, NEXT=1, dict_setitem=dict.__setitem__):
        'od.__setitem__(i, y) <==> od[i]=y'
        # Setting a new item creates a new link at the end of the linked list,
        # and the inherited dictionary is updated with the new key/value pair.
        print('key not in self: {}'.format(key not in self))
        if key not in self:
            root = self._OrderedDict__root
            last = root[PREV]
            last[NEXT] = root[PREV] = self._OrderedDict__map[key] = [last, root, key]
        dict_setitem(self, key, value)

    def __iter__(self):
        'od.__iter__() <==> iter(od)'
        # Traverse the linked list in order.
        NEXT, KEY = 1, 2

        root = self._OrderedDict__root
        curr = root[NEXT]
        print('curr: {}'.format(curr))
        print('root: {}'.format(root)) 
        print('curr is not root: {}'.format(curr is not root))

        while curr is not root:
            yield curr[KEY]
            curr = curr[NEXT]

a = Foo()
print a['bar']
# barbar

print a.keys()
# ['bar']
import collections
dictclass = collections.OrderedDict

class Foo(collections.MutableMapping):
    def __init__(self, *args, **kwargs):
        self._data = dictclass(*args, **kwargs)
    def __setitem__(self, key, value):
        self._data[key] = value
    def __delitem__(self, key):
        del self._data[key]
    def __iter__(self):
        return iter(self._data)
    def __len__(self):
        return len(self._data)

    def __getitem__(self,key):
        try:
            return self._data[key]
        except KeyError:
            pass

        data = key*2
        self[key] = data
        return data

    def __contains__(self,whatever):
        return dictclass.__contains__(self,whatever) or 'bar' in whatever
a = Foo()
print a['bar']
# barbar

print a.keys()
# ['bar']
def __setitem__(self, key, value, dict_setitem=dict.__setitem__):
    'od.__setitem__(i, y) <==> od[i]=y'
    # Setting a new item creates a new link at the end of the linked list,
    # and the inherited dictionary is updated with the new key/value pair.
    if key not in self:
        root = self.__root
        last = root[0]
        last[1] = root[0] = self.__map[key] = [last, root, key]
    return dict_setitem(self, key, value)
def __iter__(self):
    'od.__iter__() <==> iter(od)'
    # Traverse the linked list in order.
    root = self.__root
    curr = root[1]                                  # start at the first node
    while curr is not root:
        yield curr[2]                               # yield the curr[KEY]
        curr = curr[1]                              # move to next node