python-3.x - 在 Python 中实现抽象类的最佳方法
问题描述
在 Python 中实现抽象类的最佳方法是什么?
这是我见过的主要方法:
class A(ABC):
@abstractmethod
def foo(self):
pass
但是,它不会阻止您在扩展该类时调用抽象方法。
在 Java 中,如果你尝试做类似的事情,你会得到一个错误,但在 Python 中不会:
class B(A):
def foo(self):
super().foo()
B().foo() # does not raise an error
为了复制相同的 Java 行为,您可以采用这种方法:
class A(ABC):
@abstractmethod
def foo(self):
raise NotImplementedError
然而,在实践中我很少看到后一种解决方案,即使显然是最正确的解决方案。是否有特定的理由更喜欢第一种方法而不是第二种方法?
解决方案
如果您真的希望在子类之一尝试调用超类抽象方法时引发错误,那么,是的,您应该手动引发错误。(然后,为 raise 命令创建一个 Exception 类的实例,raise NotImplementedError()
即使它直接与该类一起使用)
但是,现有的行为实际上很方便:如果您的 abstractmethod 只包含 a pass
,那么您可以让任意数量的子类继承您的基类,并且只要至少有一个实现 abstractmethod,它就可以工作。即使它们都调用 super() 等效方法,而不检查其他任何内容。
如果在复杂的层次结构中调用错误NotImplementedError
或任何其他错误,使用 mixins 等,您需要在每次调用时检查super
是否引发了错误,只是为了跳过它。为了记录,检查是否super()
会命中带有条件的抽象方法的类是可能的,这样:
if not getattr(super().foo, "__isabstractmethod__", False):
super().foo(...)
因为如果你到达一个方法的层次结构的基础,你想要什么是让它什么都不做,如果什么都没发生,那就很简单了!
我的意思是,检查这个:
class A(abc.ABC):
@abstractmethod
def validate(self, **kwargs):
pass
class B(A):
def validate(self, *, first_arg_for_B, second_arg_for_B=None, **kwargs):
super().validate(**kwargs)
# perform validation:
...
class C(A)
def validate(self, *, first_arg_for_C **kwargs):
super().validate(**kwargs)
# perform validation:
...
class Final(B, C):
...
既不需要B.validate
也不C.validate
需要担心层次结构中的任何其他类,只需做他们的事情并传递。如果 A.validate 会引发,那么这两种方法都必须super().validate(...)
在try: ...;except ...:pass
语句内或奇怪的if
块内执行,以获得......什么都没有。
更新- 我刚刚在官方文档上找到了这个注释:
注意与 Java 抽象方法不同,这些抽象方法可能有一个实现。可以通过覆盖它的类中的 super() 机制调用此实现。这对于在使用协作多重继承的框架中作为超级调用的端点很有用。 https://docs.python.org/3/library/abc.html#abc.abstractmethod
如果您可以在评论中回复,我什至会回复您一个个人问题:我知道它在 Java 中的相关性要小得多,因为 Java 不能有多重继承,所以,即使在大层次结构中,第一个实现抽象的子类方法通常是众所周知的。但除此之外,在 Java 项目中,可以从各种 Base 具体类中选择一个,然后以任意顺序处理其他类,因为抽象方法引发了,如何解决?
推荐阅读
- r - 查找每个工作日的平均事件
- python - pyLDAvis 可视化中未显示的前 30 个最相关的术语
- sap-cloud-platform - 如何使用 SAP CPI 中的集成流验证 JWT 令牌?
- android - 需要但未调用:navController.navigate(
); 实际上,与此模拟的交互为零 - sql - 显示带有所需前缀的表
- html - 单击按钮时引导模式不起作用
- react-native - 如何在 React Native (expo) 中更快地检测键盘状态?
- tableau-desktop - 如何在表格过滤器中添加前面具有 Action() 的字段
- excel - 将 sheetpathrange 字符串转换为范围的列表值
- java - 将一个列表复制到另一个列表而不丢失原始列表的运行时类型