【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实现IP地址和端口状态检测与监控

《使用Python实现IP地址和端口状态检测与监控》在网络运维和服务器管理中,IP地址和端口的可用性监控是保障业务连续性的基础需求,本文将带你用Python从零打造一个高可用IP监控系统,感兴趣的小伙... 目录概述:为什么需要IP监控系统使用步骤说明1. 环境准备2. 系统部署3. 核心功能配置系统效果展

基于Python打造一个智能单词管理神器

《基于Python打造一个智能单词管理神器》这篇文章主要为大家详细介绍了如何使用Python打造一个智能单词管理神器,从查询到导出的一站式解决,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 项目概述:为什么需要这个工具2. 环境搭建与快速入门2.1 环境要求2.2 首次运行配置3. 核心功能使用指

Python实现微信自动锁定工具

《Python实现微信自动锁定工具》在数字化办公时代,微信已成为职场沟通的重要工具,但临时离开时忘记锁屏可能导致敏感信息泄露,下面我们就来看看如何使用Python打造一个微信自动锁定工具吧... 目录引言:当微信隐私遇到自动化守护效果展示核心功能全景图技术亮点深度解析1. 无操作检测引擎2. 微信路径智能获

Python中pywin32 常用窗口操作的实现

《Python中pywin32常用窗口操作的实现》本文主要介绍了Python中pywin32常用窗口操作的实现,pywin32主要的作用是供Python开发者快速调用WindowsAPI的一个... 目录获取窗口句柄获取最前端窗口句柄获取指定坐标处的窗口根据窗口的完整标题匹配获取句柄根据窗口的类别匹配获取句

利用Python打造一个Excel记账模板

《利用Python打造一个Excel记账模板》这篇文章主要为大家详细介绍了如何使用Python打造一个超实用的Excel记账模板,可以帮助大家高效管理财务,迈向财富自由之路,感兴趣的小伙伴快跟随小编一... 目录设置预算百分比超支标红预警记账模板功能介绍基础记账预算管理可视化分析摸鱼时间理财法碎片时间利用财

Python中的Walrus运算符分析示例详解

《Python中的Walrus运算符分析示例详解》Python中的Walrus运算符(:=)是Python3.8引入的一个新特性,允许在表达式中同时赋值和返回值,它的核心作用是减少重复计算,提升代码简... 目录1. 在循环中避免重复计算2. 在条件判断中同时赋值变量3. 在列表推导式或字典推导式中简化逻辑

python处理带有时区的日期和时间数据

《python处理带有时区的日期和时间数据》这篇文章主要为大家详细介绍了如何在Python中使用pytz库处理时区信息,包括获取当前UTC时间,转换为特定时区等,有需要的小伙伴可以参考一下... 目录时区基本信息python datetime使用timezonepandas处理时区数据知识延展时区基本信息

Python位移操作和位运算的实现示例

《Python位移操作和位运算的实现示例》本文主要介绍了Python位移操作和位运算的实现示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 位移操作1.1 左移操作 (<<)1.2 右移操作 (>>)注意事项:2. 位运算2.1

使用Python和Pyecharts创建交互式地图

《使用Python和Pyecharts创建交互式地图》在数据可视化领域,创建交互式地图是一种强大的方式,可以使受众能够以引人入胜且信息丰富的方式探索地理数据,下面我们看看如何使用Python和Pyec... 目录简介Pyecharts 简介创建上海地图代码说明运行结果总结简介在数据可视化领域,创建交互式地

利用python实现对excel文件进行加密

《利用python实现对excel文件进行加密》由于文件内容的私密性,需要对Excel文件进行加密,保护文件以免给第三方看到,本文将以Python语言为例,和大家讲讲如何对Excel文件进行加密,感兴... 目录前言方法一:使用pywin32库(仅限Windows)方法二:使用msoffcrypto-too