面试题答案
一键面试def check_argument_types(func):
def wrapper(*args, **kwargs):
annotations = func.__annotations__
for i, arg in enumerate(args):
if i < len(annotations):
expected_type = list(annotations.values())[i]
if not isinstance(arg, expected_type):
raise TypeError(f"Argument {i + 1} should be of type {expected_type.__name__}")
for key, value in kwargs.items():
if key in annotations:
expected_type = annotations[key]
if not isinstance(value, expected_type):
raise TypeError(f"Argument {key} should be of type {expected_type.__name__}")
return func(*args, **kwargs)
return wrapper
@check_argument_types
def add_numbers(a: int, b: int) -> int:
return a + b
装饰器工作原理解释:
- 定义装饰器函数
check_argument_types
:该函数接受一个函数func
作为参数。 - 在装饰器函数内部定义包装函数
wrapper
:- 获取函数注解
annotations
:func.__annotations__
可以获取函数参数和返回值的类型注解。 - 检查位置参数
args
:遍历args
,如果参数索引小于注解的数量,就检查当前参数是否为注解所期望的类型,如果不是则抛出TypeError
。 - 检查关键字参数
kwargs
:遍历kwargs
,如果参数名在注解中,就检查当前参数是否为注解所期望的类型,如果不是则抛出TypeError
。 - 调用原始函数:如果所有参数类型检查通过,就调用原始函数
func
并返回其结果。
- 获取函数注解
- 返回包装函数
wrapper
:装饰器最终返回包装函数,这样原始函数就被包装在一个新的函数中,这个新函数在调用原始函数之前会先检查参数类型。
使用 @check_argument_types
语法糖将装饰器应用到 add_numbers
函数上,这样当调用 add_numbers
函数时,会先执行装饰器中的参数类型检查逻辑。