【6k字】详解Python装饰器和生成器

文章目录

  • 1 Python装饰器
    • 1.1 什么是装饰器?
      • 1.1.1 参数化装饰器
    • 1.2 装饰器的工作原理
      • 1.2.1 函数签名保持
    • 1.3 装饰器的应用实例
      • 1.3.1 日志记录
      • 1.3.2 装饰器链
      • 1.3.3 自动注册装饰器
    • 1.4 Summary
  • 2 Python生成器
    • 2.1 生成器的定义和基本操作
    • 2.2 生成器的惰性求值和内存优势
    • 2.3 生成器表达式
    • 2.4 生成器和协程
    • 2.5 Python标准库itertools
    • 2.6 Summary
  • Reference

1 Python装饰器

1.1 什么是装饰器?

在 Python 中,装饰器提供了一种简洁的方式,用来修改或增强函数和类的行为。装饰器在语法上表现为一个前置于函数或类定义之前的特殊标记:

@simple_decorator
def hello_world():print("Hello, world!")

在这个例子中,simple_decorator 是一个装饰器,它作用于下方的 hello_world 函数。装饰器在概念上就像一个包装器,它可以在被装饰的函数执行前后插入任意的代码,进而改变被装饰函数的行为。

1.1.1 参数化装饰器

我们还可以进一步将装饰器参数化,这让装饰器的行为更具灵活性。比如,我们可以定义一个装饰器,让它在函数执行前后打印自定义的消息:

def message_decorator(before_message, after_message):def decorator(func):def wrapper(*args, **kwargs):print(before_message)result = func(*args, **kwargs)print(after_message)return resultreturn wrapperreturn decorator@message_decorator("Start", "End")
def hello_world():print("Hello, world!")

在这个例子中,message_decorator 是一个参数化装饰器,它接受两个参数,分别代表函数执行前后要打印的消息。

1.2 装饰器的工作原理

在 Python 中,函数是第一类对象。这意味着函数和其他对象一样,可以作为变量进行赋值,可以作为参数传给其他函数,可以作为其他函数的返回值,甚至可以在一个函数里面定义另一个函数。这个特性是实现装饰器的基础。

def decorator(func):def wrapper():print('Before function execution')func()print('After function execution')return wrapperdef hello_world():print('Hello, world!')decorated_hello = decorator(hello_world)
decorated_hello()

在这个例子中,decorator 函数接收一个函数 hello_world 作为参数,并返回了一个新的函数 wrapped_func。这个新函数在 hello_world 函数执行前后分别打印一条消息。我们可以看到,装饰器实际上是一个返回函数的函数

1.2.1 函数签名保持

默认情况下,装饰器会“掩盖”掉原函数的名字和文档字符串。这是因为在装饰器内部,我们返回了一个全新的函数。我们可以使用 functools.wraps 来解决这个问题:

import functoolsdef decorator(func):@functools.wraps(func)def wrapper():print('Before function execution')func()print('After function execution')return wrapper@decorator
def hello_world():"Prints 'Hello, world!'"print('Hello, world!')print(hello_world.__name__)
print(hello_world.__doc__)

这样,使用装饰器后的函数名和文档字符串能够保持不变。

1.3 装饰器的应用实例

装饰器在实际的 Python 编程中有许多应用场景,比如日志记录、性能测试、事务处理、缓存、权限校验等。

1.3.1 日志记录

一个常见的应用就是使用装饰器进行日志记录

import loggingdef log_decorator(func):logging.basicConfig(level=logging.INFO)def wrapper(*args, **kwargs):logging.info(f'Running "{func.__name__}" with arguments {args} and kwargs {kwargs}')result = func(*args, **kwargs)logging.info(f'Finished "{func.__name__}" with result {result}')return resultreturn wrapper@log_decorator
def add(x, y):return x + y

这个装饰器记录了函数的名称,函数调用的参数,以及函数返回的结果。

1.3.2 装饰器链

Python 允许我们将多个装饰器应用到一个函数上,形成一个装饰器链。

例如,我们可以同时应用日志装饰器和性能测试装饰器

import time
import logging
from functools import wrapsdef log_decorator(func):logging.basicConfig(level=logging.INFO)@wraps(func)def wrapper(*args, **kwargs):logging.info(f'Running "{func.__name__}" with arguments {args} and kwargs {kwargs}')result = func(*args, **kwargs)logging.info(f'Finished "{func.__name__}" with result {result}')return resultreturn wrapperdef timer_decorator(func):@wraps(func)def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()print(f'Function "{func.__name__}" took {end_time - start_time} seconds to run.')return resultreturn wrapper@log_decorator
@timer_decorator
def add(x, y):time.sleep(2)return x + y

