python – 为什么重写__contains__会破坏OrderedDict.keys?

前端之家收集整理的这篇文章主要介绍了python – 为什么重写__contains__会破坏OrderedDict.keys?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我正在继承OrderedDict(C python,2.7.3)来表示数据文件. __getitem__从数据文件提取一个字段,并将其设置在当前实例上,类似于我在下面发布的代码.现在我想覆盖__contains__以返回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,它似乎仍然有效(给出以下输出).

barbar
['bar']

我做错了什么吗?

@H_301_14@

解决方法

当Foo .__ contains__未定义时:
a['bar']

调用Foo .__ getitem__,执行

self[key] = data

这称为OrderedDict .__ setitem__,它以这种方式定义:

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,value)

由于Foo .__ contains__未定义,

if key not in self:

是真的.所以关键是正确添加到自我.__ root和self .__ map.

当Foo .__ contains__被定义时,

if key not in self:

如果错.所以关键是没有正确添加到self .__ root和self .__ map.
Foo .__包含有效的傻瓜OrderedDict .__ setitem__,认为已经添加了’bar’键.

我发现使用以下代码(在__setitem__和__iter__中添加print语句)很有帮助:

from collections import OrderedDict

dictclass = OrderedDict

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

    def __setitem__(self,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,key]
        dict_setitem(self,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']

请注意,通过使Foo成为collections.MutableMapping的子类并将其大部分行为委托给OrderedDict属性,可以避免此问题:

import collections
dictclass = collections.OrderedDict

class Foo(collections.MutableMapping):
    def __init__(self,*args,**kwargs):
        self._data = dictclass(*args,**kwargs)
    def __setitem__(self,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) or 'bar' in whatever

产量

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

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

即使定义了__contains__.

@H_301_14@ @H_301_14@

猜你在找的Python相关文章