Python 运行时类型检查传递给装饰器的函数是否具有正确的签名
Python runtime type check that function passed to a decorator has correct signature
我有一个 python 装饰器,它期望传递函数的签名是 User
和 Point
,它 returns 是一个具有相同功能的函数签名:
@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
和 typeguard
包,但找不到我需要的功能。
我正在使用 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"
如果需要,您可以在签名之间进行更详细和更细粒度的比较,而不仅仅是简单的相等性检查。您可以使用 inspect.signature
中的 return 值进行比较:
- 参数个数
- 参数名称
- 参数的种类(仅位置、位置或关键字或仅关键字)
- 参数是否有注解
- 参数的注解是什么
- 参数是否有默认值
- 参数的默认值是什么
- 函数是否有return注解
- 函数的return注解是什么
您可以找到 inspect.signature
here 的文档。
我有一个 python 装饰器,它期望传递函数的签名是 User
和 Point
,它 returns 是一个具有相同功能的函数签名:
@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
和 typeguard
包,但找不到我需要的功能。
我正在使用 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"
如果需要,您可以在签名之间进行更详细和更细粒度的比较,而不仅仅是简单的相等性检查。您可以使用 inspect.signature
中的 return 值进行比较:
- 参数个数
- 参数名称
- 参数的种类(仅位置、位置或关键字或仅关键字)
- 参数是否有注解
- 参数的注解是什么
- 参数是否有默认值
- 参数的默认值是什么
- 函数是否有return注解
- 函数的return注解是什么
您可以找到 inspect.signature
here 的文档。