在这个例子中,@log_decorator@timer_decorator 两个装饰器被同时应用到 add 函数上,它们分别负责记录日志和测量函数运行时间。

1.3.3 自动注册装饰器

一个有趣的装饰器应用是自动注册。这个装饰器会在装饰函数时自动将函数添加到一个列表或字典中,这样我们就可以在程序的其他地方访问到这个列表或字典,知道有哪些函数被装饰过。

# 装饰器将函数注册到一个列表中
def register_decorator(func_list):def decorator(func):func_list.append(func)return funcreturn decorator# 自动注册函数
registered_functions = []
@register_decorator(registered_functions)
def foo():pass@register_decorator(registered_functions)
def bar():passprint(registered_functions)  # 输出: [<function foo at 0x10d38d160>, <function bar at 0x10d38d1f0>]

这个装饰器可以用于自动注册路由、插件系统、命令行参数处理等场景,能够大大提高代码的灵活性和可扩展性。

1.4 Summary

Python 装饰器是一种强大的工具,它可以让我们更有效地管理和组织代码,从而在项目中更好地使用装饰器。

2 Python生成器

强大的数据处理管道

生成器是Python的一种核心特性,允许我们在请求新元素时再生成这些元素,而不是在开始时就生成所有元素。它在处理大规模数据集、实现节省内存的算法构建复杂的迭代器模式等多种情况下都有着广泛的应用。在本篇文章中,我们将从理论和实践两方面来探索Python生成器的深度用法。

2.1 生成器的定义和基本操作

生成器是一种特殊的迭代器,它们的创建方式是在函数定义中包含yield关键字。当这个函数被调用时,它返回一个生成器对象,该对象可以使用next()函数或for循环来获取新的元素。

def simple_generator():yield "Python"yield "is"yield "awesome"# 创建生成器
gen = simple_generator()# 使用next函数获取元素
print(next(gen))  # 输出: Python
print(next(gen))  # 输出: is
print(next(gen))  # 输出: awesome# 使用for循环获取元素
for word in simple_generator():print(word)# 输出:
# Python
# is
# awesome

当生成器耗尽(即没有更多元素产生)时,再次调用next()函数将引发StopIteration异常。这个异常可以由我们手动捕获,或者由for循环自动处理。

2.2 生成器的惰性求值和内存优势

生成器的主要优势之一是它们的惰性求值特性。也就是说,生成器只在需要时才计算和产生元素。这使得生成器在处理大规模数据时,可以大大降低内存使用量。与传统的数据结构(如列表)相比,生成器不需要在内存中存储所有元素,而是在每次迭代时动态计算出新的元素。

这种特性使得生成器在处理大规模数据流、实现复杂的算法或构建动态的数据管道等场景中具有显著的优势。

# 无限序列生成器
def infinite_sequence():num = 0while True:yield numnum += 1# 创建生成器
seq = infinite_sequence()# 输出前10个元素
for i in range(10):print(next(seq))  # 输出:
# 0
# 1
# 2
# 3
# 4
# 5
# 6
# 7
# 8
# 9

在这个例子中,infinite_sequence是一个永不停止的生成器。尽管它可以产生无穷多的元素,但由于生成器的惰性求值特性,它并不会导致内存耗尽。

2.3 生成器表达式

生成器表达式是创建生成器的一种更简洁的方式。它们与列表推导式的语法相似,但是生成的是一个生成器对象,而不是一个完整的列表。这使得生成器表达式在处理大规模数据时可以节省大量的内存。

# 创建一个生成器表达式
gen_expr = (x**2 for x in range(1000000))# 输出前10个元素
for i in range(10):print(next(gen_expr))# 输出:
# 0
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81

在这个例子中,gen_expr是一个生成器表达式,它可以生成10^6个元素的平方数。但是,由于生成器表达式的惰性求值特性,它并不会在内存中生成和存储所有这些元素。

2.4 生成器和协程

Python的生成器还可以作为协程使用。

协程是一种特殊类型的函数,它可以在其执行过程中挂起和恢复,从而在单个线程中实现多任务协作式并发。这使得我们可以使用生成器来实现复杂的控制流程,如并发编程异步IO等。

def coroutine_generator():print("Starting")while True:value = (yield)print(f"Received: {value}")# 创建生成器
gen = coroutine_generator()# 启动生成器
next(gen)  # 输出: Starting# 向生成器发送数据
gen.send("Hello")  # 输出: Received: Hello
gen.send("Python")  # 输出: Received: Python# 关闭生成器
gen.close()

