网站首页 > 教程文章 正文
在Python中,装饰器(Decorator) 是一个非常强大且独特的功能,它允许我们“包装”或“增强”现有函数的功能,而无需修改其源代码。这使得我们可以写出更优雅、可复用性更强的代码。
本文将详细讲解 Python装饰器的功能、使用方法、常见场景,并通过大量示例帮助你全面掌握这一重要概念。文章适合Python初学者阅读,也适合有一定基础的开发者复习巩固。
一、什么是装饰器?
装饰器本质上是一个函数,它接受另一个函数作为参数,并返回一个新的函数。
装饰器的主要作用是:
- 在不修改原函数代码的前提下,为其添加新功能
- 实现逻辑复用(如日志记录、权限检查、计时等)
- 支持面向切面编程(AOP)
装饰器的本质:高阶函数 + 函数闭包
def my_decorator(func):
def wrapper():
print("装饰器前置操作")
func()
print("装饰器后置操作")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()
输出:
装饰器前置操作
Hello!
装饰器后置操作
在这个例子中:
- my_decorator 是装饰器函数
- say_hello 是被装饰的函数
- 使用 @my_decorator 语法糖自动将 say_hello 传入装饰器并替换为返回的新函数
二、装饰器的基本结构与执行流程
示例:装饰器的等价写法
上面的例子也可以写成:
def say_hello():
print("Hello!")
say_hello = my_decorator(say_hello)
say_hello()
这说明装饰器其实就是一个函数包装的过程。
执行流程图解:
[原始函数] → [装饰器函数处理] → [返回新函数]
↓ ↓ ↓
say_hello() → my_decorator(say_hello) → wrapper()
三、装饰器的进阶用法
1. 处理带参数的函数
def my_decorator(func):
def wrapper(*args, **kwargs):
print("装饰器前置操作")
result = func(*args, **kwargs)
print("装饰器后置操作")
return result
return wrapper
@my_decorator
def greet(name):
print(f"Hello, {name}!")
greet("Alice")
输出:
装饰器前置操作
Hello, Alice!
装饰器后置操作
通过使用 *args 和 **kwargs,可以支持任意参数类型的函数。
2. 带参数的装饰器
有时候我们需要给装饰器本身传递参数,这时可以再嵌套一层函数。
def repeat(num_times):
def decorator(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator
@repeat(3)
def say_hi():
print("Hi!")
say_hi()
输出:
Hi!
Hi!
Hi!
这个装饰器会根据传入的次数重复执行函数。
3. 多个装饰器叠加使用
我们可以为一个函数同时应用多个装饰器,它们的执行顺序是从内向外依次包裹。
def decorator1(func):
def wrapper():
print("装饰器1进入")
func()
print("装饰器1退出")
return wrapper
def decorator2(func):
def wrapper():
print("装饰器2进入")
func()
print("装饰器2退出")
return wrapper
@decorator1
@decorator2
def hello():
print("Hello")
hello()
输出:
装饰器1进入
装饰器2进入
Hello
装饰器2退出
装饰器1退出
执行顺序相当于:
hello = decorator1(decorator2(hello))
4. 类作为装饰器
除了函数,我们还可以使用类来实现装饰器功能。
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("装饰器前置操作")
result = self.func(*args, **kwargs)
print("装饰器后置操作")
return result
@MyDecorator
def say_hello():
print("Hello!")
say_hello()
输出:
装饰器前置操作
Hello!
装饰器后置操作
这种方式更加面向对象,适用于需要保存状态的情况。
四、常用内置装饰器介绍
Python标准库中提供了一些常用的装饰器,下面介绍几个最常使用的。
1.@staticmethod和@classmethod
用于定义静态方法和类方法。
class MyClass:
@staticmethod
def static_method():
print("这是静态方法")
@classmethod
def class_method(cls):
print(f"这是类方法,
调用类:{cls.__name__}")
MyClass.static_method()
MyClass.class_method()
2.@property
用于将类的方法伪装成属性访问。
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
return self._name
p = Person("Alice")
print(p.name) # 输出 Alice
这样可以让外部像访问属性一样使用方法,提高封装性。
3.@functools.wraps
用于保留原函数元信息(如名称、文档字符串等),避免被装饰器破坏。
from functools import wraps
def my_decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
"""装饰器的说明"""
print("装饰器前置")
return func(*args, **kwargs)
return wrapper
@my_decorator
def say_hello():
"""打招呼函数"""
print("Hello")
print(say_hello.__name__)
# 输出 say_hello(而不是 wrapper)
print(say_hello.__doc__)
# 输出 招呼函数(而不是装饰器的说明)
五、装饰器的应用场景
场景1:日志记录
def log(func):
def wrapper(*args, **kwargs):
print(f"正在执行函数: {func.__name__}")
result = func(*args, **kwargs)
print(f"函数 {func.__name__} 执行完成")
return result
return wrapper
@log
def calculate_sum(a, b):
return a + b
result = calculate_sum(3, 5)
print("结果:", result)
场景2:权限验证
def login_required(func):
def wrapper(user, *args, **kwargs):
if user.is_authenticated:
return func(user, *args, **kwargs)
else:
print("权限不足,请先登录")
return wrapper
class User:
def __init__(self, is_authenticated):
self.is_authenticated = is_authenticated
@login_required
def access_data(user):
print("成功访问数据")
user = User(is_authenticated=False)
access_data(user) # 权限不足,请先登录
场景3:性能计时
import time
def timer(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
def slow_function():
time.sleep(1)
slow_function()
场景4:缓存计算结果(Memoization)
def memoize(func):
cache = {}
def wrapper(n):
if n not in cache:
cache[n] = func(n)
return cache[n]
return wrapper
@memoize
def fibonacci(n):
if n <= 1:
return n
return fibonacci(n - 1) + fibonacci(n - 2)
print(fibonacci(100))
# 快速计算斐波那契数列
六、装饰器的优点与注意事项
优点:
- 提高代码复用性,减少重复逻辑
- 实现功能扩展而不修改原函数
- 支持模块化设计,分离核心逻辑与附加逻辑
- 简洁美观,提升代码可读性和可维护性
注意事项:
- 装饰器顺序会影响执行流程,需注意多个装饰器的叠加顺序
- 不要滥用装饰器,否则可能导致逻辑混乱
- 使用 @functools.wraps 保留函数元信息
- 小心闭包变量绑定问题(尤其是在循环中)
七、总结
装饰器是 Python 中非常强大的特性之一,它允许我们在不修改原有函数代码的情况下,动态地增强其功能。它是高阶函数和闭包机制的结合体,是编写高质量、可复用代码的重要工具。
通过本文的学习,你应该已经掌握了:
- 装饰器的基本概念和构成原理
- 如何编写和使用装饰器函数
- 装饰器的内部工作机制(函数包装、参数传递)
- 装饰器的高级用法(带参装饰器、类装饰器、多层装饰器)
- 装饰器的常见应用场景(日志、权限、计时、缓存等)
- 装饰器的优缺点及使用注意事项
作为 Python 初学者,建议你在练习中多尝试使用装饰器来优化代码结构,提升程序的灵活性和可维护性。
希望这篇文章能帮助你在 Python 编程之路上越走越远!
- 上一篇: 前端开发中79条不可忽视的知识点汇总
- 下一篇: 聊一聊垃圾回收机制(垃圾回收机制的方法)
猜你喜欢
- 2025-07-27 8个前端面试的题目(前端面试题2020及答案 知乎)
- 2025-07-27 深入理解Node.js中的垃圾回收和内存泄漏的捕获
- 2025-07-27 网易+腾讯+阿里,前端工程师面经!30K果然不是很好拿
- 2025-07-27 go errgroup 获取gorouting错误信息
- 2025-07-27 盛趣游戏unity客户端面试(盛趣游戏招聘岗位)
- 2025-07-27 Swift 性能探索和优化分析(swift运行效率)
- 2025-07-27 「前端开发」eval() 函数认知和学习以及注意事项
- 2025-07-27 解锁C++灵魂:函数指针场景及实例(c++函数指针和指针函数)
- 2025-07-27 2021 年 Node.js 开发人员学习路线图
- 2025-07-27 跨越十年的C++演进:C++11新特性全解析
- 最近发表
- 标签列表
-
- location.href (44)
- document.ready (36)
- git checkout -b (34)
- 跃点数 (35)
- 阿里云镜像地址 (33)
- qt qmessagebox (36)
- mybatis plus page (35)
- vue @scroll (38)
- 堆栈区别 (33)
- 什么是容器 (33)
- sha1 md5 (33)
- navicat导出数据 (34)
- 阿里云acp考试 (33)
- 阿里云 nacos (34)
- redhat官网下载镜像 (36)
- srs服务器 (33)
- pico开发者 (33)
- https的端口号 (34)
- vscode更改主题 (35)
- 阿里云资源池 (34)
- os.path.join (33)
- redis aof rdb 区别 (33)
- 302跳转 (33)
- http method (35)
- js array splice (33)