Mar*_*man 5 python python-typing
我想类型提示一个方法,该方法可能会接收对 A 或 A 的子类进行操作的 Callable:
def do(f: Callable[[A], None])
Run Code Online (Sandbox Code Playgroud)
我也尝试过:
def do(f: Callable[[typing.Type[A]], None])
Run Code Online (Sandbox Code Playgroud)
完整的虚拟示例如下所示:
class A:
n = 1
class B(A):
n = 2
def something_a(x: A):
print(x.n)
def something_b(x: B):
print(x.n)
def do(f: Callable[[A], None]):
f(B())
do(something_a) # ok
do(something_b) # PyCharm type check warnning
Run Code Online (Sandbox Code Playgroud)
正如宫城先生指出的那样 - 类型检查警告是正确的。
B继承自A,因此something_a(x: A)可以同时接受A和B,而something_b(x: B)只能接受B。(协方差)
如果我们传递something_b(x: B)给do(f: Callable[[A], None]),我们允许something_b(x: B)接受A- 但它不能。所以something_b(x: B)不能替代something_a(x: A)。另一方面,传递something_a(x: A)给需要 a 的函数Callable[[B], None]就可以了。(逆变)
该怎么办?- 使用泛型
AType = TypeVar('AType', bound=A)
def do_fixed(f: Callable[[AType], None]):
pass
do_fixed(something_a) # ok
do_fixed(something_b) # ok
Run Code Online (Sandbox Code Playgroud)
虽然我们确实收到了传递其他类型的可调用对象的警告:
class C: # not derived from A
n = 1
def something_c(x: C):
print(x.n)
do_fixed(something_c) # type check warning
Run Code Online (Sandbox Code Playgroud)
但我们仍然需要确保我们不会传递A给something_b,这可以通过以下方式实现:
def do_safer(f: Callable[[AType], None], v: AType):
f(v)
do_safer(something_a, A()) # ok
do_safer(something_a, B()) # ok
do_safer(something_b, A()) # type check warning
do_safer(something_b, B()) # ok
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
883 次 |
| 最近记录: |