MST

星途 面试题库

面试题:Python装饰器在避免实参错误中的应用

使用Python装饰器来实现一个通用的机制,用于检查函数的实参类型。例如,有一个函数 `add_numbers` 期望接收两个整数参数,使用装饰器确保传入的实参是整数类型,如果不是则抛出合适的异常。请给出装饰器及 `add_numbers` 函数的完整代码,并解释装饰器的工作原理。
47.0万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
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


装饰器工作原理解释:

  1. 定义装饰器函数 check_argument_types:该函数接受一个函数 func 作为参数。
  2. 在装饰器函数内部定义包装函数 wrapper
    • 获取函数注解 annotationsfunc.__annotations__ 可以获取函数参数和返回值的类型注解。
    • 检查位置参数 args:遍历 args,如果参数索引小于注解的数量,就检查当前参数是否为注解所期望的类型,如果不是则抛出 TypeError
    • 检查关键字参数 kwargs:遍历 kwargs,如果参数名在注解中,就检查当前参数是否为注解所期望的类型,如果不是则抛出 TypeError
    • 调用原始函数:如果所有参数类型检查通过,就调用原始函数 func 并返回其结果。
  3. 返回包装函数 wrapper:装饰器最终返回包装函数,这样原始函数就被包装在一个新的函数中,这个新函数在调用原始函数之前会先检查参数类型。

使用 @check_argument_types 语法糖将装饰器应用到 add_numbers 函数上,这样当调用 add_numbers 函数时,会先执行装饰器中的参数类型检查逻辑。