gpt4 book ai didi

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

转载 作者:太空狗 更新时间:2023-10-29 22:27:09 27 4
gpt4 key购买 nike

我正在对 OrderedDict(Cpython,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']

我是不是做错了什么?

最佳答案

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

因为 Foo.__contains__ 没有定义,

    if key not in self:

为真。所以 key 被正确地添加到 self.__rootself.__map

Foo.__contains__被定义时,

    if key not in self:

如果为假。因此 key 未正确添加到 self.__rootself.__mapFoo.__contains__ 有效愚弄 OrderedDict.__setitem__ 认为 'bar' 键已经被添​​加。


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

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

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

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

即使定义了 __contains__

关于python - 为什么重写 __contains__ 会破坏 OrderedDict.keys?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15316422/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com