【python入门到精通专题】6.迭代器与可迭代对象

2024-09-06 10:12

本文主要是介绍【python入门到精通专题】6.迭代器与可迭代对象,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

引入

如果开发中有以下需求,如何解决?

class StuSystem(object):"""学生管理系统"""def __init__(self):self.stus = []def add(self):"""添加一个新的学生:return:"""name = input("请输入新学生的姓名:")tel = input("请输入新学生的手机号:")address = input("请输入新学生的住址:")new_stu = dict()new_stu["name"] = namenew_stu["tel"] = telnew_stu["address"] = addressself.stus.append(new_stu)# 创建管理系统对象
stu_sys = StuSystem()# 添加3个学生信息到系统中
stu_sys.add()
stu_sys.add()
stu_sys.add()# 问题1:怎样才能实现用for循环遍历系统中所有的学生信息呢?下面的方式能实现吗?
for temp in stu_sys:print(temp)# 问题2:如果需要一个列表,这个列表 样子例如 [{'name': '张三', 'id': 10086}, {'name': '李四': 'id': 10087}]
# stu_list = [ ...列表推导式...]
# 这个列表推导式该怎样写才能实现呢?

在实际开发工作中,经常需要快速的将对象转化问其他的不同的数据类型,此时如果能快速的遍历出自定义的对象,这样大大减少代码的冗余,而且可读性会更优美

问题是,怎样实现呢?

今天我们要学习的知识只有1个,那就是迭代器

什么是迭代

迭代是访问序列类型元素的一种方式

nums = [11, 22, 33]# 可以通过for循环将nums列表中的每个数据依次获取
for num in nums:print(num)name = "teacher"for temp in name:print(temp)

我们已经知道可以对listtuplestr等类型的数据使用for...in...的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代

可迭代对象

是否所有的数据类型都可以放到for...in...的语句中,然后让for...in...每次从中取出一条数据供我们使用呢?

weight = 160for item in weight:print(item)  # 报错

通过运行可以发现,并不是所有的类型都可以通过for...in...的方式进行遍历

我们可以通俗的认为:只要是可以通过for...in...的形式进行遍历的,那么这个数据类型就是可以迭代的

例如,下面的是可以迭代的数据类型

  • 列表
  • 元组
  • 字典
  • 字符串

而下面的则不是可以迭代的数据类型

  • 整型
  • 浮点型

那是否可以通过某种方式能够测量出一个数据类型到底是否是可以迭代呢?

In [50]: from collections.abc import IterableIn [51]: isinstance([], Iterable)
Out[51]: TrueIn [52]: isinstance({}, Iterable)
Out[52]: TrueIn [53]: isinstance('abc', Iterable)
Out[53]: TrueIn [54]: isinstance(mylist, Iterable)
Out[54]: FalseIn [55]: isinstance(100, Iterable)
Out[55]: False

只要是通过isinstance来判断出是Iterable类的实例,即isinstance的结果是True那么就表示,这个数据类型是可以迭代的数据类型

迭代器

迭代器是一个可以记住遍历的位置的对象。迭代器对象从第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

可迭代对象的本质

分析 可迭代对象 进行迭代的过程,发现每迭代一次(即在for...in...中每循环一次)都会返回对象中的下一条数据,一直向后读取数据直到迭代了所有数据后结束。

那么,在这个过程中就应该有一个“人”去记录每次访问到了第几条数据,以便每次迭代都可以返回下一条数据。我们把这个能帮助我们进行数据迭代的“人”称为迭代器(Iterator)

可迭代对象的本质就是可以向我们提供一个这样的中间“人”,即迭代器帮助我们对其进行迭代遍历使用。

listtuple等都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。

获取可迭代对象的迭代器

from collections.abc import Iteratornums = [11, 22, 33, 44]print(type(nums))nums_iter = iter(nums)print(type(nums_iter))print("nums", isinstance(nums, Iterator))
print("nums_iter", isinstance(nums_iter, Iterator))

