【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获取浏览器Cookies的四种方式小结

《Python获取浏览器Cookies的四种方式小结》在进行Web应用程序测试和开发时,获取浏览器Cookies是一项重要任务,本文我们介绍四种用Python获取浏览器Cookies的方式,具有一定的... 目录什么是 Cookie?1.使用Selenium库获取浏览器Cookies2.使用浏览器开发者工具

Python实现批量提取BLF文件时间戳

《Python实现批量提取BLF文件时间戳》BLF(BinaryLoggingFormat)作为Vector公司推出的CAN总线数据记录格式,被广泛用于存储车辆通信数据,本文将使用Python轻松提取... 目录一、为什么需要批量处理 BLF 文件二、核心代码解析:从文件遍历到数据导出1. 环境准备与依赖库

Python Web框架Flask、Streamlit、FastAPI示例详解

《PythonWeb框架Flask、Streamlit、FastAPI示例详解》本文对比分析了Flask、Streamlit和FastAPI三大PythonWeb框架:Flask轻量灵活适合传统应用... 目录概述Flask详解Flask简介安装和基础配置核心概念路由和视图模板系统数据库集成实际示例Stre

Python实现PDF按页分割的技术指南

《Python实现PDF按页分割的技术指南》PDF文件处理是日常工作中的常见需求,特别是当我们需要将大型PDF文档拆分为多个部分时,下面我们就来看看如何使用Python创建一个灵活的PDF分割工具吧... 目录需求分析技术方案工具选择安装依赖完整代码实现使用说明基本用法示例命令输出示例技术亮点实际应用场景扩

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

Python错误AttributeError: 'NoneType' object has no attribute问题的彻底解决方法

《Python错误AttributeError:NoneTypeobjecthasnoattribute问题的彻底解决方法》在Python项目开发和调试过程中,经常会碰到这样一个异常信息... 目录问题背景与概述错误解读:AttributeError: 'NoneType' object has no at

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

Python使用openpyxl读取Excel的操作详解

《Python使用openpyxl读取Excel的操作详解》本文介绍了使用Python的openpyxl库进行Excel文件的创建、读写、数据操作、工作簿与工作表管理,包括创建工作簿、加载工作簿、操作... 目录1 概述1.1 图示1.2 安装第三方库2 工作簿 workbook2.1 创建:Workboo

基于Python实现简易视频剪辑工具

《基于Python实现简易视频剪辑工具》这篇文章主要为大家详细介绍了如何用Python打造一个功能完备的简易视频剪辑工具,包括视频文件导入与格式转换,基础剪辑操作,音频处理等功能,感兴趣的小伙伴可以了... 目录一、技术选型与环境搭建二、核心功能模块实现1. 视频基础操作2. 音频处理3. 特效与转场三、高

Python实现中文文本处理与分析程序的示例详解

《Python实现中文文本处理与分析程序的示例详解》在当今信息爆炸的时代,文本数据的处理与分析成为了数据科学领域的重要课题,本文将使用Python开发一款基于Python的中文文本处理与分析程序,希望... 目录一、程序概述二、主要功能解析2.1 文件操作2.2 基础分析2.3 高级分析2.4 可视化2.5