Tom*_*ons 2 python typing type-hinting
我想创建一个像这里一样的工厂方法。
class A:
...
class B(A):
def f(self):
...
class C:
...
def factory(cls):
return cls()
Run Code Online (Sandbox Code Playgroud)
但我想添加一些类型提示,有两个要求:
A允许 的子类作为 的参数factory。B传递时,正确检测到factory(B)是 的实例B,即。factory(B).f()允许,而factory(A).f()不允许。Type从模块中使用typing。
from typing import Type
class A:
...
class B(A):
def f(self):
...
class C:
...
def factory(cls: Type[A]):
return cls()
factory(A) # Ok
factory(B) # Ok
factory(C) # Fail
factory(A).f() # Fail
factory(B).f() # Fail -- Wrong!
Run Code Online (Sandbox Code Playgroud)
这个正确地检测到C不应作为 的参数传递factory。然而,factory(B).f()类型检查器不允许。
使用TypeVar。
from typing import TypeVar, Type
T = TypeVar('T')
class A:
...
class B(A):
def f(self):
...
class C:
...
def factory(cls: Type[T]) -> T:
return cls()
factory(A) # Ok
factory(B) # Ok
factory(C) # Ok -- Wrong!
factory(A).f() # Fail
factory(B).f() # Ok
Run Code Online (Sandbox Code Playgroud)
可以很好地推断,这factory(B).f()是可以的,而factory(A).f()不是。然而,泛型是没有限制的,即。工厂(C)也可以。
添加约束到T.
from typing import TypeVar, Type
class A:
...
class B(A):
def f(self):
...
class D(A):
...
class C:
...
T = TypeVar('T', A)
def factory(cls: Type[T]) -> T:
return cls()
factory(A) # Ok
factory(B) # Ok
factory(C) # Fail
factory(A).f() # Fail
factory(B).f() # Ok
Run Code Online (Sandbox Code Playgroud)
这看起来很有希望,至少 PyCharm 可以正确处理所有情况。但对于实际使用来说,这个解决方案实际上是最糟糕的 -A single constraint is not allowed尽管出现了错误,但尚不清楚原因。在 PEP 484 中,只有一行简短的内容:“应该至少有两个约束,如果有的话;不允许指定单个约束。”
有什么好的解决办法吗?我只有添加一个“虚拟”类_A( 的空白子类)之类的东西A,并将其作为另一个约束来拥有类似的东西。
_A = NewType('_A', A)
T = TypeVar('T', A, _A)
def factory(cls: Type[T]) -> T:
return cls()
Run Code Online (Sandbox Code Playgroud)
但我真的不认为这是一个很好的解决方案。
先感谢您!
将 aTypeVar与 a 一起使用bound似乎有效:
from typing import Type, TypeVar
class A:
...
class B(A):
def f(self):
...
class C:
...
AnyA = TypeVar("AnyA", bound=A)
def factory(cls: Type[AnyA]) -> AnyA:
return cls()
factory(A).f() # error: "A" has no attribute "f"
factory(B).f() # ok!
factory(C) # error: Value of type variable "AnyA" of "factory" cannot be "C"
Run Code Online (Sandbox Code Playgroud)