Python编程 - 三器一包
目录
前言
一、迭代器
(一)基本概念
(二)迭代器和可迭代对象
(三)创建迭代器
(四)内置迭代器函数
(五)优点和局限性
二、生成器
(一)基本概念
(二)创建生成器
(三)生成器表达式
(四)生成器的优势
(五)使用生成器
(六)生成器的应用
(七)生成器和列表对比
三、装饰器
(一)装饰器的基本概念
(二)带参数的装饰器
(三)应用场景
(四)保持元数据
(五)总结
四、闭包
(一)简介
(二)闭包的结构
(三)工作原理
(四)应用场景
(五)注意事项
(六)闭包中修改外部变量
(七)总结
五、总结
前言
上篇文章将了python多态,类属性等知识,这篇文章了解一下python的三器一包:迭代器、生成器、装饰器和闭包
一、迭代器
Python的迭代器是一个重要的概念,特别是在处理序列数据和流数据时。迭代器是一种可以逐一遍历集合中所有元素的对象。
(一)基本概念
迭代器是实现了__iter__()和__next__()方法的对象。
__iter__(): 这个方法返回迭代器对象本身。它在一个对象被迭代时会被自动调用,可以在循环或其他迭代环境中使用。__next__(): 这个方法返回迭代中的下一个值。当序列遍历结束时,它会引发StopIteration异常,通知迭代终止。
(二)迭代器和可迭代对象
在Python中,有两种与迭代有关的对象类型:可迭代对象和迭代器。
-
可迭代对象(Iterable):任何可以返回一个迭代器的对象都被称为可迭代对象。常见的可迭代对象包括列表、元组、字典、集合和字符串。可迭代对象实现了
__iter__()方法。 -
迭代器(Iterator):是一个有状态的对象,它会在调用
__next__()时返回序列中的下一个值。迭代器对象实现了__iter__()和__next__()方法。
(三)创建迭代器
可以通过实现__iter__()和__next__()方法来手动创建一个迭代器。也可以通过iter()函数将一个可迭代对象转换为迭代器。
# 自定义迭代器示例
class MyIterator:def __init__(self, data):self.data = dataself.index = 0def __iter__(self):return selfdef __next__(self):if self.index < len(self.data):value = self.data[self.index]self.index += 1return valueelse:raise StopIteration# 使用迭代器
my_iter = MyIterator([1, 2, 3])
for item in my_iter:print(item)
(四)内置迭代器函数
python提供了一些内置函数来处理迭代器:
iter(): 返回一个迭代器对象。对于可迭代对象,iter()函数将其转换为迭代器。next(): 通过调用迭代器的__next__()方法来获取下一个元素。如果没有元素可返回,则会引发StopIteration异常。
#示例
numbers = [1, 2, 3]
iterator = iter(numbers)
print(next(iterator)) # 输出: 1
print(next(iterator)) # 输出: 2
print(next(iterator)) # 输出: 3
(五)优点和局限性
- 优点:
- 延迟计算:迭代器在需要时才生成元素,有助于节省内存。
- 简化代码:通过迭代器,代码更简洁,容易处理无限序列。
- 局限性:
- 一次性使用:迭代器一旦耗尽(遍历完),无法复用,必须重新创建。
- 无法反向迭代:标准迭代器仅支持从前到后遍历,不能逆向。
二、生成器
生成器是一种特殊的迭代器,它能够在需要时生成值,从而使得处理大型数据集或流数据变得更加高效。生成器通过使用 yield 关键字创建,并且具有延迟计算的特性,即惰性求值,只有在迭代时才会生成值。下面详细介绍生成器的相关概念和使用方法。
(一)基本概念
生成器(Generator) 是一种函数,它在每次调用时都会生成一个值,并在其 yield 语句的地方暂停执行,下一次迭代从暂停的位置继续。与普通函数不同,生成器函数在执行完所有 yield 语句后会自动退出。
生成器的关键特性包括:
- 惰性求值:生成器不会一次性生成所有值,而是按需生成,这对于处理大数据集或无限序列非常有用。
- 状态保持:生成器函数在暂停时保持其执行状态(包括局部变量、指针等),并在下一次调用时继续执行。
(二)创建生成器
生成器通过定义一个包含 yield 语句的函数来创建。yield 会暂停函数的执行并返回一个值,当生成器的 __next__() 方法被调用时,函数会从暂停处继续执行。
# 生成器函数示例
def my_generator():print("First yield")yield 1print("Second yield")yield 2print("Third yield")yield 3# 使用生成器
gen = my_generator()
print(next(gen)) # 输出: First yield \n 1
print(next(gen)) # 输出: Second yield \n 2
print(next(gen)) # 输出: Third yield \n 3
(三)生成器表达式
python 提供了一种简洁的生成器定义方式,称为 生成器表达式。生成器表达式类似于列表推导式,但返回的是一个生成器对象,而不是一个列表。
# 生成器表达式示例
gen_expr = (x * x for x in range(5))for value in gen_expr:print(value)
在上面的示例中,gen_expr 是一个生成器,它在每次迭代时按需生成平方数。
(四)生成器的优势
生成器相比于普通函数和数据结构有许多优点:
- 节省内存:生成器按需生成值,不会一次性将所有数据存储在内存中,非常适合处理大型或无限数据集。
- 代码简洁:生成器表达式可以用一行代码创建生成器,减少了代码量。
- 惰性求值:生成器只有在需要时才计算值,提高了效率,尤其是处理需要延迟计算的场景。
(五)使用生成器
除了使用 next() 函数来迭代生成器,还可以通过以下方式控制生成器:
send(value): 向生成器发送一个值,并暂停生成器的当前位置恢复执行。close(): 终止生成器,生成器在下一次调用__next__()或send()时会引发StopIteration异常。throw(type, value=None, traceback=None): 在生成器中引发指定的异常,生成器可以捕获这个异常,并决定是继续还是终止。
def controlled_generator():while True:value = yieldif value is None:breakprint(f'Received: {value}')gen = controlled_generator()
next(gen) # 初始化生成器
gen.send('Hello') # 输出: Received: Hello
gen.send('World') # 输出: Received: World
gen.close() # 关闭生成器
(六)生成器的应用
生成器在Python中有许多实际应用,以下是一些常见的场景:
- 数据流处理:生成器可以逐行读取文件,或按需处理数据流,减少内存消耗。
- 延迟计算:当需要对大数据集进行计算但不想一次性加载时,生成器可以按需计算结果。
- 管道处理:生成器可以连接在一起形成数据处理管道,每个生成器处理数据的一部分。
(七)生成器和列表对比
| 特性 | 生成器 | 列表 |
|---|---|---|
| 内存使用 | 按需生成,节省内存 | 一次性加载所有元素,占用大量内存 |
| 执行方式 | 惰性求值,逐步生成 | 立即求值,一次性生成所有元素 |
| 适用场景 | 大数据集、流数据 | 小数据集,频繁访问元素 |
| 代码复杂度 | 简洁,适合管道处理 | 简单明了,适合频繁访问 |
通过生成器,可以使Python程序在处理大规模数据时更加高效,特别是在内存受限或需要流式处理的场景下。生成器不仅提供了强大的功能,还保持了代码的简洁和可维护性。
三、装饰器
python的装饰器是一个强大的特性,允许你以优雅的方式修改函数或类的行为。装饰器可以用来插入额外的功能、修改函数行为,甚至是对函数进行包装而不直接修改其代码。
(一)装饰器的基本概念
装饰器是一个函数,接受另一个函数作为参数,返回一个新的函数。这个新的函数通常会在原函数的调用之前或之后执行额外的代码。装饰器本质上是一种“包装”机制,使得你可以在不修改原始函数代码的情况下,添加额外的功能。
示例:
def my_decorator(func):def wrapper():print("有些事情在调用方法之前发生")func()print("有些事情在调用方法之后发生")return wrapper@my_decorator
def say_hello():print("Hello!")say_hello()
在该示例中:
my_decorator是一个装饰器函数,它接受func作为参数。wrapper函数在调用func之前和之后打印了一些信息。@my_decorator是装饰器的应用方式,相当于say_hello = my_decorator(say_hello)。- 当你调用
say_hello()时,实际执行的是wrapper函数,其中包括了原始的say_hello函数的调用。
(二)带参数的装饰器
装饰器也可以接受参数。要实现带参数的装饰器,你需要创建一个嵌套的装饰器函数:
def repeat(num_times):def decorator(func):def wrapper(*args, **kwargs):for _ in range(num_times):func(*args, **kwargs)return wrapperreturn decorator@repeat(3)
def say_hello():print("Hello!")say_hello()
在这个例子中:
repeat是一个接受参数num_times的外部函数。decorator是实际的装饰器函数。wrapper是用来包装原函数的内部函数,它会根据num_times的值多次调用原函数。
(三)应用场景
装饰器在实际编程中非常有用,常见的应用场景包括:
- 日志记录:记录函数的调用信息。
- 权限检查:检查用户是否有权限调用某个函数。
- 性能计时:测量函数的执行时间。
- 缓存:缓存函数的返回值,以提高性能。
- 输入验证:验证函数参数是否符合要求。
(四)保持元数据
使用装饰器时,通常会改变原函数的一些元数据,如名称和文档字符串。可以使用 functools.wraps 来保留这些元数据
示例:
from functools import wrapsdef my_decorator(func):@wraps(func)def wrapper(*args, **kwargs):print("调用函数之前被执行")result = func(*args, **kwargs)print("调用函数之后被执行")return resultreturn wrapper@my_decorator
def say_hello():"""Prints 'Hello!'"""print("Hello!")print(say_hello.__name__) # 输出 'say_hello'
print(say_hello.__doc__) # 输出 'Prints 'Hello!''
@wraps 装饰器帮助 wrapper 函数保留原函数的元数据(如名称和文档字符串)
(五)总结
装饰器是一种功能强大的工具,可以让你在不修改原始函数代码的情况下,添加额外的功能。理解装饰器的工作原理以及如何创建和使用它们,可以让你写出更加简洁、灵活和可维护的代码。
四、闭包
(一)简介
闭包是一个函数对象,它能记住并访问它所在的词法作用域中的变量,即使在该作用域已经结束时,仍然可以使用这些变量。换句话说,闭包是一种函数,可以捕获其外部环境的变量,使得这些变量即使超出了其正常的生命周期也能在函数内被访问。
闭包是由嵌套函数和自由变量构成的,闭包可以访问这些自由变量,即外部函数作用域中的变量,即使外部函数已经执行完毕。
(二)闭包的结构
一个闭包通常由三部分组成:
- 外部函数:定义了一个包含变量的作用域。
- 内部函数:嵌套在外部函数中并引用了外部函数的变量。
- 闭包环境:内部函数对外部函数作用域中变量的引用,使得这些变量在外部函数结束后仍然有效。
示例:
def outer_function(message):def inner_function():print(message)return inner_functionclosure_function = outer_function("Hello, Python!")
closure_function() # 输出: Hello, Python!
在这个例子中:
outer_function是外部函数,它接受一个参数message。inner_function是嵌套在outer_function中的内部函数,它使用了外部函数的变量message。- 当
outer_function返回inner_function时,message的值仍然被保留并可以在之后调用closure_function()时使用,即使outer_function已经执行完毕。
(三)工作原理
在上述示例中,虽然 outer_function 已经执行结束,但返回的 inner_function依然“记住”了 message 变量的值。这种机制就是闭包的重要特性,函数会保存它们所在的词法作用域中的变量,使得这些变量可以在函数执行后依然有效。python中的闭包通过函数对象的 __closure__ 属性来实现,这个属性包含了对外部作用域变量的引用。
示例:
def outer_function(message):def inner_function():print(message)return inner_functionclosure_function = outer_function("Hello, Python!")
print(closure_function.__closure__) # 输出闭包中的自由变量
print(closure_function.__closure__[0].cell_contents) # 输出自由变量的值 "Hello, Python!"
(四)应用场景
闭包在以下场景中非常有用:
- 数据隐藏:使用闭包可以隐藏数据,实现类似于面向对象编程中的私有变量的效果。
- 函数工厂:创建带有特定参数配置的函数,避免重复写相似逻辑。
- 回调函数:在异步编程或事件驱动编程中,闭包可以保持上下文,确保在执行回调时能访问正确的环境。
- 装饰器:装饰器的实现原理就依赖于闭包,允许在不改变函数定义的情况下扩展其功能。
(五)注意事项
闭包虽然强大,但也有一些需要注意的地方:
- 变量的作用域:闭包只能访问外部函数中的不可变变量,如果你想在内部函数中修改外部变量,必须使用
nonlocal关键字。 - 可能导致内存泄漏:如果闭包引用的外部变量占用较多资源,可能导致内存泄漏,因为这些资源会一直存在,直到闭包被销毁。
(六)闭包中修改外部变量
通常情况下,闭包只能访问外部变量,但不能修改它们。如果需要修改外部函数中的变量,必须使用 nonlocal 关键字:
示例:
def outer_function():count = 0def inner_function():nonlocal count # 使用nonlocal声明count += 1print(count)return inner_functionclosure_function = outer_function()
closure_function() # 输出 1
closure_function() # 输出 2
在这个例子中,nonlocal 允许 inner_function 修改 outer_function 中的 count 变量。
(七)总结
python的闭包是一种函数对象,它能够捕获并“记住”外部函数作用域中的自由变量,使得这些变量在外部函数执行结束后依然可用。闭包在许多高级编程场景中非常有用,比如装饰器、回调函数和数据隐藏等。
五、总结
该篇文章主要讲了python的三器一包,迭代器、生成器、装饰器和闭包,每个知识点都有各自的用途,相信大家都能通过这篇文章体会到其中的差异点,欢迎提出宝贵的意见和建议!!
相关文章:
Python编程 - 三器一包
目录 前言 一、迭代器 (一)基本概念 (二)迭代器和可迭代对象 (三)创建迭代器 (四)内置迭代器函数 (五)优点和局限性 二、生成器 (一&…...
InternVL 多模态模型部署微调实践
友情链接 该文档参考InternVL垂直领域场景微调实践而写成,感谢社区同学法律人的文档。 写在前面(什么是InternVL) InternVL 是一种用于多模态任务的深度学习模型,旨在处理和理解多种类型的数据输入,如图像和文本。它…...
Ruby Dir 类和方法
Ruby Dir 类和方法 Ruby 中的 Dir 类提供了用于处理目录的各种方法。这些方法允许您列出目录内容、更改当前工作目录、创建和删除目录等。本文将详细介绍 Dir 类的常用方法,并通过示例展示如何使用它们。 目录 Dir 类的简介常用方法 Dir.chdirDir.childrenDir.de…...
C++STL~~deque
文章目录 deque的概念deque的使用deque的练习总结 deque的概念 deque(双端队列):是一种序列容器、是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)ÿ…...
SpringCloud的学习,Consul服务注册与发现、分布式配置,以及 服务调用和负载均衡
介绍 Consul 是一套开源的分布式服务发现和配置管理系统,由 HashiCorp 公司用 Go 语言开发。 提供了微服务系统中的服务治理、配置中心、控制总线等功能。这些功能中的每一个都可以根据需要单独使用,也可以一起使用以构建全方位的服务网格,…...
闯关leetcode——26. Remove Duplicates from Sorted Array
大纲 题目地址内容 解题代码地址 题目 地址 https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/ 内容 Given an integer array nums sorted in non-decreasing order, remove the duplicates in-place such that each unique element appear…...
基于A2C与超启发式的航天器星载自主任务规划算法-笔记
1. Actor-Critic 模块 主要文件:AC.py, PolicyNet.py, ValueNet.py作用:该模块实现了 A2C(Advantage Actor-Critic)强化学习算法。其中,ActorCritic 类是核心,它同时管理策略网络(Actor&#x…...
[机器学习]决策树
1 决策树简介 2 信息熵 3 ID3决策树 3.1 决策树构建流程 3.2 决策树案例 4 C4.5决策树 5 CART决策树(分类&回归) 6 泰坦尼克号生存预测案例 import pandas as pd from sklearn.model_selection import train_test_split from sklearn.tree import …...
CentOS7更换阿里云yum更新源
目前CentOS内置的更新安装源经常报错无法更新,或者速度不够理想,这个时候更换国内的镜像源就是一个不错的选择。 备份内置更新源 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup 下载阿里云repo源(需要系统…...
算法参数对拥塞控制的影响
来看看参数对公平收敛的影响。仅假象一下就知道应该是个加权公平,但事实如何,还是要具体看一下。 首先看 aimd,标准的 reno 算法是每 round 之后 cwnd 加 1,但如果有些流加 1,有些流加 2,会如何࿱…...
Go websocket
Go 中的 gorilla/websocket 是一个常用且高效的 WebSocket 实现库,可以帮助你轻松地在 Web 应用中实现实时通信。学习 gorilla/websocket 的基本用法包括建立 WebSocket 连接、发送和接收消息、处理错误、以及在实际场景中的使用。以下是关于 gorilla/websocket 的学…...
C# 委托与事件 观察者模式
委托与事件是一种观察者模式。 什么是委托与事件 在c#中,委托类似于代理,也跟其它语言的函数指针、回调函数等相似,但委托是类型安全和可靠的。声明自定义委托时,加上delegate关键字,委托定义类似于接口。 事件是特殊…...
K8S - 用service account 登陆kubectl
刚安装好k8s时 我就可以用kubectl 在master server里管理k8s的资源。 这时我们是感觉不到 k8s的用户和权限管理存在的, 但是其实用户的配置都在kubeclt 的配置文件中 /etc/kubernetes/admin.conf 中 我们可以用下命令来查看当前正在用的帐号 rootk8s-master:~/.d…...
Redis 持久化机制详解
引言 Redis 是一款基于内存的高性能键值存储系统,为了在数据丢失时能快速恢复,Redis 提供了多种持久化机制。这些持久化机制可以将内存中的数据存储到磁盘上,确保即使系统重启或宕机后也能恢复数据。Redis 支持两种主要的持久化方式…...
小阿轩yx-案例:Zabbix监控kubernetes云原生环境
小阿轩yx-案例:Zabbix监控kubernetes云原生环境 前言 传统监控的本质 就是收集、分析和使用信息来观察一段时间内监控对象的运行进度,并且进行相应的决策管理的过程,监控侧重于观察特定指标。 随着云原生时代的到来 我们对监控的功能提出…...
量化交易的个人见解
程序化交易在国内兴起有些年数了,个人以为,程序化交易与量化投资的关系,在于两者侧重点有差别。程序化交易侧重于下单的动作是机器自动执行的,量化投资则侧重于投资分析的过程是通过一个量化模型来实现的,所以量化投资…...
Java集合(一)
目录 Java集合(一) 集合介绍 单列集合分类 Collection接口 创建Collection实现类对象 常用方法 迭代器 基本使用 迭代器的执行过程 迭代器底层原理 集合中的并发修改异常及原因分析 List接口 ArrayList类 介绍 常用方法 遍历集合 Array…...
车载软件架构 --- SOA设计与应用(下)
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…...
网络原理 IP协议与以太网协议
博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:MySQL数据库 JavaEE专栏:JavaEE 关注博主带你了解更多数据结构知识 目录 1.网络层 IP协议 1.IP协议格式 2.地址管理 2.1 IP地址 2.2 解决IP地址不够用的问题 2.3NAT网络地址转换 2.4网段划分 3.路由选择…...
k8s的安装
k8s的安装 1.创建主机,设置ip,hostname,关闭firewalld,selinux,NetworkManager 编号主机名称ip1k8s-master192.168.118.662k8s-node01192.168.118.773k8s-node02192.168.118.88 2.设置主机之间的ssh免密 [rootk8s-master ~]# ssh-keygen [rootk8s-ma…...
多云管理“拦路虎”:深入解析网络互联、身份同步与成本可视化的技术复杂度
一、引言:多云环境的技术复杂性本质 企业采用多云策略已从技术选型升维至生存刚需。当业务系统分散部署在多个云平台时,基础设施的技术债呈现指数级积累。网络连接、身份认证、成本管理这三大核心挑战相互嵌套:跨云网络构建数据…...
JavaScript 中的 ES|QL:利用 Apache Arrow 工具
作者:来自 Elastic Jeffrey Rengifo 学习如何将 ES|QL 与 JavaScript 的 Apache Arrow 客户端工具一起使用。 想获得 Elastic 认证吗?了解下一期 Elasticsearch Engineer 培训的时间吧! Elasticsearch 拥有众多新功能,助你为自己…...
Day131 | 灵神 | 回溯算法 | 子集型 子集
Day131 | 灵神 | 回溯算法 | 子集型 子集 78.子集 78. 子集 - 力扣(LeetCode) 思路: 笔者写过很多次这道题了,不想写题解了,大家看灵神讲解吧 回溯算法套路①子集型回溯【基础算法精讲 14】_哔哩哔哩_bilibili 完…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
关于iview组件中使用 table , 绑定序号分页后序号从1开始的解决方案
问题描述:iview使用table 中type: "index",分页之后 ,索引还是从1开始,试过绑定后台返回数据的id, 这种方法可行,就是后台返回数据的每个页面id都不完全是按照从1开始的升序,因此百度了下,找到了…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...
Spring Boot+Neo4j知识图谱实战:3步搭建智能关系网络!
一、引言 在数据驱动的背景下,知识图谱凭借其高效的信息组织能力,正逐步成为各行业应用的关键技术。本文聚焦 Spring Boot与Neo4j图数据库的技术结合,探讨知识图谱开发的实现细节,帮助读者掌握该技术栈在实际项目中的落地方法。 …...
CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云
目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...
6.9-QT模拟计算器
源码: 头文件: widget.h #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QMouseEvent>QT_BEGIN_NAMESPACE namespace Ui { class Widget; } QT_END_NAMESPACEclass Widget : public QWidget {Q_OBJECTpublic:Widget(QWidget *parent nullptr);…...
