MST
星途 面试题库

面试题:Python函数高级编写技巧:装饰器与闭包

编写一个装饰器函数,用于统计被装饰函数的调用次数,并将每次调用的参数记录到一个日志文件中。同时,被装饰函数要接受不定数量的位置参数和关键字参数。阐述闭包在这个装饰器实现过程中的作用和原理。
11.7万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试
def call_counter(func):
    call_count = 0
    def wrapper(*args, **kwargs):
        nonlocal call_count
        call_count += 1
        with open('function_call_log.txt', 'a') as f:
            f.write(f"Call {call_count}: Args: {args}, Kwargs: {kwargs}\n")
        return func(*args, **kwargs)
    return wrapper


@call_counter
def sample_function(*args, **kwargs):
    print("Inside sample function")
    return sum(args) if args else 0


闭包在这个装饰器实现过程中的作用和原理:

  1. 作用
    • 数据隔离与保护:闭包中的call_count变量对于外部代码来说是隐藏的,只有wrapper函数可以访问和修改它,这样就避免了全局变量带来的命名冲突问题,同时保护了这个计数器变量不被随意篡改。
    • 状态保持call_count变量在多次调用wrapper函数时保持其状态,使得每次调用sample_function(被装饰函数)时,call_count能正确累加,实现调用次数的统计。
  2. 原理
    • call_counter装饰器函数被调用时,它定义了一个局部变量call_count和内部函数wrapper
    • 内部函数wrapper在其定义时,会记住其所在的词法环境,即包含call_count变量的环境。即使call_counter函数执行完毕返回,wrapper函数仍然持有对这个环境的引用,所以call_count变量不会被销毁。
    • 每次调用wrapper函数时,它可以访问并修改call_count变量,同时将调用参数记录到日志文件中,然后调用原始函数func并返回其结果。这里使用nonlocal关键字来声明call_count不是wrapper函数的局部变量,而是来自外层(但非全局)作用域,以便能够正确修改它的值。