获取迭代器的数据

上面提到,通过iter()能够得到一个可迭代对象的 迭代器,可以通过next()函数多次提取迭代器中的数据,下面我们就测试下

测试代码如下:

from collections.abc import Iteratornums = [11, 22, 33, 44]
nums_iter = iter(nums)print("nums", isinstance(nums, Iterator))
print("nums_iter", isinstance(nums_iter, Iterator))num1 = next(nums_iter)
print(num1)num2 = next(nums_iter)
print(num2)num3 = next(nums_iter)
print(num3)num4 = next(nums_iter)
print(num4)

StopIteration 异常

如果将上面的代码,多写一次的next()会怎样呢?看如下测试代码:

from collections.abc import Iteratornums = [11, 22, 33, 44]
nums_iter = iter(nums)print("nums", isinstance(nums, Iterator))
print("nums_iter", isinstance(nums_iter, Iterator))num1 = next(nums_iter)
print(num1)num2 = next(nums_iter)
print(num2)num3 = next(nums_iter)
print(num3)num4 = next(nums_iter)
print(num4)num5 = next(nums_iter)  # 这里会产生异常
print(num5)

可以看到23行,即第5次调用next()时,产生了异常。why??????

因为列表nums中只有4个数据,也就是说可以调用4次next是完全合理的,但是如果,调用的次数多了肯定是不合理,都没有5个数据,怎么可以能取5次呢!显然是不对的

此时估计想明白了,为什么会产生异常,其实就是一种告知迭代结束的标志而已

添加try...except...即可解决刚刚遇到的问题

try:num5 = next(nums_iter)print(num5)
except StopIteration as e:print(f'迭代结束: {e}')
自定义迭代器

大家是否还记得 在刚开学习今天的知识时,我们引入了一个学生管理系统的问题,该怎样实现呢

我们下面来谈谈

  • __iter__方法
  • __next__方法

__iter__方法

上面提到iter()方法必须是对”可迭代“对象 才能 提取到 ”迭代器“对象,但是怎样保证自定义的对象是”可迭代“对象呢?

答:只要在类中定义__iter__方法,那么这个类创建出来的对象一定是可迭代对象

通俗的说:一个具备了__iter__方法的对象就是一个可以迭代的对象

测试代码一:无__iter__方法

from collections.abc import Iterableclass MyList(object):def __init__(self):self.container = []def add(self, item):self.container.append(item)mylist = MyList()
mylist.add(11)
mylist.add(22)
mylist.add(33)print("mylist是否是可以迭代对象", isinstance(mylist, Iterable))for temp in mylist:print(temp)

运行结果:

mylist是否是可以迭代对象 False
Traceback (most recent call last):File "/home/ubuntu/Desktop/stu_code/测试代码.py", line 19, in <module>for temp in mylist:
TypeError: 'MyList' object is not iterable

测试代码二:有__iter__方法

from collections.abc import Iterableclass MyList(object):def __init__(self):self.container = []def add(self, item):self.container.append(item)def __iter__(self):passmylist = MyList()
mylist.add(11)
mylist.add(22)
mylist.add(33)print("mylist是否是可以迭代对象", isinstance(mylist, Iterable))for temp in mylist:print(temp)

运行结果:

mylist是否是可以迭代对象 True
Traceback (most recent call last):File "/home/ubuntu/Desktop/stu_code/测试代码.py", line 21, in <module>for temp in mylist:
TypeError: iter() returned non-iterator of type 'NoneType'

能够看出,一个类,只要有__iter__方法,那么这个类创建出来的对象就是可以迭代对象

其实,当我们调用iter()函数提取一个可迭代对象的 迭代器时,实际上会自动调用这个对象的__iter__方法,并且这个方法返回迭代器

__next__方法

通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。

实际上,在使用next()函数的时候,调用的就是迭代器对象的__next__方法(Python3中是对象的__next__方法,Python2中是对象的next()方法)。

