无法找到dict.iteritems(类)的覆盖

时间:2018-06-12 15:45:22

标签: python

我有一个已经替换__iter__的类来隐藏额外不需要的数据。我根据python版本将iteritems设置为dict.iteritemsdict.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'}}

我已经尝试了几种跟踪功能,但它们不够深入,无法弄清楚发生了什么。

1 个答案:

答案 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提供的所有相同方法,以外的copydict.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兼容代码。