流畅的Python(十四)-可迭代对象、迭代器和生成器

一、核心要义

1. 使用iter内置函数处理可迭代对象的方式

2. 如何使用Python实现经典的迭代器模式

3. 生成器函数工作原理

4. 使用生成器函数或生成器表达式代替经典的迭代器

5. 使用yield from语句合并生成器

二、代码示例

1、遍历单词序列回顾

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/26 20:42
# @Author  : Maple
# @File    : 01-遍历单词序列回顾.py
# @Software: PyCharm
from collections import abc
import re
import reprlibRE_WORDS = re.compile('\w+')
class Sentence:def __init__(self,text):self.text =  textself.words = RE_WORDS.findall(text)def __getitem__(self, pos):return self.words[pos]def __len__(self):return len(self.words)def __repr__(self):return 'Sentences(%s) ' % reprlib.repr(self.text)class Foo:def __iter__(self):passif __name__ == '__main__':# 1. 迭代Sentence对象s = Sentence('I love this word')"""s可迭代的原因1. 当迭代一个对象的时候,解释器会检查对象是否实现了__iter__方法,如果实现了,就调用它,获取一个迭代器2. 如果没有实现__iter__方法,但是实现了__getitem__方法,Python会创建一个迭代器,尝试按顺序(从索引0开始)获取元素3. 如果尝试失败,Python抛出TypeError异常,通常会提示"C object is not itereble""""for word in s:"""Ilovethisword"""print(word)# 2. Sentence对象是否可通过issubclass和isinstance测试# 虽然Sentence对象实现了 __getitem__,因为是可迭代的,但其实无法通过测试# 所以如果要判断一个对象是否可迭代,最好不要使用该方式,而是直接iter(对象),如果没有报错,就说明对象是可迭代的print(issubclass(Sentence,abc.Iterable)) # Falseprint(isinstance(s,abc.Iterable)) # False## 获取迭代器s = iter(s)## 迭代迭代器中的元素for word in s:print(word)# 3.一个类只要实现了__iter__方法,那么其对象就是可迭代的,并且可以通过issubclass和isinstance测试f = Foo()print(issubclass(Foo, abc.Iterable))  # Trueprint(isinstance(f, abc.Iterable))  # True

