【问题标题】:Python3 - How does one define an abstract subclass from an existing abstract class?Python3 - 如何从现有抽象类定义抽象子类?
【发布时间】:2018-07-26 14:54:44
【问题描述】:

我最初定义了以下抽象类:

from abc import ABC, abstractmethod    
class Primitive(ABC):

现在我想创建另一个继承自 Primitive 的抽象类:

class InstrumentName(Primitive)

我需要这个类是抽象的,因为我最终想要创建以下两个具体类:

class CurrencyInstrumentName(InstrumentName)
class MetalInstrumentName(InstrumentName)

我已阅读文档并搜索了 SO,但它们主要涉及从抽象类中子类化具体类,或讨论 Python 如何处理抽象

【问题讨论】:

    标签: python python-3.x oop inheritance abstract-class


    【解决方案1】:

    只是子类,你不需要做任何特别的事情。

    只有在实现中没有更多 abstractmethodabstractproperty 对象时,类才会变得具体。

    让我们来说明一下:

    from abc import ABC, abstractmethod    
    class Primitive(ABC):
        @abstractmethod
        def foo(self):
            pass
    
        @abstractmethod
        def bar(self):
            pass
    
    class InstrumentName(Primitive):
        def foo(self):
            return 'Foo implementation'
    

    这里,InstrumentName 仍然是抽象的,因为bar 被保留为abstractmethod。您不能创建该子类的实例:

    >>> InstrumentName()
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    TypeError: Can't instantiate abstract class InstrumentName with abstract methods bar
    

    子类也可以根据需要添加@abstractmethod@abstractproperty方法。

    在底层,所有子类都继承了强制执行此操作的 ABCMeta 元类,它只是检查类中是否还有任何 @abstractmethod@abstractproperty 属性。

    【讨论】:

    • 所以我应该忽略 PyCharm 的警告,即我没有为 InstrumentName 提供具体实现?
    • @EbramShehata 是的。 PyCharm 试图提供帮助,但无法知道您有意创建抽象基类的层次结构。但这是一件非常合理的事情!
    • 是否有可能从type 元类中进行abstractmethod 检测?这样就不需要ABCMeta 元类。 (我说的是语言设计。)换句话说,ABCMeta 做的事情是type 做不到的?
    • @Maggyero:当然,但这会给所有类型增加很多含义。 ABCMeta 还处理虚拟子类注册,它在子类化时增加了少量开销(合并基类的__abstractmethods__ 集)等。从设计角度来看,ABC 是一个需要选择加入的单独功能。如果type 实现了这一点,您将不再选择加入。
    • 好的开销。对于选择加入要求(通过选择加入,我假设您是指用户的故意选择——我不是以英语为母语的人),我认为定义抽象基类的意图从抽象的存在中已经很清楚了方法。对我来说感觉不是很DRY(不要重复自己),更像是 WET(所有内容都写两次)解决方案。
    【解决方案2】:

    正如@MartijnPieters 所写,您不需要为 Python 做任何特别的事情,但 PyCharm 会发出警告:

    类 InstrumentName 必须实现所有抽象方法

    抑制该警告的一种方法:

    import abc
    
    class Primitive(abc.ABC):
        @abc.abstractmethod
        def foo(self):
            pass
    
    # noinspection PyAbstractClass
    class InstrumentName(Primitive):
        def is_tuba(self):
            return False
    

    另一种方式:

    ...
    
    class InstrumentName(Primitive, metaclass=abc.ABCMeta):
        def is_tuba(self):
            return False
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-06-16
      • 1970-01-01
      • 2017-01-10
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多