在Python2.7和Python3中具有视图的子类数据类型



Python3引入了视图(请参阅此问题)。它们还被后移植到Python 2.7。我目前正在Python 2.7应用程序中对dict进行子类化(尽管目标是将其移植到Python 3)。我想知道我是否以及如何能够以与原始视图完全相同的方式对.viewitems()和类似的函数进行子类化。

这是我的意图:我有一个这样的格言:

data = my_subclassed_dict
data["_internal"] = "internal_value"
data["key"] = "value"
list(data.keys()) == ["key"]

也就是说,我过滤所有以"_"开头的数据。到目前为止,这一切都很好:对于迭代器,我只使用yield,对于列表,我使用列表理解来过滤不需要的值。然而,这些项目与dict没有任何联系(这很好,感觉就像一个dict)。然而,这两种方式都不起作用:

keys = data.viewkeys()
"key" in keys
del data["key"]
"key" not in keys # This is False !

最后一部分不起作用,因为没有引用原始键,所以Python不会注意到。

那么:有没有一种简单的方法可以实现这一点(不需要重新实现所有逻辑!)?

这更像是一个出于兴趣的问题,因为我不认为它在我的场景中应用那么多。

view对象基本上是"空"代理。他们指着原来的字典。

不幸的是,当前的字典视图对象并不是真正可重用的。引用源代码:

/* TODO(guido): The views objects are not complete:
 * support more set operations
 * support arbitrary mappings?
   - either these should be static or exported in dictobject.h
   - if public then they should probably be in builtins
*/

注意support arbitrary mappings条目;这些对象不支持任意映射,我们也不能从Python代码中创建新的实例或子类:

>>> type({}.viewkeys())({})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: cannot create 'dict_keys' instances
>>> class MyView(type({}.viewkeys())): pass
... 
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: Error when calling the metaclass bases
    type 'dict_keys' is not an acceptable base type

您被迫创建自己的并实现视图对象支持的所有挂钩:

class DictKeys(object):
    def __init__(self, parent):
        self.parent = parent
    def __len__(self):
        return len(self.parent)
    def __contains__(self, key):
        return key in self.parent
    def __iter__(self):
        return iter(self.parent)

等等。

原始对象实现的方法是:

>>> dir({}.viewkeys())
['__and__', '__class__', '__contains__', '__delattr__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__or__', '__rand__', '__reduce__', '__reduce_ex__', '__repr__', '__ror__', '__rsub__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__xor__']

__and____or____sub____xor____rand____ror____rsub____rxor__方法实现了对&|^运算符的重写,以提供集合操作。

如果您在阅读C代码时相当安全,请查看视图对象的实现,了解它们是如何实现方法的。

考虑将任何以下划线开头的键存储在一个单独的dict中。您不必实现keysiterkeysviewitems等,但可能需要重新实现许多其他方法。

最新更新