所以,我们要想构造一个迭代器,就要实现它的__next__方法。

但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。

一个实现了__iter__方法和__next__方法的对象,就是迭代器

如何判断一个对象是否是迭代器

可以使用 isinstance() 判断一个对象是否是 Iterator 对象:

In [56]: from collections.abc import IteratorIn [57]: isinstance([], Iterator)
Out[57]: FalseIn [58]: isinstance(iter([]), Iterator)
Out[58]: TrueIn [59]: isinstance(iter("abc"), Iterator)
Out[59]: True

自定义迭代器:

from collections.abc import Iterable
from collections.abc import Iteratorclass MyList(object):"""自定义的一个可迭代对象"""def __init__(self):self.items = []def add(self, val):self.items.append(val)def __iter__(self):return MyIterator()class MyIterator(object):"""自定义的供上面可迭代对象使用的一个迭代器"""def __init__(self):passdef __next__(self):passdef __iter__(self):passmylist = MyList()
mylist_iter = iter(mylist)print("mylist是否是可以迭代对象", isinstance(mylist, Iterable))
print("mylist是否是迭代器", isinstance(mylist, Iterator))print("mylist_iter是否是可以迭代对象", isinstance(mylist_iter, Iterable))
print("mylist_iter是否是迭代器", isinstance(mylist_iter, Iterator))

运行结果:

mylist是否是可以迭代对象 True
mylist是否是迭代器 False
mylist_iter是否是可以迭代对象 True
mylist_iter是否是迭代器 True

自定义迭代器案例

class MyList(object):"""自定义的一个可迭代对象"""def __init__(self):self.items = []def add(self, val):self.items.append(val)def __iter__(self):myiterator = MyIterator(self)return myiteratorclass MyIterator(object):"""自定义的供上面可迭代对象使用的一个迭代器"""def __init__(self, mylist):self.mylist = mylist# current用来记录当前访问到的位置self.current = 0def __next__(self):if self.current < len(self.mylist.items):item = self.mylist.items[self.current]self.current += 1return itemelse:raise StopIterationdef __iter__(self):return selfif __name__ == '__main__':mylist = MyList()mylist.add(1)mylist.add(2)mylist.add(3)mylist.add(4)mylist.add(5)for num in mylist:print(num)

运行结果:

1
2
3
4
5

可迭代对象通过__iter__方法向我们返回一个迭代器,我们在迭代一个可迭代对象的时候,实际上就是先获取该对象提供的一个迭代器,然后通过这个迭代器来依次获取对象中的每一个数据。

for...in...循环的本质
  1. 先调用iter()函数,它会自动调用可迭代对象中的__iter__方法,此方法返回这个可迭代对象的 迭代器对象
  2. 对获取到的迭代器不断调用next()函数,它会自动调用迭代器中的__next__方法来获取下一个值
  3. 当遇到StopIteration异常后循环结束
并不是只有for循环能接收可迭代对象

除了for循环能接收可迭代对象,listtuple等也能接收。

测试代码如下:

class MyList(object):"""自定义的一个可迭代对象"""def __init__(self):self.items = []def add(self, val):self.items.append(val)def __iter__(self):myiterator = MyIterator(self)return myiteratorclass MyIterator(object):"""自定义的供上面可迭代对象使用的一个迭代器"""def __init__(self, mylist):self.mylist = mylist# current用来记录当前访问到的位置self.current = 0def __next__(self):if self.current < len(self.mylist.items):item = self.mylist.items[self.current]self.current += 1return itemelse:raise StopIterationdef __iter__(self):return selfif __name__ == '__main__':mylist = MyList()mylist.add(1)mylist.add(2)mylist.add(3)mylist.add(4)mylist.add(5)nums = list(mylist)print(nums)

运行结果:

