这是一个由类实现的装饰器的经典示例:
class Decorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
self.func(*args, **kwargs)
如何使
__call__
具有与func
相同的签名和类型提示?
我尝试过以下代码:
from typing import Callable, TypeVar, ParamSpec, Generic
PT = ParamSpec('PT')
RT = TypeVar('RT')
class Decorator(Generic[PT, RT]):
def __init__(self, func: Callable[PT, RT]) -> None:
self.func = func
def __call__(self, *args: PT.args, **kwargs: PT.kwargs) -> RT:
return self.func(*args, **kwargs)
@Decorator
def add(x: int, y: int) -> int:
return x + y
但我未能在 PyCharm 中获得
add
的正确参数列表。
是 PyCharm 的错吗?
您希望将函数显式替换为具有特定签名的可调用函数,而不是使用工作原理相同但不共享签名的可调用类替换该函数。
具体方法如下:
from typing import Callable, TypeVar, ParamSpec, Generic
PT = ParamSpec('PT')
RT = TypeVar('RT')
class Decorator(Generic[PT, RT]):
def __init__(self, func: Callable[PT, RT]) -> None:
self.func = func
def __call__(self, *args: PT.args, **kwargs: PT.kwargs) -> RT:
return self.func(*args, **kwargs)
def decorator(func: Callable[PT, RT]) -> Callable[PT, RT]:
return Decorator(func)
@decorator
def add(x: int, y: int) -> int:
return x + y
print(add(1, 2))
您会发现类型提示和类型检查现在都可以正常工作,在 PyCharm 中也是如此。虽然,当您使用该类作为装饰器时,类型检查可以工作,但类型提示会如您在问题中所示那样显示。