Python 3.4+;

Python 3.4+;,python,python-3.x,abstract-class,Python,Python 3.x,Abstract Class,以一个常见的车辆继承为例,vehicle和Car是ABC,后者从前者继承。然后我们就有了例如福特野马,它不是抽象的,应该继承自汽车 所以,我们有 class Vehicle(ABC): @abstractmethod def abstract_vehicle_method(self): pass 想必这一切都很好。但是,对于Car类,我不确定它是否应该仅从Vehicle继承,还是从Vehicle和ABC继承,如果是,以什么顺序继承?此外,我想强制abstrac

以一个常见的车辆继承为例,
vehicle
Car
是ABC,后者从前者继承。然后我们就有了例如
福特野马
,它不是抽象的,应该继承自
汽车

所以,我们有

class Vehicle(ABC):

    @abstractmethod
    def abstract_vehicle_method(self):
        pass
想必这一切都很好。但是,对于
Car
类,我不确定它是否应该仅从
Vehicle
继承,还是从
Vehicle
ABC
继承,如果是,以什么顺序继承?此外,我想强制
abstract\u vehicle\u method()
FordMustang
和所有此类非抽象类中定义,那么我应该重复
abstract\u vehicle\u method
中的
abstract\u vehicle\u method
定义,还是继承会解决这个问题

要列举选项,请执行以下操作:

应该是吗

class Car(Vehicle):
    [...]
class Vehicle(ABC):

    @abstractmethod
    def abstract_vehicle_method(self):
        pass

class Car(Vehicle):

    @abstractmethod
    def abstract_vehicle_method(self):
        pass

    # Some car specific defs here

class FordMustang(Car):

    def abstract_vehicle_method(self):
        # Concrete def here

(假设第一个是正确的简单性)应该是

class Car(Vehicle):
    [...]
class Vehicle(ABC):

    @abstractmethod
    def abstract_vehicle_method(self):
        pass

class Car(Vehicle):

    @abstractmethod
    def abstract_vehicle_method(self):
        pass

    # Some car specific defs here

class FordMustang(Car):

    def abstract_vehicle_method(self):
        # Concrete def here
或者只是

class Vehicle(ABC):

    @abstractmethod
    def abstract_vehicle_method(self):
        pass

class Car(Vehicle):

    # Some car specific defs here

class FordMustang(Car):

    def abstract_vehicle_method(self):
        # Concrete def here

您可以直接从
车辆继承
;使
车辆
成为“抽象”的元类将与它一起继承。对于这些子类,您不需要混合使用
ABC

您也不需要重新定义该方法。它也是继承的,还有它的“抽象性”

在引擎盖下,元类跟踪哪些属性是“抽象的”;只要存在实例,该类就不能用于创建实例。您可以添加更多的抽象方法,或者通过为同一名称提供不同的属性,从集合中删除抽象方法

具体示例的演示:

>>> from abc import ABC, abstractmethod
>>> class Vehicle(ABC):
...     @abstractmethod
...     def abstract_vehicle_method(self):
...         pass
...
>>> type(Vehicle)  # it's an abstract class
<class 'abc.ABCMeta'>
>>> Vehicle.__abstractmethods__  # this set determines what is still abstract
frozenset({'abstract_vehicle_method'})
>>> class Car(Vehicle):
...     pass
...
>>> type(Car)  # still an abstract class
<class 'abc.ABCMeta'>
>>> Car.__abstractmethods__  # still has abstract methods, incl. inherited methods
frozenset({'abstract_vehicle_method'})
>>> class FordMustang(Car):
...     def abstract_vehicle_method(self):
...         pass
...
>>> type(FordMustang)  # still an abstract class
<class 'abc.ABCMeta'>
>>> FordMustang.__abstractmethods__  # but with no abstract methods left
frozenset()
>>> FordMustang()  # so we can create an instance
<__main__.FordMustang object at 0x106054f98>
>>从abc导入abc,abstractmethod
>>>车辆等级(ABC):
...     @抽象方法
...     def abstract_vehicle_方法(自):
...         通过
...
>>>type(Vehicle)#它是一个抽象类
>>>车辆。_uAbstractMethods_#此集合确定什么仍然是抽象的
冻结集({'abstract\u vehicle\u method'})
>>>车辆类别:
...     通过
...
>>>type(Car)#仍然是一个抽象类
>>>Car.uu abstractmethods_uuu#仍然有抽象方法,包括继承的方法
冻结集({'abstract\u vehicle\u method'})
>>>野马(汽车)的等级:
...     def abstract_vehicle_方法(自):
...         通过
...
>>>类型(FordMustang)#仍然是一个抽象类
>>>FordMustang.uu abstractmethods_uu35;但没有留下任何抽象方法
frozenset()
>>>FordMustang()#因此我们可以创建一个实例

这完全取决于您想对这些类执行什么操作。你想让Car成为一个抽象类还是想让它用来实例化对象?@OlivierMelançon:不是为了回答这里提到的问题,它不是。我很好奇在实例化抽象类时,TypeError是从哪里产生的。它似乎不是来自abc模块中的任何地方。你知道是什么引起的吗?@OlivierMelançon:这是由
对象处理的;看见对于设置了
Py\u TPFLAGS\u is\u ABSTRACT
的任何类,都会引发异常。当
ABCMeta将
\uuuuuuu abstractmethods\uuuuu
设置为非空值时,将设置该标志。谢谢。让我震惊的是,PyCharm认为这是“错误的”,尽管这是有意义的,也是最优雅的方法。对我来说,它给出了一个“类车必须实现所有抽象方法”的代码检查错误。也许我会把它作为一张票向他们提出,让他们去修正,尽管实际上我认为IDE没有办法区分意图的不同,也无法确定某个继承的类是否应该是抽象的,或者用户是否只是忘记了在非抽象类中实现抽象方法。不过,当我混入
ABC
时,它也会触发此错误。见图。@P.Lau:这肯定是PyCharm的一个假设,即不能从基类创建抽象类的层次结构,这是错误的。