【问题标题】:Specify return type of a wrapper function that calls an abstract method in Python指定在 Python 中调用抽象方法的包装函数的返回类型
【发布时间】:2023-01-08 02:18:03
【问题描述】:

对于此示例,请考虑简化的场景,其中 Solver 将返回 Solution

我们有Solutions:

class Solution(ABC):
    pass


class AnalyticalSolution(Solution):
    pass


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

还有Solvers:

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 对象没有 get_mesh_sizemember。

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

我知道 Pylance 只看到 solve 的接口,这表明返回类型是一个 Solution 对象,不需要 get_mesh_size 方法。 我也知道这个例子在运行时有效。

我试着像这样使用TypeVar(实际上,因为 ChatGPT 建议这样做):

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

然后重写Solver类:

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。所以这不是解决方案。

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

【问题讨论】:

    标签: python object abstract-class type-hinting


    【解决方案1】:

    您可以使用 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())
    

    【讨论】:

    • 这就像一个魅力,谢谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    • 2020-10-02
    • 1970-01-01
    • 2010-12-13
    • 2017-05-02
    • 2017-02-25
    相关资源
    最近更新 更多