当我使用 ABCMeta 和抽象方法时,我没有看到我期望的结果。
这在 python3 中工作正常:
from abc import ABCMeta, abstractmethod
class Super(metaclass=ABCMeta):
@abstractmethod
def method(self):
pass
a = Super()
TypeError: Can't instantiate abstract class Super ...
在 2.6 中:
class Super():
__metaclass__ = ABCMeta
@abstractmethod
def method(self):
pass
a = Super()
TypeError: Can't instantiate abstract class Super ...
除了 ABCMeta 之外,如果我从对象派生 Super,它们也都可以正常工作(我得到了预期的异常)。
如果我从列表中派生 Super,它们都“失败”(没有出现异常)。
我希望抽象基类是一个列表,但抽象,在子类中具体。
我做错了吗,或者我不应该在 python 中使用它?
最佳答案
使用 Super
在您的工作片段中构建,您在执行 Super()
时调用的是:
>>> Super.__init__
<slot wrapper '__init__' of 'object' objects>
如果Super
继承自list
,则称它为Superlist
:
>>> Superlist.__init__
<slot wrapper '__init__' of 'list' objects>
现在,抽象基类可以用作mixin 类,与具体类一起多重继承(以获得 ABC 可能提供的“模板方法”设计模式特性)类,而不使生成的后代抽象。所以考虑:
>>> class Listsuper(Super, list): pass
...
>>> Listsuper.__init__
<slot wrapper '__init__' of 'list' objects>
看到问题了吗?根据多重继承调用 Listsuper()
的规则(不允许仅仅因为有一个悬空的抽象方法而失败)运行与调用 Superlist( )
(您希望失败)。该代码在实践中 (list.__init__
)不反对悬挂抽象方法——只有object.__init__
反对。修复它可能会破坏依赖于当前行为的代码。
建议的解决方法是:如果你想要一个抽象基类,它的所有基类都必须是抽象的。因此,不要在你的基础中使用具体的 list
,而是使用 collections.MutableSequence
作为基础,添加一个 __init__
来生成一个 。 _list
属性,并通过直接委托(delegate)给 self._list
来实现 MutableSequence
的抽象方法。不完美,但也没有那么痛苦。
关于Python 2.6、3 抽象基类的误解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2862153/