Python typing库使用:如何为装饰器内部函数指定具体类型
你可以通过typing.ParamSpec搭配TypeVar实现装饰器的类型透传,完整的标注方案如下:
from typing import Callable, Any, ParamSpec, TypeVar from threading import Thread, Lock # 定义泛型参数捕获原函数的参数类型、返回值类型 P = ParamSpec('P') R = TypeVar('R') def synchronized(function: Callable[P, R]) -> Callable[P, R]: lock = Lock() def innerFunction(*args: P.args, **kwargs: P.kwargs) -> R: # 用上下文管理器替代手动加锁解锁,避免异常场景下锁无法释放 with lock: return function(*args, **kwargs) return innerFunction class Test: def __init__(self): self.__value: int = 0 @synchronized def threadFunc(self): self.__value = 0 for _ in range(10000000): self.__value += 1 print(self.__value) def main(): testObj = Test() for _ in range(100): thread = Thread(target=testObj.threadFunc, args=()) thread.start() if __name__ == "__main__": main()
标注逻辑说明
ParamSpec是Python 3.10引入的专门用于捕获可调用对象参数类型的特殊类型变量,能完整保留位置参数、关键字参数的类型信息,不会丢失原函数的参数类型提示TypeVar用于捕获原函数的返回值类型,保证装饰后的函数返回值和原函数完全一致- 标注完成后,静态类型检查工具(如mypy、pyright)可以正常识别被装饰函数的参数、返回值类型,不会出现类型丢失的问题
低版本Python兼容
如果使用Python 3.9及更早版本,需先安装typing-extensions依赖,将ParamSpec的导入语句修改为from typing_extensions import ParamSpec即可。
内容的提问来源于stack exchange,提问作者Duško Mirković
相关产品推荐
相关产品推荐

