python - Python 运行时类型检查传递给装饰器的函数是否具有正确的签名
问题描述
我有一个 python 装饰器,它期望传递函数的签名是 aUser
和 a Point
,它返回一个具有相同签名的函数:
@dataclass
class User:
name: str
@dataclass
class Point:
x: float
y: float
z: float
def logging_decorator(f: Callable[[User, Point], bool]) -> Callable[[User, Point], bool]:
print('decorating function...')
def decorated(a: User, b: Point) -> bool:
print(f'User {a.name} calling with points {b.x},{b.y},{b.z}')
ret = f(a, b)
print(f'returned {ret}')
return ret
return decorated
在打印decorating function...
时,我希望它检查传入的函数是否具有正确的签名,如果没有,则给出合理的错误消息。
这是一个装饰两个函数的示例,一个具有正确的签名,一个具有不正确的签名:
@logging_decorator
def good_f(a: User, b: Point) -> bool:
return True
@logging_decorator
def bad_f(a: str, b: str) -> str:
return "Hello"
如何向 中添加检查,logging_decorator
以便检查被修饰的函数是否具有正确的参数类型?
我尝试使用typing_inspect
andtypeguard
包,但找不到我需要的功能。
我正在使用 Python 3.8.3
解决方案
使用inspect
标准库中的模块。使用inspect.signature
,您可以编写如下函数验证代码:
import inspect
def validate_func(func):
def good_func(a: User, b: Point) -> bool: ...
good_func_signature = inspect.signature(good_func)
received_signature = inspect.signature(func)
if received_signature != good_func_signature:
raise TypeError(
f'Invalid function signature: '
f'expected "{good_func_signature}", '
f'got "{received_signature}"'
)
(您可以将此逻辑放在您的用例的装饰器中;我只是将其编写为一个单独的函数,以使其与您的代码分开。)
使用中:
>>> validate_func(good_f)
>>> validate_func(lambda a, b: a)
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 6, in validate_func
TypeError: Invalid function signature: expected "(a:__main__.User, b:__main__.Point) -> bool", got "(a, b)"
>>> validate_func(bad_f)
Traceback (most recent call last):
File "<string>", line 1, in <module>
File "<string>", line 6, in validate_func
TypeError: Invalid function signature: expected "(a:__main__.User, b:__main__.Point) -> bool", got "(a:str, b:str) -> str"
如果您愿意,您可以在签名之间进行更详细和细粒度的比较,而不仅仅是简单的相等检查。您可以使用 from 的返回值inspect.signature
进行比较:
- 参数个数
- 参数名称
- 参数的种类(仅位置、位置或关键字或仅关键字)
- 参数是否有注解
- 参数的注解是什么
- 参数是否有默认值
- 参数的默认值是什么
- 函数是否有返回注解
- 函数的返回注解是什么
inspect.signature
您可以在此处找到文档。
推荐阅读
- javascript - 在导出的函数(功能组件)React 中使用 redux 状态
- amazon-web-services - 从自定义指标添加 AWS CloudWatch 警报
- rust - 根据当前运行环境获取tokio运行时句柄的正确方法
- html - 如何使页脚居中
- java - 通过反射获取非静态方法中本地类的构造函数
- flutter - 需要帮助使用数据模型从 api 将列表存储在 sqflite 数据库中
- java - REST 请求 json Long 与原始 Long 不同
- kubernetes-helm - helm chart repo add 404 not found
- c# - C# WPF 窗口边距
- textbox - 文本框中只允许三个数值或字符