[1, 2, 3, 4, 5]
简单总结
  • 凡是可作用于for 循环的对象都是 Iterable 类型
  • 凡是可作用于 next() 函数的对象都是 Iterator 类型
  • 序列数据类型如 listdictstr等是 Iterable 但不是Iterator,不过可以通过 iter() 函数获得一个 Iterator 对象
随堂作业

既然已经学习过了迭代器,那么今天刚开始的知识点也就自然有了答案

  • 实现用for循环遍历学生系统中的所有学生信息
class StuSystem(object):"""学生管理系统"""def __init__(self):self.stus = []self.current_num = 0def add(self):"""添加一个新的学生:return:"""name = input("请输入新学生的姓名:")tel = input("请输入新学生的手机号:")address = input("请输入新学生的住址:")new_stu = dict()new_stu["name"] = namenew_stu["tel"] = telnew_stu["address"] = addressself.stus.append(new_stu)def __iter__(self):return selfdef __next__(self):if self.current_num < len(self.stus):ret = self.stus[self.current_num]self.current_num += 1return retelse:self.current_num = 0raise StopIteration# 创建管理系统对象
stu_sys = StuSystem()# 添加3个学生信息到系统中
stu_sys.add()
stu_sys.add()
stu_sys.add()# 问题1:怎样才能实现用for循环遍历系统中所有的学生信息呢?下面的方式能实现吗?
for temp in stu_sys:print(temp)

运行结果:

(base) ubuntu@VM-16-5-ubuntu:~/Desktop/stu_code$ /home/ubuntu/miniconda3/bin/python /home/ubuntu/Desktop/stu_code/测试代码.py
请输入新学生的姓名:顾安
请输入新学生的手机号:13711111111
请输入新学生的住址:长沙
请输入新学生的姓名:安娜
请输入新学生的手机号:13711111112
请输入新学生的住址:长沙
请输入新学生的姓名:双双
请输入新学生的手机号:13711111113
请输入新学生的住址:长沙
{'name': '顾安', 'tel': '13711111111', 'address': '长沙'}
{'name': '安娜', 'tel': '13711111112', 'address': '长沙'}
{'name': '双双', 'tel': '13711111113', 'address': '长沙'}
  • 对输入的数据进行格式转换
class StuSystem(object):"""学生管理系统"""def __init__(self):self.stus = []self.current_num = 0def add(self):"""添加一个新的学生:return:"""name = input("请输入新学生的姓名:")tel = input("请输入新学生的手机号:")address = input("请输入新学生的住址:")new_stu = dict()new_stu["name"] = namenew_stu["tel"] = telnew_stu["address"] = addressself.stus.append(new_stu)def __iter__(self):return selfdef __next__(self):if self.current_num < len(self.stus):ret = self.stus[self.current_num]self.current_num += 1return retelse:self.current_num = 0raise StopIterationstu_sys = StuSystem()stu_sys.add()
stu_sys.add()
stu_sys.add()stu_list = [x for x in stu_sys]
print(stu_list)

运行结果:

请输入新学生的姓名:顾安
请输入新学生的手机号:13711111111
请输入新学生的住址:长沙
请输入新学生的姓名:安娜
请输入新学生的手机号:13711111112
请输入新学生的住址:南京
请输入新学生的姓名:双双
请输入新学生的手机号:13711111113
请输入新学生的住址:上海
[{'name': '顾安', 'tel': '13711111111', 'address': '长沙'}, {'name': '安娜', 'tel': '13711111112', 'address': '南京'}, {'name': '双双', 'tel': '13711111113', 'address': '上海'}]
结语

以上就是关于python专题中的迭代器全部内容了,欢迎同学们在评论区讨论交流,有任何python开发、数据采集相关需求也可以后台或V加regentwan与我联系哟~

这篇关于【python入门到精通专题】6.迭代器与可迭代对象的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1141738

相关文章

Python使用自带的base64库进行base64编码和解码

《Python使用自带的base64库进行base64编码和解码》在Python中,处理数据的编码和解码是数据传输和存储中非常普遍的需求,其中,Base64是一种常用的编码方案,本文我将详细介绍如何使... 目录引言使用python的base64库进行编码和解码编码函数解码函数Base64编码的应用场景注意