在这个例子中,coroutine_generator是一个协程生成器。我们可以使用send()函数向它发送数据,生成器在收到数据后将其打印出来。

2.5 Python标准库itertools

在Python的标准库itertools中,有一个函数itertools.islice,它可以用来对生成器进行切片操作,就像我们对列表进行切片那样。这在处理大规模数据流时非常有用。

import itertools# 无限序列生成器
def infinite_sequence():num = 0while True:yield numnum += 1# 创建生成器
seq = infinite_sequence()# 对生成器进行切片操作
sliced_seq = itertools.islice(seq, 5, 10)# 输出切片后的元素
for num in sliced_seq:print(num)# 输出:
# 5
# 6
#7
# 8
# 9

在这个例子中,我们使用itertools.islice函数对无限序列生成器seq进行了切片操作,获取了序列的第5个到第10个元素(从0开始计数)。这让我们能够在不消耗大量内存的情况下,灵活地处理大规模的数据流。

2.6 Summary

生成器是Python中一种非常强大的工具,它让我们能够以更高效和简洁的方式处理复杂的问题。熟练掌握生成器的使用,将使你在Python编程中具有更高的自由度和更强的实力。

Reference

https://blog.csdn.net/magicyangjay111/article/details/131054330

https://blog.csdn.net/magicyangjay111/article/details/130965602

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/106969.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【工具】html请求 Content-Encoding=br 返回值乱码的问题 解码返回值

