我正在继承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']
我做错了什么吗?
解决方法
当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__.