Python 2.6、3 抽象基类的误解

标签 python abstract-class

当我使用 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/

相关文章:

python - 无需 for 循环,围绕一组坐标生成随机数

python - 将元类规则应用于所有后代而不是直接元类

python - 为什么在 Python 中使用抽象基类?

Java 回文、方法和抽象类?

java - java.util.AbstractList.add 处的 UnsupportedOperationException

python - 在 Spyder 中无法看到 PySide2 创建的应用程序窗口

python - Nodejs 加密与 python hashlib

php - 在 Laravel 中通过依赖注入(inject)解决抽象类的依赖

python - 反向要求.txt

python - Pyspark 数据框收集热门记录