【问题标题】:Mix-in of abstract class and namedtuple抽象类和命名元组的混合
【发布时间】:2016-02-08 10:57:36
【问题描述】:

我想用定义和abstract method 定义一个命名元组和一个基类的混合:

import abc
import collections

class A(object):
    __metaclass__ = abc.ABCMeta

    @abc.abstractmethod
    def do(self):
        print("U Can't Touch This")

B = collections.namedtuple('B', 'x, y')

class C(B, A):
    pass

c = C(x=3, y=4)
print(c)
c.do()

据我了解阅读文档和other examples I have seenc.do() 应该会引发错误,因为 C 类没有实现do()。但是,当我运行它时......它可以工作:

B(x=3, y=4)
U Can't Touch This

我一定是忽略了什么。

【问题讨论】:

  • 你用的是什么版本的python?在 python 2 和 python 3 中,元类以不同的、不兼容的方式被调用。如果你使用的是 python 3,那么你的类实际上并不是一个抽象类。
  • 我在 Python 2 和 3 上都试过了。同样的行为。

标签: python


【解决方案1】:

当您查看C 的方法解析顺序时,您会发现B 在该列表中位于A 之前。这意味着当您实例化C 时,将首先调用B__new__ 方法。

这是namedtuple.__new__的实现

def __new__(_cls, {arg_list}):
    'Create new instance of {typename}({arg_list})'
    return _tuple.__new__(_cls, ({arg_list}))

你可以看到它不支持协作继承,因为它打破了链条,简单地调用了tuples__new__方法。像这样 ABCMeta.__new__ 检查抽象方法的方法 永远不会执行(无论在哪里),它也不能检查抽象方法。所以实例化不会失败。

我认为反转 MRO 可以解决这个问题,但奇怪的是它没有。我将进行更多调查并更新此答案。

【讨论】:

  • 可能反转 MRO 并不重要,因为 B 实现了 __new__A 没有。
  • namedtupleABCMeta 都有__new__ 方法。 MRO不是深度优先搜索吗?
  • 有点。请参阅此示例:>>> class X(B,A): ... pass ... >>> X.__mro__ (<class '__main__.X'>, <class '__main__.B'>, <type 'tuple'>, <class '__main__.A'>, <type 'object'>) >>> >>> class Y(A,B): ... pass ... >>> Y.__mro__ (<class '__main__.Y'>, <class '__main__.A'>, <class '__main__.B'>, <type 'tuple'>, <type 'object'>)。无论哪种方式,都首先调用元组,因为最终它们都派生自对象。
  • ABCMeta 是一种类型。它的__new__ 函数仅在创建类时调用,而不是在创建对象时调用。
  • 是的,我很困惑,当然ABCMeta.__new__ 是在不同的时间调用的。但我仍然不明白如何在object.__new__ 中完成对抽象方法的检查。有代码可以检查吗?为什么它在object.__new__ 而不是ABCMeta.__call__,这对我来说是有意义的。
猜你喜欢
  • 2011-07-23
  • 2010-09-30
  • 2019-03-25
  • 1970-01-01
  • 1970-01-01
  • 2015-08-14
  • 2011-11-26
  • 1970-01-01
  • 2017-11-03
相关资源
最近更新 更多