与其将其视为“虚拟函数”,不如将其视为“duck类型”的一个示例。在这个表达中:
self.print_hello()
我们只需访问
print_hello
属性
self
(不管是什么),然后叫它。如果没有这样的属性,则
AttributeError
在运行时引发。如果属性不可调用,则
TypeError
她长大了。这就是全部。没有对这类问题做出任何假设
自己
--我们只是让它“像鸭子一样呱呱叫”,看看它能不能。
duck类型的危险在于,如果你实例化一个
parent_print
打电话
print_word
在这方面,它将失败:
abstract_print = parent_print()
abstract_print.print_word()
# raises AttributeError: 'parent_print' object has no attribute 'print_hello'
Python确实支持静态类型声明和抽象类的概念,这可以帮助您避免错误。例如,如果我们运行静态类型检查器(
mypy
)在您的代码中,我们将得到一个错误:
test.py:4: error: "parent_print" has no attribute "print_hello"
这是完全正确的——从静态类型的角度来看,调用
打印你好
因为我们还没有确定这一切
家长打印
实例具有这样的属性。
为了解决这个问题,我们可以宣布
打印你好
作为一种抽象方法(为了培养良好习惯,我还将清理名称以匹配标准Python约定):
from abc import ABC, abstractmethod
class ParentPrint(ABC):
@abstractmethod
def print_hello(self) -> None: ...
def print_word(self) -> None:
self.print_hello()
class ChildPrint(ParentPrint):
def print_hello(self) -> None:
print('Hello')
basic_print = ChildPrint()
basic_print.print_word()
现在代码类型检查没有问题。
这个
@abstractmethod
decorator还指出该类是抽象的(“纯虚拟的”),无法实例化。如果我们试图创造一个
ParentPrint
或
任何
它的子类没有提供抽象方法的实现,我们得到一个错误,
二者都
静态地从
麦皮
在运行时以
打字错误
在您尝试实例化对象时(甚至在您尝试调用抽象方法之前),会立即引发该问题:
abstract_print = ParentPrint()
# raises error: Cannot instantiate abstract class "ParentPrint" with abstract attribute "print_hello"