【工具】Content-Encodingbr 解码返回值 添加依赖 <dependency><groupId>org.brotli</groupId><artifactId>dec</artifactId><version>0.1.2</version></dependency> 代码 public static String 解码br(InputStream is) {try…

MySQL日志管理和权限管理(重点)

目录 一、日志管理1.错误日志2.二进制日志3.慢查询日志 二、权限管理(重点)1.用户登录管理2.创建用户及授权3.刷新权限4.权限简介5.查看权限7.修改密码8、删除用户9、查看密码复杂度 一、日志管理 日志类型 1、错误日志&#xff1a;启动&#xff0c;停止&#xff0c;关闭失败报…

UPS监控技术,你一定要试试,太绝了!

UPS&#xff08;不间断电源&#xff09;监控系统是一种关键的技术&#xff0c;用于监视、管理和维护不间断电源设备&#xff0c;以确保电力供应的稳定性和可用性。这对于各种组织和企业来说至关重要&#xff0c;因为电力中断可能导致生产中断、数据丢失和设备损坏&#xff0c;对…

全流量安全分析发现内部系统外联异常

内部系统外连监控的重要性在于保护企业的信息安全和预防数据泄露&#xff0c;以下是几个重要的理由&#xff1a; 1、检测异常活动&#xff1a;通过监控内部系统的外连连接&#xff0c;可以及时发现是否有未经授权或异常的链接尝试。这可能表示存在恶意软件、黑客攻击或内部员工…

MySQL JSON_TABLE() 函数

JSON_TABLE()函数从一个指定的JSON文档中提取数据并返回一个具有指定列的关系表。 应用&#xff1a;数据库字段以JSON 存储后&#xff0c;实际应用需要对其中一个字段进行查询 语法 JSON_TABLE(json,path COLUMNS(column[,column[,...]]))column:name参数 json必需的。一个 …

风向编码与度数对照表

十六方位风向和静风的方位、符号、风向编码、中心角度及各风向角度范围对照表 方位 符号 风向编码中心角度 角度范围 北N9990010.0348.76~11.25北东北NNE99900222.511.26~33.75东北NE99900345.033.76~56.25东东北ENE99900467.556.26~78.75东E99900590.078.76~101.25东东南ESE…

登录ip地址异常怎么办

在互联网时代&#xff0c;登录IP地址异常已经成为一个普遍存在的问题。当用户尝试登录某个网站或服务时&#xff0c;如果其IP地址被认定为异常&#xff0c;则可能会被拒绝访问或面临其他安全风险。虎观代理小二二将介绍登录IP地址异常的处理方法&#xff0c;帮助大家解决这一问…

机器学习的打分方程汇总

机器学习的打分方程集合 受到机器学习&#xff08;Machine Learning&#xff09;和深度学习&#xff08;Deep Learning&#xff09;等算法模型的创新性冲击&#xff0c;其应用范围涵盖了自然语言处理&#xff08;Natural Language Processing&#xff09;、自动驾驶&#xff08…

远程计算机或设备将不接受连接

远程计算机或设备将不接受连接 1 现象网络连接失败感叹号,提示ip被占用,修改ip后显示连接成功但是不能上网,网络检验后提示:远程计算机或设备将不接受连接 2 原因因为安装了梯子,关机的时候未退出,原因大概就是这个原因. 3 解决1.修改internet属性(winr:inetpl.cpl)->连接-&…

使用Python创建faker实例生成csv大数据测试文件并导入Hive数仓

文章目录 一、Python生成数据1.1 代码说明1.2 代码参考 二、数据迁移2.1 从本机上传至服务器2.2 检查源数据格式2.3 检查大小并上传至HDFS 三、beeline建表3.1 创建测试表并导入测试数据3.2 建表显示内容 四、csv文件首行列名的处理4.1 创建新的表4.2 将旧表过滤首行插入新表 一…

docker部署的jenkins配置(接口自动化)

目录 一、jenkins汉化1.点击Manage Jenkins&#xff08;系统管理&#xff09;&#xff0c;点击Plugins&#xff08;插件&#xff09;2.安装Locale插件 二、jenkins配置allure报告1.安装allure插件2.配置 三、配置jenkins项目1.新建任务2.创建项目3.源码管理4.构建触发器5.增加构…

12个VIM编辑器的高级玩法

vim 是一个很好用的编辑器&#xff0c;应用十分广泛。但关于 vim&#xff0c;总有一些你不知道的事情&#xff0c;我们需要持续不断的学习。 我经常使用 vim&#xff0c;也经常在各大社区、论坛看到 vim 专家用户分享经验&#xff0c;今天我们就总结其中常用的一部分&#xff…

【问题解决】Ubuntu 安装 SeisSol 依赖 easi 报错解决: undefined reference to `H5free_memory‘

兼职帮客户安装 SeisSol 时问题解决&#xff0c;安装 easi 这个报错卡了很久&#xff08;搞了一天&#xff09;&#xff0c;记录下&#xff0c;以备后用~ # 编译器问题 rootubuntu:/opt/easi# make -j install [ 4%] Building CXX object CMakeFiles/easi.dir/src/component/…

科普向丨语音芯片烧录工艺的要求

语音芯片烧录工艺要求烧录精度、速度、内存容量、电源稳定性、兼容性和数据安全性。这些要素需优化和控制以保证生产高效、稳定、安全并烧录出高质量的语音芯片。不同厂家生产的语音芯片在烧录工艺上存在差异&#xff0c;需相应设计和研发以实现兼容。 一、烧录精度 语音芯片烧…

小程序页面路由传参的方法?

小程序页面路由传参的方法有三种&#xff1a; 1.URL参数传递&#xff1a;通过在页面跳转的URL中携带参数实现传参。可以使用wx.navigateTo或wx.redirectTo等跳转方法&#xff0c;并在URL中添加参数。 示例&#xff1a; // PageA.wxml <button bindtap"navigateToPage…

hive排序

目录 order by (全局排序asc ,desc) sort by(reduce 内排序) Distribute by(分区排序) Cluster By&#xff08;当 distribute by 和 sorts by 字段相同时 &#xff0c;可以使用 &#xff09; order by (全局排序asc ,desc) INSERT OVERWRITE LOCAL DIRECTORY /home/test2 …

城市综合管廊运维的系统集成方案

摘 要&#xff1a;从网络拓扑结构、开放式实时以太网协议、控制层系统配置方面介绍了综合管廊的系统网络架构设计&#xff0c;分析了无线网络特性&#xff0c;阐述了基于HTML5架构所能实现的功能的初步构想&#xff0c;以便于综合管廊运维人员巡检&#xff0c;确保管廊本体安全…

2023年(2024届)双非保研历程(中南、东南、浙大、信工所、国防科大、北邮)

个人情况 学校层次&#xff1a;双非 专业&#xff1a;信息安全&#xff08;投的基本都是网安&#xff09; 排名&#xff1a;2/66 英语&#xff1a;六级565&#xff0c;四级560 竞赛&#xff1a;大英赛国三、美赛H、蓝桥杯省一、数竞省一、词达人省一、数模国赛省三。 论文&…

第二证券:国际油价大幅上涨 后市恐难持续走高

上个买卖周&#xff0c;受巴以冲突影响&#xff0c;原油商场成为各方关注的焦点。到上星期五收盘&#xff0c;布伦特原油周内涨幅达7%以上&#xff0c;为本年2月以来最大周涨幅&#xff0c;WTI原油周内累计上涨近6%。业内人士认为&#xff0c;其时地缘要素是导致油价出现异动的…

excel映射xml方法

excel映射xml方法 创建xml模板 新建一个文本文件&#xff0c;编写模板并命名为xxx.xml <?xml version"1.0" encoding"UTF-8"?> <root><item ID""><surname></surname><man></man><woman>&…