在 Python 中实现抽象 类 的最佳方式
Best way to implement abstract classes in Python
在 Python 中实现抽象 classes 的最佳方法是什么?
这是我看到的主要做法:
class A(ABC):
@abstractmethod
def foo(self):
pass
但是,当您扩展 class.
时,它不会阻止调用抽象方法
在 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
然而,在实践中我很少看到后一种解决方案,即使这显然是最正确的解决方案。是否有特定原因更喜欢第一种方法而不是第二种方法?
如果您真的希望在其中一个子class 尝试调用超级class 抽象方法时引发错误,那么,是的,您应该手动引发错误。 (然后,为 raise 命令 raise NotImplementedError()
创建异常 class 的实例,即使它直接与 class 一起工作)
然而,现有的行为实际上很方便:如果你的抽象方法只包含一个 pass
,那么你可以有任意数量的子 classes 继承你的基础 class,只要至少有一个实现了抽象方法,它就会起作用。即使他们都调用 super() 等效方法,而不检查任何其他内容。
如果错误 - NotImplementedError
或任何其他错误,将在复杂的层次结构中使用 mixin 等调用,您需要在每次调用时进行检查 super
如果出现错误,则跳过它。作为记录,检查 super()
是否会命中 class 方法是有条件的抽象方法是可能的,这样:
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
都不需要担心层次结构中的任何其他 class,只做他们的事情并继续前进。
如果 A.validate 会引发,这两种方法都必须在 try: ...;except ...:pass
语句内或在奇怪的 if
块内执行 super().validate(...)
,以获得...无。
更新 - 我刚在官方文档中找到这条注释:
Note Unlike Java abstract methods, these abstract methods may have an
implementation. This implementation can be called via the super()
mechanism from the class that overrides it. This could be useful as an
end-point for a super-call in a framework that uses cooperative
multiple-inheritance.
https://docs.python.org/3/library/abc.html#abc.abstractmethod
我什至会 return 你一个私人问题,如果你能在评论中回复:我知道它在 Java 中的相关性要小得多,因为一个人不能有多重继承,所以,即使在一个大层次结构中,第一个实现抽象方法的 subclass 通常也是众所周知的。但除此之外,在一个 Java 项目中,人们可以选择各种基础具体 classes 中的一种,然后以任意顺序继续其他的,因为抽象方法提出了,那是如何解决的?
在 Python 中实现抽象 classes 的最佳方法是什么?
这是我看到的主要做法:
class A(ABC):
@abstractmethod
def foo(self):
pass
但是,当您扩展 class.
时,它不会阻止调用抽象方法在 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
然而,在实践中我很少看到后一种解决方案,即使这显然是最正确的解决方案。是否有特定原因更喜欢第一种方法而不是第二种方法?
如果您真的希望在其中一个子class 尝试调用超级class 抽象方法时引发错误,那么,是的,您应该手动引发错误。 (然后,为 raise 命令 raise NotImplementedError()
创建异常 class 的实例,即使它直接与 class 一起工作)
然而,现有的行为实际上很方便:如果你的抽象方法只包含一个 pass
,那么你可以有任意数量的子 classes 继承你的基础 class,只要至少有一个实现了抽象方法,它就会起作用。即使他们都调用 super() 等效方法,而不检查任何其他内容。
如果错误 - NotImplementedError
或任何其他错误,将在复杂的层次结构中使用 mixin 等调用,您需要在每次调用时进行检查 super
如果出现错误,则跳过它。作为记录,检查 super()
是否会命中 class 方法是有条件的抽象方法是可能的,这样:
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
都不需要担心层次结构中的任何其他 class,只做他们的事情并继续前进。
如果 A.validate 会引发,这两种方法都必须在 try: ...;except ...:pass
语句内或在奇怪的 if
块内执行 super().validate(...)
,以获得...无。
更新 - 我刚在官方文档中找到这条注释:
Note Unlike Java abstract methods, these abstract methods may have an implementation. This implementation can be called via the super() mechanism from the class that overrides it. This could be useful as an end-point for a super-call in a framework that uses cooperative multiple-inheritance. https://docs.python.org/3/library/abc.html#abc.abstractmethod
我什至会 return 你一个私人问题,如果你能在评论中回复:我知道它在 Java 中的相关性要小得多,因为一个人不能有多重继承,所以,即使在一个大层次结构中,第一个实现抽象方法的 subclass 通常也是众所周知的。但除此之外,在一个 Java 项目中,人们可以选择各种基础具体 classes 中的一种,然后以任意顺序继续其他的,因为抽象方法提出了,那是如何解决的?