2、可迭代对象和迭代器

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/26 21:03
# @Author  : Maple
# @File    : 02-可迭代对象和迭代器.py
# @Software: PyCharm"""
两者的定义和关系:1.可迭代对象: 实现了__iter__方法2.迭代器: 实现了__iter__和__next__方法"""
import re
import reprlibRE_WORDS = re.compile('\w+')"""
1.利用__iter__方法定义一个类,当调用iter方法时,返回一个迭代器
2.对迭代器进行遍历的时候,不断调用next方法,返回迭代器中的每一个元素
"""
class Sentence:def __init__(self,text):self.text =  textself.words = RE_WORDS.findall(text)def __iter__(self):return SentenceIterator(self.words)def __len__(self):return len(self.words)def __repr__(self):return 'Sentences(%s) ' % reprlib.repr(self.text)class SentenceIterator:"""定义迭代器:__iter__方法和__next__方法"""def __init__(self,words):self.words = wordsself.index = 0def __iter__(self):"""迭代器应该一直可以迭代,所以返回自身,在哪里会用到这个特性? """return selfdef __next__(self):try:word = self.words[self.index]except IndexError:raise StopIteration()self.index += 1return wordif __name__ == '__main__':# 1. Sentence测试s = Sentence('I love this world')for word in s:print(s)# 2.s2是一个迭代器## 2-1 直接调用迭代器类 生成一个迭代器print('******2-1 直接调用迭代器类 生成一个迭代器************')s2 = SentenceIterator(['we', 'are', 'the', 'world'])print('s2:',s2)index = 0for word in s2:"""weare"""index += 1if index > 1:print(word)breakelse:print(word)## 2-2 调用迭代器的iter方法,返回迭代器本身print('******2-2 调用迭代器的iter方法,返回迭代器本身************')s3 = iter(s2)print('s3:',s3)for word in s3:"""在2-1的基础上,继续迭代,直到迭代结束theworld"""print(word)

3、生成器函数

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/26 21:42
# @Author  : Maple
# @File    : 03-生成器函数.py
# @Software: PyCharm"""
对上一小节的Sentence进一步改造:__iter__方法不用返回一个迭代器.而是直接将其定义为一个生成器函数
--什么是生成器函数: 包含yield关键
"""
import re
import reprlibRE_WORDS = re.compile('\w+')# 利用生成器函数,实现Sentence类对象的可迭代(不用在__iter__方法中返回迭代器)
class Sentence1:def __init__(self,text):self.text =  textself.words = RE_WORDS.findall(text)def __repr__(self):return 'Sentences(%s) ' % reprlib.repr(self.text)def __iter__(self):for word in self.words:yield wordreturndef __len__(self):return len(self.words)# 对Sentence1进一步改造:self.words不需要提前生成(是一个列表)
class Sentence2:def __init__(self,text):self.text = textdef __repr__(self):return 'Sentences(%s) ' % reprlib.repr(self.text)def __iter__(self):# RE_WORDS.finditer(self.text)返回的是一个迭代器# 通过for循环遍历迭代器for match in RE_WORDS.finditer(self.text):yield match.group()return# 利用生成器表达式,进一步改造Sentence
class Sentence3:def __init__(self,text):self.text = textdef __repr__(self):return 'Sentences(%s) ' % reprlib.repr(self.text)def __iter__(self):# 直接返回生成器表达式,与yield的作用相同return (match.group() for  match in RE_WORDS.finditer(self.text))if __name__ == '__main__':# 1.Sentence1测试s = Sentence1('I love this world')##  调用iter返回一个生成器s_iter = iter(s)## 遍历生成器(本质就是一个迭代器)for word in s_iter:"""Ilovethisword"""print(word)# 2.Sentence2测试print('******2.Sentence2测试***********')s2 = Sentence2('Please stay with me forerver')##  调用iter返回一个生成器s_iter2 = iter(s2)## 遍历生成器(本质就是一个迭代器)for word in s_iter2:"""Pleasestaywithmeforerver"""print(word)# 3.Sentence3测试print('******3.Sentence3测试***********')s3 = Sentence3("Let's start study Python")##  调用iter返回一个生成器s_iter3 = iter(s3)## 遍历生成器(本质就是一个迭代器)for word in s_iter3:"""LetsstartstudyPython"""print(word)

4、等差数列生成器

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/27 20:03
# @Author  : Maple
# @File    : 04-等差数列生成器.py
# @Software: PyCharm# 自定义等差序列生成器
from decimal import Decimalclass ArithmeticProgression:def __init__(self,start,step,end=None):self.start = startself.step = stepself.end = enddef __iter__(self):index = 0result = type(self.start + self.step)(self.start)forever = self.end is Nonewhile forever or result < self.end:yield resultindex += 1result = self.start + self.step * indexclass ArithmeticProgression2:def __init__(self,start,step,end=None):self.start = startself.step = stepself.end = enddef __iter__(self):ap_gen = itertools.count(self.start, self.step)if self.end is not None:ap_gen =  itertools.takewhile(lambda n: n < self.end, itertools.count(self.start, self.step))# 直接返回迭代器return ap_genif __name__ == '__main__':# 1. 自定义等差序列生成器测试## 1-1: 起始值1,步长为0.5,末项是5(不包含)a1 = ArithmeticProgression(1,0.5,5)for i in a1:"""1.01.52.02.53.03.54.04.5"""print(i)## 1-2: 起始值1,步长为Decimal(0.2),末项是2(不包含)a2 = ArithmeticProgression(1, Decimal(.2),2)for i in a2:"""11.2000000000000000111022302461.4000000000000000222044604921.6000000000000000333066907391.800000000000000044408920985"""print(i)#2.利用系统自带的itertools模块生成等差数列print('*****2.利用系统自带的itertools模块生成等差数列********')import itertools## 2-1 注意:由于该模块方法并没有end参数,如果通过for循环遍历,会生成无穷的序列..直到内存爆掉g = itertools.count(1,0.5)print(next(g)) # 1print(next(g)) # 1.5## 2-2 为了修复上面提到的弊端,可以利用# 该方法返回的是一个迭代器,然后接收两个参数:当第二个迭代器中的元素,不满足第一个参数设置的条件时,会终止第二个迭代器迭代gen = itertools.takewhile(lambda n: n <3,itertools.count(1,0.5))print(list(gen)) # [1, 1.5, 2.0, 2.5]# 3.利用itertools.takewhile改造ArithmeticProgressionprint('******3.利用itertools.takewhile改造ArithmeticProgression**********************')a3 = ArithmeticProgression2(1, 0.5, 5)print(list(a3)) # [1, 1.5, 2.0, 2.5, 3.0, 3.5, 4.0, 4.5]a4 = ArithmeticProgression2(1, Decimal(.2), 2)print(list(a4)) # [1, Decimal('1.200000000000000011102230246'), Decimal('1.400000000000000022204460492'), Decimal('1.600000000000000033306690738'), Decimal('1.800000000000000044408920984')]

5、yield from

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/27 20:36
# @Author  : Maple
# @File    : 05-yield from.py
# @Software: PyCharm"""
当生成器函数需要产出另一个生成器 生成的值,传统的解决方案是for循环嵌套"""def chain(*iterables):for it in iterables:for i in it:yield i# 利用yield from
def chain2(*iterables):for it in iterables:yield from itif __name__ == '__main__':#1.chain方法测试s = 'ABC't = tuple(range(3))# ['A', 'B', 'C', 0, 1, 2]print(list(chain(s,t)))#2.chain2方法测试s = 'EDF't = tuple(range(3))# ['A', 'B', 'C', 0, 1, 2]print(list(chain2(s, t))) # ['E', 'D', 'F', 0, 1, 2]

6、可迭代的归约函数

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/27 20:45
# @Author  : Maple
# @File    : 06-可迭代的归约函数.py
# @Software: PyCharmif __name__ == '__main__':print(all([1,2,3])) #Trueprint(all([1,0,3])) #Falseprint(any([1,2,3])) #Trueprint(any([1,0,3])) #Trueprint(any([0,0.0])) #Falseprint(any([])) #Falseg = (n for n in [0,0.0,7,8])print(any(g)) #True

7、迭代器哨值

#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2024/2/27 20:50
# @Author  : Maple
# @File    : 07-迭代器哨值.py
# @Software: PyCharm"""
迭代器函数iter可以传入两个参数:其中第一个必须是一个可调用对象,第二个就是哨值,当可调用对象返回这个值时,迭代器将停止迭代
"""
from random import randintdef f6():# 返回[1-6]区间的整数return randint(1,6)if __name__ == '__main__':# print(randint(1,6))f6_iter = iter(f6,1)for i in f6_iter:# 如下结果表明,第三次迭代的值是1,然后迭代终止"""24"""print(i)

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

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

相关文章

电脑WiFi共享给电脑的网口,另一终端可通过该网口进行上网。可用于wireshark抓设备终端的包。

1、点击WinR&#xff0c;弹出命令框&#xff0c;输入services.msc 2、选中“Internet Connection Sharing”这个服务右键&#xff0c;点击属性打开&#xff0c;启动类型选择“自动”&#xff0c;确定保存 3、点击WinR&#xff0c;弹出命令框&#xff0c;输入regedit 4、找到路径…

Qt中的QGraphicView和QGraphicScene简单使用

概述&#xff1a;我们利用QGraphicView和QGraphicScene来实现一个简单的视频播放器&#xff0c;然后上面悬浮一些操作的控件&#xff0c;看看怎么来实现。 1、CcTestVideoPlayer类 模拟播放器类&#xff0c;继承QGraphicScene 1.1 CcTestVideoPlayer.h #pragma once#include…

【ArcGIS】重采样栅格像元匹配问题:不同空间分辨率栅格数据统一

重采样栅格像元匹配问题&#xff1a;不同空间分辨率栅格数据统一 原始数据数据1&#xff1a;GDP分布数据2.1&#xff1a;人口密度数据2.2&#xff1a;人口总数数据3&#xff1a;土地利用类型 数据处理操作1&#xff1a;将人口密度数据投影至GDP数据&#xff08;栅格数据的投影变…

LVS做集群四层负载均衡的简单理解

背景&#xff1a;业务中主要是TCP/SSL连接&#xff0c;要做四层负载均衡。 之前做负载均衡&#xff0c;调研了nginx&#xff08;见之前的nginx实现后端服务负载均衡和nginx负载均衡监测后台服务状态&#xff09;。 nginx作为一个应用&#xff0c;做四层负载均衡效率低。lvs是li…

非同质化权益(NFR):重塑数字资产权益的生态系统

每天五分钟讲解一个互联网知识&#xff0c;大家好我是啊浩 随着区块链技术的深入发展和普及&#xff0c;数字资产已经逐渐渗透到我们生活的方方面面。在这一背景下&#xff0c;非同质化权益&#xff08;NFR&#xff09;作为一种新型的数字资产形式&#xff0c;不仅为数字资产权…

eBPF实践篇之环境搭建

文章目录 前言实验环境前置知识配置开发环境最后 前言 你好&#xff0c;我是醉墨居士&#xff0c;本次我们学习一下eBPF&#xff0c;我们基于libbpf-bootstrap来进行我们的eBPF程序开发&#x1f917; 实验环境 一台Debian12操作系统的计算机&#xff0c;我使用的是Debian12.…

什么是索引?它们在MySQL中是如何工作的?什么是视图(View)?它们有什么用?

什么是索引&#xff1f;它们在MySQL中是如何工作的&#xff1f; 索引在MySQL中是一个数据结构&#xff0c;它帮助快速查询数据库中的数据。没有索引&#xff0c;查询可能需要遍历整个数据库表&#xff0c;这称为全表扫描&#xff0c;对于大型表来说非常慢。 索引的工作原理是创…

SpringBoot案例(黑马学习笔记)

这个案例呢&#xff0c;就是Tlias智能学习辅助系统。 参考接口文档完成后端功能的开 发&#xff0c;然后结合前端工程进行联调测试即可。 完成后的成品效果展示&#xff1a; 准备工作 需求&环境搭建 需求说明 部门管理 部门管理功能开发包括&#xff1a; ● 查询部门列…

亚信安慧AntDB数据库与流式处理的有机融合

流式处理的概念 2001年9月11日&#xff0c;美国世贸大楼被袭击&#xff0c;美国国防部第一次将“主动预警”纳入国防的宏观战略规划。而IBM作为当时全球最大的IT公司&#xff0c;承担了大量基础支撑软件研发的任务。其中2009年正式发布的IBM InfoSphere Streams&#xff0c;就是…

杰理-按键多次按下识别多击

杰理-按键多次按下识别多击 #define ALL_KEY_EVENT_CLICK_ONLY 0 //是否全部按键只响应单击事件

自动化测试高效学习路线指导,提高你百倍自学效率

前言 从各方来的朋友&#xff0c;能够相聚这篇文章是大家的缘分&#xff0c;也是我的荣幸。 接下来&#xff0c;我要开始和大家讲讲如何从0开始学Python自动化测试。 不论是转行自动化测试还是功能测试进阶自动化还是开发转自动化测试的伙伴&#xff0c;这篇自动化测试工程师…

Zookeeper客户端命令、JAVA API、监听原理、写数据原理以及案例

1. Zookeeper节点信息 指定服务端&#xff0c;启动客户端命令&#xff1a; bin/zkCli.sh -server 服务端主机名:端口号 1&#xff09;ls / 查看根节点下面的子节点 ls -s / 查看根节点下面的子节点以及根节点详细信息 其中&#xff0c;cZxid是创建节点的事务id&#xff0c…

Rocky Linux 运维工具 firewall-cmd

一、firewall-cmd​的简介 ​​firewall-cmd​是基于firewalld的防火墙管理工具。用户可以使用它来配置、监控和管理防火墙规则&#xff0c;包括开放端口、设置服务规则等。 二、firewall-cmd​​的参数说明 序号参数描述1​​–zone指定防火墙区域2–add-portxxx/tcp允许特定…

tkinterFrame框架+标签框架LabelFrame+Toplevel窗口的使用

1.在tkinter中&#xff0c;Frame是一个容器小部件用于组织和管理其他小部件。它可以作为一个独立的可见区域&#xff0c;也可以作为其他小部件的父容器。 import tkinter as tk import tkinter.ttk as ttk import tkinter.messagebox as mbm tk.Tk() m.title("tkinter L…

MSSQL渗透测试

目录 mssql数据库连接提权至服务器权限 拿到目标的IP地址&#xff0c;我们先对IP地址进行信息收集&#xff0c;收集信息资产&#xff0c;同时使用nmap对IP地址进行扫描 nmap -sC -sV IP从扫描的结果中&#xff0c;我们能知道目标服务器是windows操作系统&#xff0c;使用的是m…

DAY10-内容安全过滤技术概述

文件过滤技术流程: 应用行为控制技术具体:

W-TinyLFU 算法实现

前言 不同于常见的 LRU 或 LFU&#xff0c;Window TinyLFU 是一种非常高效的缓存设计方案。先来看下 LRU 和 LFU 算法的缺点&#xff1a; LFU 缺点&#xff1a; 需要为每个记录项维护频率信息&#xff0c;这将消耗大量的内存空间可能存在旧数据长期不被淘汰&#xff08;一开…

快速卷积介绍

快速卷积是一种使用快速傅里叶变换&#xff08;FFT&#xff09;来有效计算两个序列&#xff08;信号、函数等&#xff09;卷积的方法。快速卷积对于数字信号处理、图像处理、音频处理等领域至关重要&#xff0c;因为它大大提高了计算卷积的效率。 卷积的概念 卷积是一种数学运…

让AI给你写代码,初体验(二)-写一个flask应用

这里我们准备让AI做一个稍微复杂一点任务&#xff0c;写一个前后应用&#xff0c;具体&#xff1a; 前台用html输入股票代码&#xff0c;后台通过akshare的接口程序获取该股票的实时价格&#xff0c;然后返回显示在html 我们先用AI对话看一下&#xff0c;AI会给我们什么编码建…

Flink Catalog

1.Flink侧创建 按照SQL的解析处理流程在Parse解析SQL以后&#xff0c;进入执行流程——executeInternal。   其中有个分支专门处理创建Catalog的SQL命令 } else if (operation instanceof CreateCatalogOperation) {return createCatalog((CreateCatalogOperation) operatio…