[英]Error "__init__ method from base class is not called" for an abstract class
[英]How to create a class with an abstract `__init__` method?
我想在 Python 中創建一個抽象基類,其中合同的一部分是如何創建實例。 不同的具體實現代表了可以互換使用的各種算法。 下面是一個簡化的示例(通常的免責聲明- 實際用例更復雜):
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()
上述方法有效,但有一個缺點是我不能在ConcreteAlgorithm.__init__
中調用super().__init__(...)
,這可能會破壞某些繼承場景,我認為(如果我在這里錯了,請糾正我,但調用super
對於多重繼承很重要,對吧?)。 (嚴格來說__init__
可以被調用,但與子類__init__
具有相同的簽名,這沒有意義)。
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))
這可行並且沒有上面提到的缺點,但我確實喜歡在抽象基類中使用__init__
-signature 以用於文檔目的。
最后,可以有抽象類方法,所以這種方法也有效:
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))
這行得通,但是我失去了使用諸如可調用algorithm
之類的算法的好特性(它更靈活,以防有人真的想加入一個函數,例如根據某些參數值決定使用哪種算法)。
那么,是否有一種方法可以滿足所有三個要求:
__init__
。嚴格來說
__init__
可以被調用,但是與子類__init__
具有相同的簽名,這沒有意義。
不,這很有意義。
您正在規定簽名,因為您要求每個子類都准確地實現它。 這意味着您也需要完全這樣稱呼它。 每個子類都需要完全根據抽象定義調用它的super().__init__
,並傳遞所有定義的參數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.