我有一个装饰函数,该函数填充函数的前两个参数,并且仅要求调用者填充其余参数。它用于处理数据库事务(前两个参数是连接和游标,如果没有异常发生,则提交事务)。
我尝试使mypy推断修饰函数的类型,但跳过前两个参数。不幸的是没有成功。
由于数据库事务代码很复杂,所以我准备了一个简化的示例:
'..' is not recognized as an internal or external command,
装饰器应填充第一个参数,例如与@decorator
def add(a: int, b: int, zero: bool = False) -> int:
if zero:
return 0
else:
return a + b
一起使用,并使1
函数仅需要一个参数。 add
逻辑仅用于确保也存在关键字参数的情况下起作用。
zero
def decorator(fn):
def wrapper(*args, **kwargs):
return fn(1, *args, **kwargs) # note the first argument `1`
return wrapper
到目前为止我尝试过的事情:
add(1) # = 2
…很好,但是类型推断仅适用于返回类型,不适用于参数。如果我将参数设置为字符串,mypy不会将其视为问题,并且在运行时会崩溃。
T = TypeVar('T')
def decorator(fn: Callable[..., T]) -> Callable[..., T]:
def wrapper(*args: Any, **kwargs: Any) -> T:
return fn(1, *args, **kwargs)
return wrapper
…这仅反映了此原始T = TypeVar('T', bound=Callable)
def decorator(fn: T) -> T:
def wrapper(*args: Any, **kwargs: Any) -> T:
return fn(1, *args, **kwargs)
return cast(T, wrapper)
函数的签名,并且是错误的。 Mypy将抱怨缺少add
的论点。
add
...这是行不通的,因为Args = TypeVar('Args')
KwArgs = TypeVar('KwArgs')
Result = TypeVar('Result')
class OriginalCallable(Protocol):
def __call__(self, a: int, *args: Args, **kwargs: KwArgs) -> Result: ...
class DecoratedCallable(Protocol):
def __call__(self, *args: Args, **kwargs: KwArgs) -> Result: ...
def decorator(fn: OriginalCallable) -> DecoratedCallable:
def wrapper(*args: Any, **kwargs: Any) -> Result:
return fn(1, *args, **kwargs)
return cast(DecoratedCallable, wrapper)
与add
的签名不完全匹配,但正确的是,但对于装饰器,我无法知道所有装饰功能的签名。
关于long thread,关于mypy的装饰器支持尚不完善,但是我的情况尚未完全涵盖。在python中,有一些内置函数可以执行类似的操作(functool.partial,@ staticmethod等),但是找不到如何定义此行为的方法。