简体   繁体   English

为什么要在Python中调用抽象类方法?

[英]Why can I call an abstract class method in Python?

If I define an abstract class with an abstract method: 如果我使用抽象方法定义抽象类:

import abc


class A(abc.ABC):

    @classmethod
    @abc.abstractmethod
    def foo(cls):
        pass

I can't instantiate it (as expected): 我无法实例化它(如预期):

>>> A()
TypeError: Can't instantiate abstract class A with abstract methods foo

But I can call its abstract method with no errors. 但是我可以正确地调用它的抽象方法。

>> A.foo()

Is this behavior documented somewhere ? 此行为记录在某处吗?

Tested on Python 3.6 and 3.7. 在Python 3.6和3.7上测试。

foo is a classmethod and by property a class method can be called directly by the class itself. foo是一个classmethod和由属性一个类的方法,可以由类本身直接调用。
By doing 通过做

In [3]: A.foo()  

you are not instantiating the class A , rather you are just calling the function foo on class A . 您不是在实例化类A ,而是在类A上调用函数foo

Nothing is explicit about that. 没有什么是明确的。

Simply the documentation of a the abstractmethod decorator says: 简单地说, abstractmethod装饰器的文档说:

A class that has a metaclass derived from ABCMeta cannot be instantiated unless all of its abstract methods and properties are overridden. 除非实例化了所有抽象方法和属性,否则无法实例化具有从ABCMeta派生的元类的类。

And PEP 3119 says: PEP 3119说:

A class containing at least one method declared with this decorator that hasn't been overridden yet cannot be instantiated. 包含至少一个尚未使用此装饰器声明的方法的类,无法实例化。

and later 然后

Implementation : The @abstractmethod decorator sets the function attribute __isabstractmethod__ to the value True. 实现@abstractmethod装饰器将函数属性__isabstractmethod__设置为True。 The ABCMeta.__new__ method computes the type attribute __abstractmethods__ as the set of all method names that have an __isabstractmethod__ attribute whose value is true. ABCMeta.__new__方法将类型属性__abstractmethods__计算为所有具有__isabstractmethod__属性值为true的方法名称的集合。 It does this by combining the __abstractmethods__ attributes of the base classes, adding the names of all methods in the new class dict that have a true __isabstractmethod__ attribute, and removing the names of all methods in the new class dict that don't have a true __isabstractmethod__ attribute. 它通过组合基类的__abstractmethods__属性,添加新类dict中具有真实__isabstractmethod__属性的所有方法的名称以及删除新类dict中不具有真实属性的所有方法的名称来实现此目的。 __isabstractmethod__属性。 If the resulting __abstractmethods__ set is non-empty, the class is considered abstract, and attempts to instantiate it will raise TypeError . 如果生成的__abstractmethods__集为非空,则该类被视为抽象类,并且尝试实例化该类将引发TypeError

My interpretation of the implementation part is that @abstractmethod never prevents the method to be called but only say that that class cannot be instantiated and that a subclass will still be abstract unless it overrides all of its abstract methods. 我对实现部分的解释是, @abstractmethod永远不会阻止调用该方法,而只是说该类无法实例化,并且子类将仍然是抽象的,除非它覆盖了其所有抽象方法。

So I would not say that it is by design , but it is at least an assumed side effect. 因此,我不会说这是设计使然 ,但这至少是假定的副作用。

Subclassing abc.ABC indicates that class A cannot be instantiated directly. 子类abc.ABC指示不能直接实例化类A

The @abc.abstractmethod decorator forces a check on any subclass of A during type/name resolution. @abc.abstractmethod装饰器在类型/名称解析期间强制检查A任何子类。 If class subofA(A): does not implement the decorated method, then an exception is raised. 如果class subofA(A):未实现修饰的方法,则引发异常。

Once type/name resolution is passed, the abstractmethod decorator does not prevent you from calling the method. 一旦通过类型/名称解析,则abstractmethod装饰器不会阻止您调用该方法。 After all, you aren't able to call the method without an instance, unless it is a class method. 毕竟,没有实例就无法调用该方法,除非它是一个类方法。

By decorating foo with both @classmethod and @abstractmethod you, the developer, specify that A.foo() is safe to call without instantiating the class, but that anyone who subclasses A must implement an overriding method to preserve that behaviour. 通过使用@classmethod@abstractmethod装饰foo ,开发人员可以指定A.foo()可以安全调用而无需实例化该类,但是子类A任何人都必须实现重写方法以保留该行为。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM