我有一个已经替换__iter__
的类来隐藏额外不需要的数据。我根据python版本将iteritems
设置为dict.iteritems
或dict.items
,使我的其余代码向后兼容,然后我可以调用iteritems(class_object)
,但它我的班级似乎不太适合。
用一个例子来解释会更容易:
class Test(dict):
def __init__(self, some_dict):
self.some_dict = some_dict
super(self.__class__, self).__init__(self.some_dict)
def __iter__(self):
for k, v in self.some_dict.iteritems():
yield k, v['value']
test_dict = {
'a': {'value': 'what',
'hidden': 123},
'b': {'value': 'test'}
}
如果我Test(test_dict).__iter__()
,则会正确返回{'a': 'what', 'b': 'test'}
如果我在课程中添加iteritems = __iter__
,那么在执行Test(test_dict).iteritems()
但是,无论我尝试什么,执行dict.iteritems(Test(test_dict))
默认为标准dict迭代,并返回{'a': {'hidden': 123, 'value': 'what'}, 'b': {'value': 'test'}}
我已经尝试了几种跟踪功能,但它们不够深入,无法弄清楚发生了什么。
答案 0 :(得分:1)
dict.iteritems()
方法直接进入dict
实现的内部数据结构。您传入了dict
的子类,因此可以使用相同的数据结构进行访问。您无法覆盖此行为。
dict.iteritems()
不会使用__iter__
;后者只生成键,而不是键值对!
您应该以不同方式定义iteritems
;给定PY3
布尔变量,对于Python 2为False
,否则为True
:
from operator import methodcaller
iteritems = methodcaller('items' if PY3 else 'iteritems')
现在iteritems(object)
已根据需要翻译为object.iteritems()
或object.items()
,并始终调用正确的方法。
接下来,为了扩展字典行为,而不是子类化dict
,我将子类collections.MutableMapping
(*):
from collections import MutableMapping
class Test(MutableMapping):
def __init__(self, some_dict):
self.some_dict = some_dict.copy()
def __getitem__(self, key):
return self.some_dict[key]
def __setitem__(self, key, value):
self.some_dict[key] = value
def __delitem__(self, key):
del self.some_dict[key]
def __len__(self):
return len(self.some_dict)
def __iter__(self):
for k, v in self.some_dict.iteritems():
yield k, v['value']
这实现了dict
提供的所有相同方法,除以外的copy
和dict.fromkeys()
类方法。
您可以继承collections.UserDict()
,这会添加其余两个方法:
try:
# Python 2
from UserDict import UserDict
except ImportError:
from collections import UserDict
class Test(UserDict):
def __iter__(self):
for k, v in self.data.iteritems():
yield k, v['value']
在这种情况下,只需要替代__iter__
实施。
在任何一种情况下,仍然无法在这些对象上使用dict.iteritems
,因为该方法只能用于实际的dict
个对象。
(*) collections.MutableMapping
是该类的Python 2位置,官方Python 3位置为collections.abc.MutableMapping
但是有一些别名可以支持Python 2兼容代码。