Python重写子类中方法返回的类型提示,而不重新定义方法签名

2024-04-18 05:13:57 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个基类,在方法的返回上有一个类型提示float

在子类中,在不重新定义签名的情况下,我能否以某种方式将方法返回的类型提示更新为int


示例代码

#!/usr/bin/env python3.6


class SomeClass:
    """This class's some_method will return float."""

    RET_TYPE = float

    def some_method(self, some_input: str) -> float:
        return self.RET_TYPE(some_input)


class SomeChildClass(SomeClass):
    """This class's some_method will return int."""

    RET_TYPE = int


if __name__ == "__main__":
    ret: int = SomeChildClass().some_method("42"). # 
    ret2: float = SomeChildClass().some_method("42")

我的IDE抱怨类型不匹配:

pycharm expected type float

这是因为我的IDE仍在使用来自SomeClass.some_method的类型提示


研究

我认为解决方法可能是使用泛型,但我不确定是否有更简单的方法

Python: how to override type hint on an instance attribute in a subclass?

建议可能使用instance variable annotations,但我不确定如何对返回类型执行该操作


Tags: 方法self类型returntypesomefloatthis
3条回答

好的,所以我能够把@AntonPomieshcheko和@KevinLanguasco的答案结合起来,提出一个解决方案,其中:

  • 我的IDE(PyCharm)可以正确推断返回类型
  • mypy报告类型是否不匹配
  • 即使类型提示指示不匹配,在运行时也不会出错

这正是我想要的行为。非常感谢大家:)

#!/usr/bin/env python3

from typing import TypeVar, Generic, ClassVar, Callable


T = TypeVar("T", float, int)  # types supported


class SomeBaseClass(Generic[T]):
    """This base class's some_method will return a supported type."""

    RET_TYPE: ClassVar[Callable]

    def some_method(self, some_input: str) -> T:
        return self.RET_TYPE(some_input)


class SomeChildClass1(SomeBaseClass[float]):
    """This child class's some_method will return a float."""

    RET_TYPE = float


class SomeChildClass2(SomeBaseClass[int]):
    """This child class's some_method will return an int."""

    RET_TYPE = int


class SomeChildClass3(SomeBaseClass[complex]):
    """This child class's some_method will return a complex."""

    RET_TYPE = complex


if __name__ == "__main__":
    some_class_1_ret: float = SomeChildClass1().some_method("42")
    some_class_2_ret: int = SomeChildClass2().some_method("42")

    # PyCharm can infer this return is a complex.  However, running mypy on
    # this will report (this is desirable to me):
    # error: Value of type variable "T" of "SomeBaseClass" cannot be "complex"
    some_class_3_ret = SomeChildClass3().some_method("42")

    print(
        f"some_class_1_ret = {some_class_1_ret} of type {type(some_class_1_ret)}\n"
        f"some_class_2_ret = {some_class_2_ret} of type {type(some_class_2_ret)}\n"
        f"some_class_3_ret = {some_class_3_ret} of type {type(some_class_3_ret)}\n"
    )

以下代码在PyCharm上运行良好。我添加了complex案例以使其更清楚

我基本上将该方法提取到一个泛型类,然后将其用作每个子类的混入。请格外小心使用,因为它似乎不太标准

from typing import ClassVar, Generic, TypeVar, Callable


S = TypeVar('S', bound=complex)


class SomeMethodImplementor(Generic[S]):
    RET_TYPE: ClassVar[Callable]

    def some_method(self, some_input: str) -> S:
        return self.__class__.RET_TYPE(some_input)


class SomeClass(SomeMethodImplementor[complex]):
    RET_TYPE = complex


class SomeChildClass(SomeClass, SomeMethodImplementor[float]):
    RET_TYPE = float


class OtherChildClass(SomeChildClass, SomeMethodImplementor[int]):
    RET_TYPE = int


if __name__ == "__main__":
    ret: complex = SomeClass().some_method("42")
    ret2: float = SomeChildClass().some_method("42")
    ret3: int = OtherChildClass().some_method("42")
    print(ret, type(ret), ret2, type(ret2), ret3, type(ret3))

例如,如果将ret2: float更改为ret2: int,它将正确显示类型错误

不幸的是,mypy在这种情况下显示错误(版本0.770)

otherhint.py:20: error: Incompatible types in assignment (expression has type "Type[float]", base class "SomeClass" defined the type as "Type[complex]")
otherhint.py:24: error: Incompatible types in assignment (expression has type "Type[int]", base class "SomeClass" defined the type as "Type[complex]")
otherhint.py:29: error: Incompatible types in assignment (expression has type "complex", variable has type "float")
otherhint.py:30: error: Incompatible types in assignment (expression has type "complex", variable has type "int")

第一个错误可以通过书写“修复”

    RET_TYPE: ClassVar[Callable] = int

对于每个子类。现在,错误减少到

otherhint.py:29: error: Incompatible types in assignment (expression has type "complex", variable has type "float")
otherhint.py:30: error: Incompatible types in assignment (expression has type "complex", variable has type "int")

这与我们想要的正好相反,但如果你只关心PyCharm,那就没什么关系了

你可以用这样的东西:

from typing import TypeVar, Generic


T = TypeVar('T', float, int) # types you support


class SomeClass(Generic[T]):
    """This class's some_method will return float."""

    RET_TYPE = float

    def some_method(self, some_input: str) -> T:
        return self.RET_TYPE(some_input)


class SomeChildClass(SomeClass[int]):
    """This class's some_method will return int."""

    RET_TYPE = int


if __name__ == "__main__":
    ret: int = SomeChildClass().some_method("42")
    ret2: float = SomeChildClass().some_method("42")

但有一个问题。我不知道该怎么解决。对于SomeChildClass方法,某些方法IDE将显示通用提示。至少pycharm(我想你应该是这样)没有将其显示为错误

相关问题 更多 >