正确的typehint函数在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__继承了AB)的返回类型,因此mypy认为B.__enter__也返回了A。我想避免重新实现该功能,只是为了纠正typehint ...

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

我通过使用TypeVar来模板化cls的类型来解决方法构造函数中的类似问题,以便稍后使用,但是我不确定如何使用类似的技巧可能适用于非类方法

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

解决方法

相信我知道了...

您还需要使用TypeVar _T来指示self的类型。然后,您可以重复使用与返回类型相同的_T

请注意,如果您想使用该类的任何属性(如我在下面的print中所做的那样),则还需要使用TypeVarbound绑定到一个类上论点。

_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