Python装饰器原理全解析
Python装饰器是一种强大的语言特性,它允许在不修改原函数代码的基础上,为函数添加额外的功能,例如日志记录、性能测试和权限验证等。装饰器本质上是一个函数,它接收一个函数作为参数,并返回一个新的函数。通过`@`语法糖,可以将装饰器应用到函数上,实现功能的增强。本文将深入解析Python装饰器的工作原理,包括如何处理带参数的函数,以及函数装饰器与类装饰器的区别。同时,还将探讨如何编写带参数的装饰器,以及如何使用`functools.wraps`来保留原始函数的元数据,避免影响函数信息。此外,文章还将介绍装饰器链的使用方法,展示多个装饰器叠加使用时的执行顺序,助你全面掌握Python装饰器的应用。
装饰器通过函数作为第一类对象实现,定义一个接收函数的装饰器,在其内部定义wrapper函数并添加额外逻辑,最后返回wrapper;使用@语法糖将原函数替换为包装后的函数,从而在不修改原函数代码的情况下增强功能。

装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象。 它们经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理等等。
装饰器就像给函数穿上了一件“外衣”,这件“外衣”可以给函数增加额外的能力,但不会改变函数本身。
装饰器是如何实现的?
Python的装饰器是基于函数是“第一类对象”这一概念实现的。这意味着函数可以像任何其他对象一样被传递、赋值和作为返回值。
简单来说,装饰器通过以下步骤工作:
- 定义一个装饰器函数,该函数接收一个函数作为参数。
- 在装饰器函数内部,定义一个新的函数(通常称为wrapper函数)。
- wrapper函数中,调用原始函数,并在调用前后添加额外的功能。
- 装饰器函数返回wrapper函数。
当使用@decorator语法糖来装饰一个函数时,实际上是将原始函数作为参数传递给装饰器函数,并将装饰器返回的wrapper函数赋值给原始函数的名字。
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()这段代码的执行结果是:
Something is happening before the function is called. Hello! Something is happening after the function is called.
如何处理带参数的函数?
如果被装饰的函数带有参数,wrapper函数需要能够接收和传递这些参数。可以使用*args和**kwargs来实现:
def my_decorator(func):
def wrapper(*args, **kwargs):
print("Before calling the function")
result = func(*args, **kwargs)
print("After calling the function")
return result
return wrapper
@my_decorator
def add(a, b):
return a + b
print(add(2, 3))输出结果:
Before calling the function After calling the function 5
装饰器能做什么?除了日志和性能监控
装饰器可以做的远不止日志和性能监控。 它们可以用于:
- 权限验证: 检查用户是否有权限访问某个函数。
- 缓存: 缓存函数的返回值,避免重复计算。
- 重试机制: 在函数执行失败时自动重试。
- 类型检查: 验证函数参数的类型。
- 信号处理: 在函数执行前后发送信号。
- 路由控制: 在Web框架中,将URL映射到对应的处理函数。
例如,一个简单的缓存装饰器:
import functools
def cache(func):
cached_values = {}
@functools.wraps(func)
def wrapper(*args):
if args in cached_values:
return cached_values[args]
else:
result = func(*args)
cached_values[args] = result
return result
return wrapper
@cache
def expensive_operation(n):
print(f"Calculating for {n}...")
return n * n
print(expensive_operation(5))
print(expensive_operation(5)) # 从缓存中获取装饰器与类装饰器有什么区别?
除了函数装饰器,Python还支持类装饰器。 类装饰器接收一个函数或类作为参数,并返回一个修改后的函数或类。
类装饰器通常通过实现__call__方法来工作。 当使用类装饰器装饰一个函数时,实际上是创建了该类的一个实例,并将被装饰的函数作为参数传递给类的构造函数。 当调用被装饰的函数时,实际上是调用了类实例的__call__方法。
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("Before calling the function")
result = self.func(*args, **kwargs)
print("After calling the function")
return result
@MyDecorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")如何编写一个带参数的装饰器?
有时候,我们需要一个可以接收参数的装饰器。 这可以通过创建一个返回装饰器函数的函数来实现。
def repeat(num_times):
def decorator_repeat(func):
def wrapper(*args, **kwargs):
for _ in range(num_times):
result = func(*args, **kwargs)
return result
return wrapper
return decorator_repeat
@repeat(num_times=3)
def greet(name):
print(f"Hello, {name}!")
greet("Bob")这个例子中,repeat函数接收一个num_times参数,并返回一个装饰器函数decorator_repeat。 decorator_repeat函数再接收被装饰的函数func,并返回wrapper函数。
装饰器会影响函数的元数据吗?
默认情况下,装饰器会改变被装饰函数的元数据,例如__name__和__doc__。 这可能会导致一些问题,例如在使用help()函数时显示不正确的信息。
为了解决这个问题,可以使用functools.wraps装饰器来保留原始函数的元数据。
import functools
def my_decorator(func):
@functools.wraps(func)
def wrapper(*args, **kwargs):
"""This is the wrapper function."""
print("Before calling the function")
result = func(*args, **kwargs)
print("After calling the function")
return result
return wrapper
@my_decorator
def say_hello():
"""This is the original function."""
print("Hello!")
print(say_hello.__name__)
print(say_hello.__doc__)使用了functools.wraps后,say_hello.__name__会输出say_hello,say_hello.__doc__会输出This is the original function.。 如果没有使用functools.wraps,则会输出wrapper函数的信息。
装饰器链:多个装饰器叠加使用
可以同时使用多个装饰器来增强一个函数的功能,这就是装饰器链。 装饰器的应用顺序是从下往上,从里到外。
def bold(func):
def wrapper(*args, **kwargs):
return "<b>" + func(*args, **kwargs) + "</b>"
return wrapper
def italic(func):
def wrapper(*args, **kwargs):
return "<i>" + func(*args, **kwargs) + "</i>"
return wrapper
@bold
@italic
def get_message(message):
return message
print(get_message("Hello"))在这个例子中,get_message函数首先被italic装饰器装饰,然后再被bold装饰器装饰。 因此,输出结果是Hello。
今天带大家了解了的相关知识,希望对你有所帮助;关于文章的技术知识我们会一点点深入介绍,欢迎大家关注golang学习网公众号,一起学习编程~
Java生成唯一UUID方法全解析
- 上一篇
- Java生成唯一UUID方法全解析
- 下一篇
- Win10高清截图方法大全
-
- 文章 · python教程 | 38分钟前 |
- Pandas读取Django表格:协议关键作用
- 401浏览 收藏
-
- 文章 · python教程 | 45分钟前 | 身份验证 断点续传 requests库 PythonAPI下载 urllib库
- Python调用API下载文件方法
- 227浏览 收藏
-
- 文章 · python教程 | 47分钟前 |
- Windows7安装RtMidi失败解决办法
- 400浏览 收藏
-
- 文章 · python教程 | 53分钟前 |
- Python异步任务优化技巧分享
- 327浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- PyCharm图形界面显示问题解决方法
- 124浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python自定义异常类怎么创建
- 450浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python抓取赛狗数据:指定日期赛道API教程
- 347浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- Python3中datetime常用转换方式有哪些?
- 464浏览 收藏
-
- 文章 · python教程 | 2小时前 |
- PyCharm无解释器问题解决方法
- 290浏览 收藏
-
- 文章 · python教程 | 3小时前 | 性能优化 Python正则表达式 re模块 匹配结果 正则模式
- Python正则表达式入门与使用技巧
- 112浏览 收藏
-
- 文章 · python教程 | 3小时前 |
- MacPython兼容LibreSSL的解决方法
- 324浏览 收藏
-
- 文章 · python教程 | 3小时前 |
- OdooQWeb浮点转整数技巧
- 429浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- ChatExcel酷表
- ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
- 3178次使用
-
- Any绘本
- 探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
- 3390次使用
-
- 可赞AI
- 可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
- 3418次使用
-
- 星月写作
- 星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
- 4523次使用
-
- MagicLight
- MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
- 3797次使用
-
- Flask框架安装技巧:让你的开发更高效
- 2024-01-03 501浏览
-
- Django框架中的并发处理技巧
- 2024-01-22 501浏览
-
- 提升Python包下载速度的方法——正确配置pip的国内源
- 2024-01-17 501浏览
-
- Python与C++:哪个编程语言更适合初学者?
- 2024-03-25 501浏览
-
- 品牌建设技巧
- 2024-04-06 501浏览

