问题描述
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
。我想避免重新实现该功能,只是为了纠正typehint ...
class B(A):
def __enter__(self) -> B:
return super().__enter__() # type: ignore
我通过使用TypeVar
来模板化cls
的类型来解决类方法构造函数中的类似问题,以便稍后使用,但是我不确定如何使用类似的技巧可能适用于非类方法。
这种情况也适用于其他任何返回self
的方法。
解决方法
相信我知道了...
您还需要使用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