当前位置:首页>python>Python装饰器原理——函数增强的核心机制

Python装饰器原理——函数增强的核心机制

  • 2026-10-11 08:32:56
Python装饰器原理——函数增强的核心机制

一、什么是装饰器?

装饰器(Decorator) 是 Python 中的一种设计模式,它允许在不修改原函数代码的情况下,给函数添加额外的功能。装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数(增强后的版本)。

deftimer(func):
"""计算函数执行时间的装饰器"""
defwrapper(*args, **kwargs):
import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
print(f"{func.__name__} 耗时: {end - start:.4f}秒")
return result
return wrapper

@timer
defslow_function():
import time
    time.sleep(1)
return"完成"

print(slow_function())   # slow_function 耗时: 1.0002秒 \n 完成

二、装饰器的本质:语法糖

@decorator 语法实际上是高阶函数的语法糖,它将目标函数作为参数传递给装饰器函数,并将返回的新函数替换原函数。

# 使用 @ 语法
@timer
defmy_func():
pass

# 等价于
defmy_func():
pass
my_func = timer(my_func)

三、装饰器的核心原理

3.1 函数在 Python 中是“一等公民”

Python 中函数可以:

  • • 赋值给变量
  • • 作为参数传递给其他函数
  • • 作为其他函数的返回值
defgreet(name):
returnf"Hello, {name}"

# 赋值给变量
say_hello = greet
print(say_hello("张三"))   # Hello, 张三

# 作为参数传递
defcall_func(func, arg):
return func(arg)
print(call_func(greet, "李四"))   # Hello, 李四

# 作为返回值
defmake_greeter(prefix):
defgreeter(name):
returnf"{prefix}, {name}"
return greeter

3.2 装饰器的基本结构

defdecorator(func):
"""装饰器函数"""
defwrapper(*args, **kwargs):
# 调用前可以添加额外操作
print("调用函数前")
        result = func(*args, **kwargs)
# 调用后可以添加额外操作
print("调用函数后")
return result
return wrapper

四、装饰器的执行流程

deflog(func):
print(f"装饰器函数被调用,正在装饰 {func.__name__}")
defwrapper(*args, **kwargs):
print(f"wrapper 函数被调用")
return func(*args, **kwargs)
return wrapper

@log
defsay_hello(name):
print(f"Hello, {name}")

print("--- 执行函数 ---")
say_hello("张三")

输出:

装饰器函数被调用,正在装饰 say_hello
--- 执行函数 ---
wrapper 函数被调用
Hello, 张三

执行步骤:

  1. 1. Python 解释器执行到 @log 时,立即调用 log(say_hello)。
  2. 2. log 函数执行,定义并返回 wrapper 函数。
  3. 3. 原函数 say_hello 被替换为 wrapper。
  4. 4. 当调用 say_hello("张三") 时,实际执行的是 wrapper 函数。

五、带参数的装饰器

装饰器本身也可以接收参数,这需要三层嵌套的函数结构。

defrepeat(times):
"""带参数的装饰器:重复执行指定次数"""
defdecorator(func):
defwrapper(*args, **kwargs):
for _ inrange(times):
                result = func(*args, **kwargs)
return result
return wrapper
return decorator

@repeat(3)
defgreet(name):
print(f"Hello, {name}")

greet("张三")
# 输出三次 "Hello, 张三"

执行流程:

  1. 1. @repeat(3) 首先调用 repeat(3),返回 decorator 函数。
  2. 2. @decorator 将 greet 函数传递给 decorator,返回 wrapper。
  3. 3. greet 被替换为 wrapper。

六、装饰器保留函数元信息

使用 functools.wraps 可以保留原函数的名称、文档字符串等元信息。

deftimer(func):
"""计时装饰器"""
defwrapper(*args, **kwargs):
"""wrapper 的文档"""
import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
print(f"{func.__name__} 耗时: {end - start:.4f}秒")
return result
return wrapper

@timer
defmy_func():
"""my_func 的文档"""
pass

print(my_func.__name__)   # wrapper(不是 my_func)
print(my_func.__doc__)    # wrapper 的文档(不是 my_func 的文档)

使用 @wraps 修复:

from functools import wraps

deftimer(func):
    @wraps(func)           # 保留原函数元信息
defwrapper(*args, **kwargs):
import time
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
print(f"{func.__name__} 耗时: {end - start:.4f}秒")
return result
return wrapper

@timer
defmy_func():
"""my_func 的文档"""
pass

print(my_func.__name__)   # my_func
print(my_func.__doc__)    # my_func 的文档

七、类装饰器

除了函数,类也可以作为装饰器,需要实现 __call__ 方法。

classTimer:
def__init__(self, func):
self.func = func
self.count = 0