Spring Boot + MyBatis Plus 高效开发实战从入门到进阶优化(推荐)

《SpringBoot+MyBatisPlus高效开发实战从入门到进阶优化(推荐)》本文将详细介绍SpringBoot+MyBatisPlus的完整开发流程,并深入剖析分页查询、批量操作、动... 目录Spring Boot + MyBATis Plus 高效开发实战:从入门到进阶优化1. MyBatis

Python基于wxPython和FFmpeg开发一个视频标签工具

《Python基于wxPython和FFmpeg开发一个视频标签工具》在当今数字媒体时代,视频内容的管理和标记变得越来越重要,无论是研究人员需要对实验视频进行时间点标记,还是个人用户希望对家庭视频进行... 目录引言1. 应用概述2. 技术栈分析2.1 核心库和模块2.2 wxpython作为GUI选择的优

Python如何使用__slots__实现节省内存和性能优化

《Python如何使用__slots__实现节省内存和性能优化》你有想过,一个小小的__slots__能让你的Python类内存消耗直接减半吗,没错,今天咱们要聊的就是这个让人眼前一亮的技巧,感兴趣的... 目录背景:内存吃得满满的类__slots__:你的内存管理小助手举个大概的例子:看看效果如何?1.

Python+PyQt5实现多屏幕协同播放功能

《Python+PyQt5实现多屏幕协同播放功能》在现代会议展示、数字广告、展览展示等场景中,多屏幕协同播放已成为刚需,下面我们就来看看如何利用Python和PyQt5开发一套功能强大的跨屏播控系统吧... 目录一、项目概述:突破传统播放限制二、核心技术解析2.1 多屏管理机制2.2 播放引擎设计2.3 专

Python中随机休眠技术原理与应用详解

《Python中随机休眠技术原理与应用详解》在编程中,让程序暂停执行特定时间是常见需求,当需要引入不确定性时,随机休眠就成为关键技巧,下面我们就来看看Python中随机休眠技术的具体实现与应用吧... 目录引言一、实现原理与基础方法1.1 核心函数解析1.2 基础实现模板1.3 整数版实现二、典型应用场景2

Python实现无痛修改第三方库源码的方法详解

《Python实现无痛修改第三方库源码的方法详解》很多时候,我们下载的第三方库是不会有需求不满足的情况,但也有极少的情况,第三方库没有兼顾到需求,本文将介绍几个修改源码的操作,大家可以根据需求进行选择... 目录需求不符合模拟示例 1. 修改源文件2. 继承修改3. 猴子补丁4. 追踪局部变量需求不符合很

在java中如何将inputStream对象转换为File对象(不生成本地文件)

《在java中如何将inputStream对象转换为File对象(不生成本地文件)》:本文主要介绍在java中如何将inputStream对象转换为File对象(不生成本地文件),具有很好的参考价... 目录需求说明问题解决总结需求说明在后端中通过POI生成Excel文件流,将输出流(outputStre

python+opencv处理颜色之将目标颜色转换实例代码

《python+opencv处理颜色之将目标颜色转换实例代码》OpenCV是一个的跨平台计算机视觉库,可以运行在Linux、Windows和MacOS操作系统上,:本文主要介绍python+ope... 目录下面是代码+ 效果 + 解释转HSV: 关于颜色总是要转HSV的掩膜再标注总结 目标:将红色的部分滤

Python 中的异步与同步深度解析(实践记录)

《Python中的异步与同步深度解析(实践记录)》在Python编程世界里,异步和同步的概念是理解程序执行流程和性能优化的关键,这篇文章将带你深入了解它们的差异,以及阻塞和非阻塞的特性,同时通过实际... 目录python中的异步与同步:深度解析与实践异步与同步的定义异步同步阻塞与非阻塞的概念阻塞非阻塞同步