首页 > 解决方案 > 在 python3 中正确键入返回 self 的函数

问题描述

假设我有以下代码....

from __future__ import annotations
from typing import Any, TypeVar, Type
from typing_extensions import Literal

_T = TypeVar("_T")

class A:

    @classmethod
    def constructor(cls: Type[_T]) -> _T:
        return cls()

    def __enter__(self) -> A:
        return self

    def __exit__(self, *args: Any, **kwargs: Any) -> Literal[False]:
        return False


class B(A):
    pass


def test() -> None:
    a_instance: A = A.constructor()
    b_instance: B = B.constructor()  # Works because constructor return type is _T

    with B() as b:
        a_instance = b
        b_instance = b  # Error, Incompatible types in assignment

如果我对上面的代码运行 mypy,我会收到以下警告

» mypy test.py                               
test.py:30: error: Incompatible types in assignment (expression has type "A", variable has type "B")
Found 1 error in 1 file (checked 1 source file)

这是因为A.__enter__,( A) 的返回类型是由 继承的B,所以 mypy 认为B.__enter__也返回A。我想避免重新实现该功能只是为了更正类型提示......

class B(A):
   def __enter__(self) -> B:
      return super().__enter__()  # type: ignore

我已经解决了类方法构造函数中的类似问题,方法是使用 aTypeVar模板化类型,cls以便我以后可以使用它,但我不确定类似的技巧如何适用于非类方法。

这种情况也适用于任何其他返回的方法self

标签: python-3.xtypespython-typing

解决方案


相信我想通了...

您还需要使用 TypeVar_T来指示self. 然后你可以重新使用它_T作为返回类型。

注意,如果你想使用类的任何属性(就像我在下面做的print那样),你还需要TypeVar使用参数将 绑定到一个类bound

_T = TypeVar("_T", bound="A")

class A:
    def __init__(self) -> None:
        self.a_attr = 1

    @classmethod
    def constructor(cls: Type[_T]) -> _T:
        return cls()

    def __enter__(self: _T) -> _T:
        print(self.a_attr)
        return self

推荐阅读