🐍Python 函数与面向对象

装饰器与闭包

面试回答

常见问法

Python 装饰器的本质是什么?它和闭包是什么关系?

回答

装饰器本质上是“接收一个函数,返回一个新函数”的高阶函数写法;闭包则是内部函数引用了外部函数作用域中的变量,并在外部函数返回后仍然保留这些变量。

装饰器之所以常和闭包一起出现,是因为很多装饰器都靠闭包保存被装饰函数和附加状态。

def log_decorator(func):
    def wrapper(*args, **kwargs):
        print("before")
        result = func(*args, **kwargs)
        print("after")
        return result
    return wrapper

追问

  • @decorator 为什么只是语法糖
  • 为什么要用 functools.wraps
  • 带参数装饰器为什么要多包一层

原理展开

@decorator 等价于:

def hello():
    print("hello")

hello = log_decorator(hello)

带参数装饰器通常是三层:

from functools import wraps

def repeat(n):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for _ in range(n):
                func(*args, **kwargs)
        return wrapper
    return decorator

这里:

  • 最外层收装饰器参数
  • 中间层收函数对象
  • 最内层是真正执行时的包装逻辑

易错点

  • 只会写 @ 语法,不会展开本质
  • 忘记 wraps 导致函数名、文档字符串丢失
  • 把闭包和普通嵌套函数混为一谈