Python装饰器:魔法般的代码“外挂”,让你的函数更强大!

你是否曾想过,在不修改原有函数代码的情况下,给它增加新功能?就像给游戏角色穿上装备,属性立刻提升!这就是Python装饰器的魔力所在。

什么是装饰器?

简单来说,装饰器就是一个返回函数的函数,它接受一个函数作为参数,并返回一个新的函数。

想象一下,你有一个普通的咖啡(函数):

1
2
def coffee():
print("一杯普通咖啡")

现在你想给它加点糖和奶(装饰器功能),但不想改变咖啡本身的配方。

基础装饰器:从零开始理解

让我们先看一个最简单的例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
def sugar_decorator(func):
def wrapper():
print("加一勺糖") # 新增功能
func() # 执行原函数
print("搅拌一下") # 新增功能
return wrapper

@sugar_decorator
def coffee():
print("一杯普通咖啡")

# 使用装饰后的函数
coffee()

输出:

1
2
3
加一勺糖
一杯普通咖啡
搅拌一下

看!我们没有修改coffee函数的代码,却给它增加了新功能。

装饰器语法糖:@符号的魔法

@sugar_decorator 实际上等价于:

1
coffee = sugar_decorator(coffee)

Python的@语法让代码更加简洁优雅!

处理带参数的函数

如果原函数有参数怎么办?别担心,装饰器也能处理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"开始执行函数: {func.__name__}")
print(f"参数: {args}, {kwargs}")
result = func(*args, **kwargs)
print(f"函数执行完毕")
return result
return wrapper

@log_decorator
def add(a, b):
return a + b

print(add(3, 5))

输出:

1
2
3
4
开始执行函数: add
参数: (3, 5), {}
函数执行完毕
8

*args**kwargs让我们可以处理任意参数的函数,这就是装饰器的强大之处!

实际应用场景

1. 性能测试装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import time

def timer_decorator(func):
def wrapper(*args, **kwargs):
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
print(f"{func.__name__} 执行时间: {end_time - start_time:.4f}秒")
return result
return wrapper

@timer_decorator
def heavy_calculation(n):
return sum(i*i for i in range(n))

heavy_calculation(1000000)

2. 权限验证装饰器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def login_required(func):
def wrapper(user, *args, **kwargs):
if not user.get('is_login', False):
print("请先登录!")
return None
return func(user, *args, **kwargs)
return wrapper

@login_required
def view_profile(user):
print(f"欢迎 {user['name']} 查看个人资料")

# 测试
user1 = {'name': '小明', 'is_login': True}
user2 = {'name': '小红', 'is_login': False}

view_profile(user1) # 正常访问
view_profile(user2) # 需要登录

3. 缓存装饰器(记忆化)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
def cache_decorator(func):
cache = {}
def wrapper(n):
if n not in cache:
cache[n] = func(n)
print(f"计算 fibonacci({n})")
else:
print(f"使用缓存: fibonacci({n})")
return cache[n]
return wrapper

@cache_decorator
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10)) # 大幅提升递归性能!

带参数的装饰器

有时候我们希望装饰器本身也能接受参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def repeat(times):
"""重复执行函数指定次数"""
def decorator(func):
def wrapper(*args, **kwargs):
results = []
for i in range(times):
print(f"第{i+1}次执行")
result = func(*args, **kwargs)
results.append(result)
return results
return wrapper
return decorator

@repeat(times=3)
def greet(name):
print(f"你好,{name}!")
return f"已问候{name}"

greet("世界")

类装饰器:更强大的封装

除了函数装饰器,我们还可以使用类来实现装饰器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class CounterDecorator:
def __init__(self, func):
self.func = func
self.count = 0

def __call__(self, *args, **kwargs):
self.count += 1
print(f"{self.func.__name__} 被调用了第{self.count}次")
return self.func(*args, **kwargs)

@CounterDecorator
def say_hello():
print("Hello!")

say_hello()
say_hello()
say_hello()

注意事项和最佳实践

  1. 保留元信息:使用functools.wraps保持原函数信息

    1
    2
    3
    4
    5
    6
    7
    from functools import wraps

    def my_decorator(func):
    @wraps(func) # 保留原函数的名称、文档等
    def wrapper(*args, **kwargs):
    return func(*args, **kwargs)
    return wrapper
  2. 装饰器顺序很重要

    1
    2
    3
    4
    5
    @decorator1
    @decorator2
    def func():
    pass
    # 等价于:func = decorator1(decorator2(func))
  3. 避免过度使用:装饰器虽好,但不要滥用,以免降低代码可读性

总结

装饰器是Python中强大而优雅的特性,它遵循了开放封闭原则(对扩展开放,对修改封闭)。通过装饰器,我们可以:

  • ✅ 在不修改源代码的情况下增强函数功能
  • ✅ 实现代码的复用和分离
  • ✅ 保持代码的整洁和可读性
  • ✅ 轻松实现AOP(面向切面编程)

记住这个核心:装饰器 = 接受函数作为参数 + 返回新函数

下次当你发现多个函数需要相同的前置或后置处理时,不妨考虑使用装饰器这个”代码外挂”!


练习时间:尝试为自己写一个装饰器,用来记录函数的执行日志到文件中。分享你的实现到评论区吧!

#Python #编程技巧 #装饰器 #代码优化 #Python进阶