我有一个函数,它接受另一个函数 x 作为其参数。函数 x 可以有 2 种不同类型的签名,我想通过类型提示来强制执行此操作:
TYPE_A = Callable[[int, int], int]
TYPE_B = Callable[[int], int]
def my_func(x: Union[TYPE_A, TYPE_B]) -> None:
...determine x is of which type and use x accordingly...
我遇到了 2 个问题:
-
我不知道如何检查 x 是否为
TYPE_A
或 | ||。我尝试使用TYPE_B
,它会生成类型错误。isinstance(x, TYPE_A)
如果我使用另一种方式来确定x的类型,例如,使用 -
来确定x内部
signature
的签名(如果x有1 个参数或 2 个参数),my_func
每当我运行 x:mypy
fromspectorimportsignature 时仍然认为存在类型错误 def my_func(x: 联合[TYPE_A, TYPE_B]): sig = 签名(x) if len(sig.parameters.values()) == 1: x(1) // mypy 认为这是一个类型错误:参数太少 别的: x(1, 2) // mypy 认为这是类型错误:参数太多有没有办法让我编写一个将另一个函数作为输入的函数,并使用类型检查来强制输入函数具有正确的签名?
Is there a way for me to write a function that takes another function as its input, and use type checking to enforce that the input function has the correct signature?
是对的,
isinstance(x, TYPE_A)
不适用于
Callable
类型提示。这是因为
Callable
类型提示在运行时不会创建实际的类型。它们仅在类型检查期间使用。
为了解决的问题,可以使用类型守卫函数和重载。以下是如何操作:
from typing import Callable, Union, overload
TYPE_A = Callable[[int, int], int]
TYPE_B = Callable[[int], int]
@overload
def my_func(x: TYPE_A) -> None:
...
@overload
def my_func(x: TYPE_B) -> None:
...
def my_func(x: Union[TYPE_A, TYPE_B]) -> None:
if is_type_a(x):
# 在这里,mypy 知道 x 是 TYPE_A 类型
x(1, 2)
else:
# 在这里,mypy 知道 x 是 TYPE_B 类型
x(1)
def is_type_a(x: Union[TYPE_A, TYPE_B]) -> bool:
try:
x(1, 2)
return True
except TypeError:
return False
解释:
-
重载: 我们使用
@overload
装饰器定义了my_func
的两个版本,每个版本接受一种类型的可调用对象。这告诉 mypy,my_func
可以接受两种不同的参数类型。 -
类型守卫:
is_type_a
函数使用“鸭子类型”来确定x
的类型。如果x
可以使用两个参数调用,则它被认为是TYPE_A
类型。 -
函数体: 在
my_func
的函数体中,我们使用is_type_a
来确定x
的类型。根据结果,我们使用正确的参数数量调用x
。
优点:
-
类型安全:
mypy 可以理解的代码,并确保在调用
x
时使用正确的参数数量。 - 可读性: 代码更易于理解,因为每个重载函数都清楚地显示了它接受的参数类型。
注意:
-
使用
try...except
块来确定类型并不总是理想的解决方案,因为它可能会掩盖其他错误。但是,在这种情况下,它是安全且实用的,因为它专门检查TypeError
以区分两种Callable
类型。
希望这可以帮助!如果还有其他问题,请随时提出。
标签:python,python-typing,mypy From: 49088342