簡體   English   中英

指定調用 Python 中的抽象方法的包裝器 function 的返回類型

[英]Specify return type of a wrapper function that calls an abstract method in Python

對於此示例,請考慮Solver將返回Solution的簡化場景。

我們有Solution

class Solution(ABC):
    pass


class AnalyticalSolution(Solution):
    pass


class NumericalSolution(Solution):
    def get_mesh_size(self) -> float:
        return 0.12345

Solver

class Solver(ABC):
    def solve(self, task: int) -> Solution:
        # Do some pre-processing with task
        # ...
        return self._solve(task)

    @abstractmethod
    def _solve(self, task: int) -> Solution:
        pass


class NumericalSolver(Solver):
    def _solve(self, task: int) -> NumericalSolution:
        return NumericalSolution()


class AnalyticalSolver(Solver):
    def _solve(self, task: int) -> AnalyticalSolution:
        return AnalyticalSolution()

我遇到的問題是由包裝方法solve的實現引起的,然后調用抽象方法_solve 我經常遇到這樣的情況,我想在對所有求解器都相同的solve方法中進行一些預處理,但是_solve的實際實現可能會有所不同。

如果我現在調用數值求解器並調用get_mesh_size()方法,Pylance(正確地)告訴我Solution object 沒有get_mesh_size成員。

if __name__ == "__main__":
    solver = NumericalSolver()
    solution = solver.solve(1)
    print(solution.get_mesh_size())

我知道 Pylance 只看到solve的接口,這表明返回類型是Solution object 不需要有get_mesh_size方法。 我也知道這個例子在運行時有效。

我嘗試像這樣使用TypeVar (實際上,因為 ChatGPT 建議這樣做):

class Solution(ABC):
    pass
T = TypeVar("T", bound=Solution)

然后重寫Solver class:

class Solver(ABC):
    def solve(self, task: int) -> T:
        # Do some pre-processing with task
        # ...
        return self._solve(task)

    @abstractmethod
    def _solve(self, task: int) -> T:
        pass

但是 Pylance 現在告訴我TypeVar "T" appears only once in generic function signature 所以這不是解決方案。

我如何輸入才能使用此示例?

您可以使用Generic[T]作為Solver的基礎,然后按如下方式擴展它

from abc import ABC, abstractmethod
from typing import TypeVar, Generic


class Solution(ABC):
    pass


class AnalyticalSolution(Solution):
    pass


class NumericalSolution(Solution):
    def get_mesh_size(self) -> float:
        return 0.12345


SolutionGeneric = TypeVar("SolutionGeneric", bound=Solution)


class Solver(ABC, Generic[SolutionGeneric]):
    def solve(self, task: int) -> SolutionGeneric:
        # Do some pre-processing with task
        # ...
        return self._solve(task)

    @abstractmethod
    def _solve(self, task: int) -> SolutionGeneric:
        pass


class NumericalSolver(Solver[NumericalSolution]):
    def _solve(self, task: int) -> NumericalSolution:
        return NumericalSolution()


class AnalyticalSolver(Solver):
    def _solve(self, task: int) -> AnalyticalSolution:
        return AnalyticalSolution()


if __name__ == "__main__":
    solver = NumericalSolver()
    solution = solver.solve(1)
    print(solution.get_mesh_size())

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM