创建有序计数器

新手上路,请多包涵

我一直在阅读 super() 是如何工作的。我遇到了 这个演示如何创建有序计数器的方法

 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 文档 中。

原文由 Sean 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 573
1 个回答

OrderedCounter 在 OrderedDict 文档 中作为示例给出,并且无需覆盖任何方法即可工作:

 class OrderedCounter(Counter, OrderedDict):
    pass

当一个类方法被调用时,Python 必须找到正确的方法来执行。它搜索类层次结构的定义顺序称为“方法解析顺序”或 mro。 mro 存储在属性 __mro__ 中:

 OrderedCounter.__mro__

(<class '__main__.OrderedCounter'>, <class 'collections.Counter'>, <class 'collections.OrderedDict'>, <class 'dict'>, <class 'object'>)

When an instance of an OrderedDict is calling __setitem__() , it searches the classes in order: OrderedCounter , Counter , OrderedDict (where it is成立)。所以像 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__() 的调用。该代码 调用 dict.__setitem__()

如果基类被颠倒,它就不再有效。因为 mro 不同并且调用了错误的方法。

 class OrderedCounter(OrderedDict, Counter):   # <<<== doesn't work
    pass

可以在 Python 2.3 文档 中找到有关 mro 的更多信息。

原文由 RootTwo 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题