Python / MyPy:如何注释一个可以返回几种不同类型对象之一的方法?

时间:2017-11-05 07:50:55

标签: python python-3.x oop types mypy

我应该如何注释可以返回多种不同类型对象的方法的返回类型?

具体来说,这是我遇到问题的方法:

def _bin_factory(self) -> Any:
    """
    Returns a bin with the specificed algorithm,
    heuristic, and dimensions
    """
    if self.algorithm == 'guillotine':
        return guillotine.Guillotine(self.bin_width, self.bin_height, self.rotation,
                                     self.rectangle_merge, self.split_heuristic)
    elif self.algorithm == 'shelf':
        return shelf.Sheet(self.bin_width, self.bin_height, self.rotation, self.wastemap)
    elif self.algorithm == 'maximal_rectangle':
        return maximal_rectangles.MaximalRectangle(self.bin_width, self.bin_height, self.rotation)
    raise ValueError('Error: No such Algorithm')

我试过了Union[shelf.Sheet, guillotine.Guillotine, maximal_rectangles.MaximalRectangle],但MyPy给了我很多错误,我稍后会在代码中使用_bin_factory方法。这些错误似乎围绕着这样一个事实,即联盟中的所有三种对象类型都有不同的属性。

1 个答案:

答案 0 :(得分:1)

Here's a solution using typing.Generic

from typing import Generic, TypeVar

T = TypeVar('T', 'Guillotine', 'Sheet', 'MaximalRectangle')

class Guillotine:
    pass

class Sheet:
    pass

class MaximalRectangle:
    pass

class Algo(Generic[T]):
    def __init__(self, algorithm: str) -> None:
        self.algorithm = algorithm

    def _bin_factory(self) -> T:
        """
        Returns a bin with the specificed algorithm,
        heuristic, and dimensions
        """
        if self.algorithm == 'guillotine':
            return Guillotine()  # type: ignore
        elif self.algorithm == 'shelf':
            return Sheet()  # type: ignore
        elif self.algorithm == 'maximal_rectangle':
            return MaximalRectangle()  # type: ignore
        raise ValueError('Error: No such Algorithm')


algo: Algo[Guillotine] = Algo('guillotine')
reveal_type(algo._bin_factory())

Alternately, if you're willing to modify your approach a bit more, you can provide a cleaner API:

from typing import Generic, TypeVar, Type

T = TypeVar('T', 'Guillotine', 'Sheet', 'MaximalRectangle')

class Guillotine:
    pass

class Sheet:
    pass

class MaximalRectangle:
    pass

class Algo(Generic[T]):
    def __init__(self, algorithm: Type[T]) -> None:
        self.algorithm = algorithm  # type: Type[T]

    def _bin_factory(self) -> T:
        """
        Returns a bin with the specificed algorithm,
        heuristic, and dimensions
        """
        if self.algorithm is Guillotine:
            # handle custom arguments:
            return self.algorithm()
        elif self.algorithm is Sheet:
            # handle custom arguments:
            return self.algorithm()
        elif self.algorithm is MaximalRectangle:
            # handle custom arguments:
            return self.algorithm()
        raise ValueError('Error: No such Algorithm')

algo = Algo(Guillotine)
reveal_type(algo._bin_factory())