我一直在阅读 super()
的工作原理。我遇到了this recipe演示如何创建有序计数器:
from collections import Counter, OrderedDict
class OrderedCounter(Counter, OrderedDict):
'Counter that remembers the order elements are first seen'
def __repr__(self):
return '%s(%r)' % (self.__class__.__name__,
OrderedDict(self))
def __reduce__(self):
return self.__class__, (OrderedDict(self),)
例如:
oc = OrderedCounter('adddddbracadabra')
print(oc)
OrderedCounter(OrderedDict([('a', 5), ('d', 6), ('b', 2), ('r', 2), ('c', 1)]))
有人能解释一下这是如何神奇地工作的吗?
这也出现在 Python documentation .
最佳答案
OrderedCounter 在 OrderedDict documentation 中作为示例给出。 ,并且无需覆盖任何方法即可工作:
class OrderedCounter(Counter, OrderedDict):
pass
当一个类方法被调用时,Python 必须找到正确的方法来执行。有一个定义的顺序来搜索类层次结构,称为“方法解析顺序”或 mro。 mro 存储在属性 __mro__
中:
OrderedCounter.__mro__
(<class '__main__.OrderedCounter'>, <class 'collections.Counter'>, <class 'collections.OrderedDict'>, <class 'dict'>, <class 'object'>)
当 OrderedDict 的实例调用 __setitem__()
时,它会按顺序搜索类:OrderedCounter
、Counter
、 OrderedDict
(在哪里找到)。所以像 oc['a'] = 0
这样的语句最终会调用 OrderedDict.__setitem__()
。
相比之下,__getitem__
不会被 mro 中的任何子类覆盖,因此 count = oc['a']
由 dict 处理。 __getitem__()
.
oc = OrderedCounter()
oc['a'] = 1 # this call uses OrderedDict.__setitem__
count = oc['a'] # this call uses dict.__getitem__
对于像 oc.update('foobar') 这样的语句,会出现一个更有趣的调用序列。
首先,调用 Counter.update()
。 Counter.update()
的代码使用 self[elem],它变成了对 OrderedDict.__setitem__()
的调用。 that 的代码调用 dict.__setitem__()
。
如果基类颠倒了,它就不再起作用了。因为 mro 不同,调用了错误的方法。
class OrderedCounter(OrderedDict, Counter): # <<<== doesn't work
pass
有关 mro 的更多信息可以在 Python 2.3 documentation 中找到.
关于python - 创建有序计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35446015/