【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 MySQL如何通过Binlog获取变更记录恢复数据

《PythonMySQL如何通过Binlog获取变更记录恢复数据》本文介绍了如何使用Python和pymysqlreplication库通过MySQL的二进制日志(Binlog)获取数据库的变更记录... 目录python mysql通过Binlog获取变更记录恢复数据1.安装pymysqlreplicat

利用Python编写一个简单的聊天机器人

《利用Python编写一个简单的聊天机器人》这篇文章主要为大家详细介绍了如何利用Python编写一个简单的聊天机器人,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 使用 python 编写一个简单的聊天机器人可以从最基础的逻辑开始,然后逐步加入更复杂的功能。这里我们将先实现一个简单的

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

C#使用yield关键字实现提升迭代性能与效率

《C#使用yield关键字实现提升迭代性能与效率》yield关键字在C#中简化了数据迭代的方式,实现了按需生成数据,自动维护迭代状态,本文主要来聊聊如何使用yield关键字实现提升迭代性能与效率,感兴... 目录前言传统迭代和yield迭代方式对比yield延迟加载按需获取数据yield break显式示迭

Python实现高效地读写大型文件

《Python实现高效地读写大型文件》Python如何读写的是大型文件,有没有什么方法来提高效率呢,这篇文章就来和大家聊聊如何在Python中高效地读写大型文件,需要的可以了解下... 目录一、逐行读取大型文件二、分块读取大型文件三、使用 mmap 模块进行内存映射文件操作(适用于大文件)四、使用 pand

python实现pdf转word和excel的示例代码

《python实现pdf转word和excel的示例代码》本文主要介绍了python实现pdf转word和excel的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价... 目录一、引言二、python编程1,PDF转Word2,PDF转Excel三、前端页面效果展示总结一

Python xmltodict实现简化XML数据处理

《Pythonxmltodict实现简化XML数据处理》Python社区为提供了xmltodict库,它专为简化XML与Python数据结构的转换而设计,本文主要来为大家介绍一下如何使用xmltod... 目录一、引言二、XMLtodict介绍设计理念适用场景三、功能参数与属性1、parse函数2、unpa

Python中使用defaultdict和Counter的方法

《Python中使用defaultdict和Counter的方法》本文深入探讨了Python中的两个强大工具——defaultdict和Counter,并详细介绍了它们的工作原理、应用场景以及在实际编... 目录引言defaultdict的深入应用什么是defaultdictdefaultdict的工作原理

Python中@classmethod和@staticmethod的区别

《Python中@classmethod和@staticmethod的区别》本文主要介绍了Python中@classmethod和@staticmethod的区别,文中通过示例代码介绍的非常详细,对大... 目录1.@classmethod2.@staticmethod3.例子1.@classmethod

Python手搓邮件发送客户端

《Python手搓邮件发送客户端》这篇文章主要为大家详细介绍了如何使用Python手搓邮件发送客户端,支持发送邮件,附件,定时发送以及个性化邮件正文,感兴趣的可以了解下... 目录1. 简介2.主要功能2.1.邮件发送功能2.2.个性签名功能2.3.定时发送功能2. 4.附件管理2.5.配置加载功能2.6.