Python 2.6,3抽象基类误解

Aar*_*ron 9 python abstract-class

当我使用ABCMeta和abstractmethod时,我没有看到我的期望.

这在python3中工作正常:

from abc import ABCMeta, abstractmethod

class Super(metaclass=ABCMeta):
    @abstractmethod
    def method(self):
        pass

a = Super()
TypeError: Can't instantiate abstract class Super ...
Run Code Online (Sandbox Code Playgroud)

而在2.6:

class Super():
    __metaclass__ = ABCMeta
    @abstractmethod
    def method(self):
         pass

a = Super()
TypeError: Can't instantiate abstract class Super ...
Run Code Online (Sandbox Code Playgroud)

除了ABCMeta之外,如果我从对象派生Super,它们也都可以正常工作(我得到了预期的异常).

如果我从列表中派生超级,他们都"失败"(没有例外).

我想要一个抽象基类作为列表但是抽象,并且在子类中具体.

我做错了,还是我不想在python中使用它?

Ale*_*lli 15

使用Super您的工作片段中的构建,您执行的操作Super()是:

>>> Super.__init__
<slot wrapper '__init__' of 'object' objects>
Run Code Online (Sandbox Code Playgroud)

如果Super继承list,请调用它Superlist:

>>> Superlist.__init__
<slot wrapper '__init__' of 'list' objects>
Run Code Online (Sandbox Code Playgroud)

现在,抽象基类可以用作mixin类,可以多次继承(获得ABC可能提供的"模板方法"设计模式功能)和一个具体的类,而不会产生由此产生的后代抽象.所以考虑:

>>> class Listsuper(Super, list): pass
... 
>>> Listsuper.__init__
<slot wrapper '__init__' of 'list' objects>
Run Code Online (Sandbox Code Playgroud)

看到问题?通过多继承调用的规则Listsuper()(由于存在悬空抽象方法不允许失败)运行与调用相同的代码Superlist()(您想要失败).在实践(list.__init__)中,该代码并不反对悬挂抽象方法 - 只是object.__init__这样做.并修复可能会破坏依赖于当前行为的代码.

建议的解决方法是:如果您需要抽象基类,则其所有基础必须是抽象的.因此,不要list在你的基础中具体,使用作为基础collections.MutableSequence,添加__init__一个._list属性,并MutableSequence通过直接委托实现抽象方法self._list.不完美,但也不是那么痛苦.