def__call__(self, *args, **kwargs):
import time
        start = time.time()
        result = self.func(*args, **kwargs)
        end = time.time()
self.count += 1
print(f"{self.func.__name__} 第 {self.count} 次调用,耗时: {end - start:.4f}秒")
return result

@Timer
defslow_function():
import time
    time.sleep(1)
return"完成"

slow_function()
slow_function()

八、多个装饰器叠加

一个函数可以应用多个装饰器,执行顺序是从下往上。

defdecorator_a(func):
print("装饰器 A 被调用")
defwrapper(*args, **kwargs):
print("A 开始")
        result = func(*args, **kwargs)
print("A 结束")
return result
return wrapper

defdecorator_b(func):
print("装饰器 B 被调用")
defwrapper(*args, **kwargs):
print("B 开始")
        result = func(*args, **kwargs)
print("B 结束")
return result
return wrapper

@decorator_a
@decorator_b
defmy_func():
print("执行原函数")

my_func()

输出:

装饰器 B 被调用
装饰器 A 被调用
A 开始
B 开始
执行原函数
B 结束
A 结束

等价于:

my_func = decorator_a(decorator_b(my_func))

九、实战案例

9.1 权限验证装饰器

from functools import wraps

defrequire_permission(permission):
"""权限验证装饰器"""
defdecorator(func):
        @wraps(func)
defwrapper(*args, **kwargs):
# 模拟从上下文获取当前用户权限
            current_user = getattr(wrapper, 'user', None)
if current_user and permission in current_user.get('permissions', []):
return func(*args, **kwargs)
else:
raise PermissionError(f"缺少权限: {permission}")
return wrapper
return decorator

classUser:
def__init__(self, name, permissions):
self.name = name
self.permissions = permissions

defset_current_user(user):
defdecorator(func):
        @wraps(func)
defwrapper(*args, **kwargs):
            wrapper.user = user
return func(*args, **kwargs)
return wrapper
return decorator

@set_current_user(User("张三", ["read", "write"]))
@require_permission("write")
defdelete_file(filename):
print(f"删除文件: {filename}")

delete_file("test.txt")   # 删除文件: test.txt

9.2 重试装饰器

from functools import wraps
import time

defretry(max_attempts=3, delay=1, exceptions=(Exception,)):
"""重试装饰器"""
defdecorator(func):
        @wraps(func)
defwrapper(*args, **kwargs):
for attempt inrange(1, max_attempts + 1):
try:
return func(*args, **kwargs)
except exceptions as e:
print(f"第 {attempt} 次尝试失败: {e}")
if attempt == max_attempts:
raise
                    time.sleep(delay)
returnNone
return wrapper
return decorator

@retry(max_attempts=5, delay=0.5, exceptions=(ValueError,))
defunstable_function():
import random
if random.random() < 0.7:
raise ValueError("随机失败")
return"成功"

print(unstable_function())

9.3 缓存装饰器

from functools import wraps

defcache(maxsize=128):
"""简单缓存装饰器"""
defdecorator(func):
        cache_dict = {}

        @wraps(func)
defwrapper(*args):
if args in cache_dict:
print(f"缓存命中: {args}")
return cache_dict[args]
print(f"计算: {args}")
            result = func(*args)
# 简单的 LRU 淘汰
iflen(cache_dict) >= maxsize:
                cache_dict.pop(next(iter(cache_dict)))
            cache_dict[args] = result
return result
return wrapper
return decorator

@cache(maxsize=3)
deffibonacci(n):
if n < 2:
return n
return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))

十、注意事项

  1. 1. 装饰器的执行时机:装饰器在函数定义时立即执行(模块加载时),而不是在函数调用时。
  2. 2. 保留元信息:始终使用 @functools.wraps 保留原函数的名称、文档字符串等。
  3. 3. 函数签名:装饰器可能会改变函数的参数签名,影响内省和文档生成工具。
  4. 4. 性能影响:装饰器会增加函数调用开销,对性能敏感的函数需注意。
  5. 5. 调试困难:多层装饰器嵌套会使调试变得复杂,可以使用 functools.wraps 改善。

十一、总结

  • • 装饰器 是一种不修改原函数代码就能添加功能的机制。
  • • 本质:装饰器是返回函数的高阶函数,@decorator 是语法糖。
  • • 核心要素:函数是一等公民、闭包、高阶函数。
  • • 带参数的装饰器 需要三层嵌套函数结构。
  • • 多个装饰器 从下往上应用,从上往下执行。
  • • 类装饰器 通过实现 __call__ 方法实现。
  • • 最佳实践:使用 functools.wraps 保留函数元信息。

装饰器是 Python 中最优雅、最强大的特性之一。理解其原理,可以帮助你写出更简洁、可复用的代码,也是学习框架源码的必备知识。

最新文章

随机文章