[英]How to create a class with an abstract `__init__` method?
I want to create an abstract base class in Python where part of the contract is how instances can be created.我想在 Python 中创建一个抽象基类,其中合同的一部分是如何创建实例。 The different concrete implementations represent various algorithms that can be used interchangeably.
不同的具体实现代表了可以互换使用的各种算法。 Below is a simplified example ( usual disclaimer - the real use-case is more complex):
下面是一个简化的示例(通常的免责声明- 实际用例更复杂):
from abc import ABC, abstractmethod
from typing import Type
class AbstractAlgorithm(ABC):
@abstractmethod
def __init__(self, param: int):
pass
@abstractmethod
def get_result(self) -> int:
pass
class ConcreteAlgorithm(AbstractAlgorithm):
def __init__(self, param: int):
self._param = param
def get_result(self) -> int:
return self._param * 2
def use_algorithm(algorithm: Type[AbstractAlgorithm]) -> int:
a = algorithm(10)
return a.get_result()
The above works, but has the drawback that I can't call super().__init__(...)
in ConcreteAlgorithm.__init__
, which might break certain inheritance scenarios, I think (correct me if I'm wrong here, but calling super
is important for multiple inheritance, right?).上述方法有效,但有一个缺点是我不能在
ConcreteAlgorithm.__init__
中调用super().__init__(...)
,这可能会破坏某些继承场景,我认为(如果我在这里错了,请纠正我,但调用super
对于多重继承很重要,对吧?)。 (Strictly speaking __init__
can be called, but with the same signature as the subclass __init__
, which doesn't make sense). (严格来说
__init__
可以被调用,但与子类__init__
具有相同的签名,这没有意义)。
Python classes are callables, so I could also express it like this: Python 类是可调用的,所以我也可以这样表达:
from abc import ABC, abstractmethod
from typing import Callable
class AbstractAlgorithm(ABC):
@abstractmethod
def get_result(self) -> int:
pass
class ConcreteAlgorithm(AbstractAlgorithm):
def __init__(self, param: int):
self._param = param
def get_result(self) -> int:
return self._param * 2
def use_algorithm(algorithm: Callable[[int], AbstractAlgorithm]) -> int:
a = algorithm(10)
return a.get_result()
print(use_algorithm(ConcreteAlgorithm))
This works and doesn't have the drawback mentioned above, but I do like having the __init__
-signature in the abstract base class for documentation purposes.这可行并且没有上面提到的缺点,但我确实喜欢在抽象基类中使用
__init__
-signature 以用于文档目的。
Finally, it is possible to have abstract classmethods, so this approach works as well:最后,可以有抽象类方法,所以这种方法也有效:
from abc import ABC, abstractmethod
from typing import Type
class AbstractAlgorithm(ABC):
@classmethod
@abstractmethod
def initialize(cls, param: int) -> "AbstractAlgorithm":
pass
@abstractmethod
def get_result(self) -> int:
pass
class ConcreteAlgorithm(AbstractAlgorithm):
@classmethod
def initialize(cls, param: int) -> "ConcreteAlgorithm":
return cls(param)
def __init__(self, param: int):
self._param = param
def get_result(self) -> int:
return self._param * 2
def use_algorithm(algorithm: Type[AbstractAlgorithm]) -> int:
a = algorithm.initialize(10)
return a.get_result()
print(use_algorithm(ConcreteAlgorithm))
This works, but I lose the nice property of using algorithm
like a callable (it's just more flexible, in case someone actually wants to drop in a function, for example to decide which algorithm to use based on certain parameter values).这行得通,但是我失去了使用诸如可调用
algorithm
之类的算法的好特性(它更灵活,以防有人真的想加入一个函数,例如根据某些参数值决定使用哪种算法)。
So, is there an approach that satisfies all three requirements:那么,是否有一种方法可以满足所有三个要求:
__init__
.__init__
。Strictly speaking
__init__
can be called, but with the same signature as the subclass__init__
, which doesn't make sense.严格来说
__init__
可以被调用,但是与子类__init__
具有相同的签名,这没有意义。
No, it makes perfect sense.不,这很有意义。
You're prescribing the signature because you require each child class to implement it exactly.您正在规定签名,因为您要求每个子类都准确地实现它。 That means you need to call it exactly like that as well.
这意味着您也需要完全这样称呼它。 Each child class needs to call its
super().__init__
exactly according to the abstract definition, passing all defined parameters along.每个子类都需要完全根据抽象定义调用它的
super().__init__
,并传递所有定义的参数。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.