python装饰器类型错误,装饰器的Python 3类型提示

Considere the following code:

from typing import Callable, Any

TFunc = Callable[..., Any]

def get_authenticated_user(): return "John"

def require_auth() -> Callable[TFunc, TFunc]:

def decorator(func: TFunc) -> TFunc:

def wrapper(*args, **kwargs) -> Any:

user = get_authenticated_user()

if user is None:

raise Exception("Don't!")

return func(*args, **kwargs)

return wrapper

return decorator

@require_auth()

def foo(a: int) -> bool:

return bool(a % 2)

foo(2) # Type check OK

foo("no!") # Type check failing as intended

This piece of code is working as intended. Now imagine I want to extend this, and instead of just executing func(*args, **kwargs) I want to inject the username in the arguments. Therefore, I modify the function signature.

from typing import Callable, Any

TFunc = Callable[..., Any]

def get_authenticated_user(): return "John"

def inject_user() -> Callable[TFunc, TFunc]:

def decorator(func: TFunc) -> TFunc:

def wrapper(*args, **kwargs) -> Any:

user = get_authenticated_user()

if user is None:

raise Exception("Don't!")

return func(*args, user, **kwargs) #

return wrapper

return decorator

@inject_user()

def foo(a: int, username: str) -> bool:

print(username)

return bool(a % 2)

foo(2) # Type check OK

foo("no!") # Type check OK

I can't figure out a correct way to type this. I know that on this example, decorated function and returned function should technically have the same signature (but even that is not detected).

解决方案

You can't use Callable to say anything about additional arguments; they are not generic. Your only option is to say that your decorator takes a Callable and that a different Callable is returned.

In your case you can nail down the return type with a typevar:

RT = TypeVar('RT') # return type

def inject_user() -> Callable[[Callable[..., RT]], Callable[..., RT]]:

def decorator(func: Callable[..., RT]) -> Callable[..., RT]:

def wrapper(*args, **kwargs) -> RT:

# ...

Even then the resulting decorated foo() function has a typing signature of def (*Any, **Any) -> builtins.bool* when you use reveal_type().

Various proposals are currently being discussed to make Callable more flexible but those have not yet come to fruition. See

for some examples. The last one in that list is an umbrella ticket that includes your specific usecase, the decorator that alters the callable signature:

Mess with the return type or with arguments

For an arbitrary function you can't do this at all yet -- there isn't even a syntax. Here's me making up some syntax for it.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值