目录
一、可迭代对象Iterable
1.1 可迭代对象的条件
1.2 for 循环工作原理
1.3 isinstance()
二、迭代器 Iterator
2.1 __iter__() 和 __next__()
2.2 可迭代对象&迭代器
2.2.1 定义与特性
2.2.2 关系与转换
2.2.3 应用场景
三、迭代器协议(了解即可)
四、自定义迭代器类
在这一节,我将向大家介绍Python中的迭代器和生成器,在介绍之前我们先回顾一下什么是可迭代对象?
一、可迭代对象Iterable
含义: 可以通过for ..in….这类语句遍历读取数据的对象称之为可迭代对象
遍历(迭代):依次从对象中把一个个元素取出来的过程
可迭代对象的数据类型:str、list、tuple、dict、set 等
1.1 可迭代对象的条件
(满足了这两个条件也可以称为可迭代对象):
1、对象实现了__iter__()方法
2、__iter__() 方法返回了迭代器对象
1.2 for 循环工作原理
1、先通过__iter__() 获取可迭代对象的迭代器
2、对获取到的迭代器不断调用__next__() 方法来获取下一个值并将其赋值给临时变量 i
1.3 isinstance()
判断一个对象是否是可迭代对象或者是一个己知的数据类型
导入模块:
from collections.abc import Iterable # 导入模块
isinstance(o,t) o:对象,t:类型,可以是直接或者间接类名、基本类型或者元组
eg:
from collections.abc import Iterable # 导入模块
# 示例对象
my_list = [1, 2, 3]
my_str = "hello"
my_int = 42
# 判断是否是可迭代对象
print(isinstance(my_list, Iterable)) # 输出: True
print(isinstance(my_str, Iterable)) # 输出: True
print(isinstance(my_int, Iterable)) # 输出: False
在这个例子中,my_list 是一个列表,my_str 是一个字符串,它们都是可迭代对象,因此 isinstance() 返回 True。而 my_int 是一个整数,不是可迭代对象,所以 isinstance() 返回 False。
此外,还可以使用 isinstance() 来判断一个对象是否是某个具体的数据类型,比如列表、元组、字典等:
# 判断是否是列表
print(isinstance(my_list, list)) # 输出: True
# 判断是否是元组
my_tuple = (1, 2, 3)
print(isinstance(my_tuple, tuple)) # 输出: True
# 判断是否是字典
my_dict = {'a': 1, 'b': 2}
print(isinstance(my_dict, dict)) # 输出: True
二、迭代器 Iterator
含义:迭代器是一个可以记住遍历位置的对象,迭代器对象从集合的第一个元素开始访
问,直到所有的元素被访问完结束。迭代器只能往前不会后退。
2.1 __iter__() 和 __next__()
迭代器有两个基本的方法:__iter__() 和 __next__()
__iter__() 方法:返回迭代器对象本身
__next__() 方法:返回容器的下一个元素,并将其移动到下一个位置,如果容器中没有更多的元素,则返回一个StopIteration异常
步骤:
1、iter() 调用对象的__iter__(),并把__iter__() 方法的返回结果作为自己的返回值
2、next() 调用对象的__next__(),一个个取出元素
3、所以元素都取完了,__next__()将引发StopIteration异常
接下来通过一个例子来更好的了解这两个方法:
# 第一种方法:
li = [1,2,3,4]
# 1.创建迭代器对象
li2 = iter(li)
print(li2)
# 2.获取下一条数据
print(next(li2)) # 1
print(next(li2)) # 2
print(next(li2)) # 3
print(next(li2)) # 4
# 3.取完元素后,再使用next()会引发StopIteration异常
print(next(li2)) # StopIteration异常
# 第二种方法:
li = [1,2,3,4]
# 1.创建迭代器对象
li2 = li.__iter__()
print("li2:",li2)
# 2.获取下一条数据
print(li2.__next__()) # 1
print(li2.__next__()) # 2
print(li2.__next__()) # 3
print(li2.__next__()) # 4
# 3.取完元素后,再使用next()会引发StopIteration异常
print(li2.__next__()) # StopIteration异常
2.2 可迭代对象&迭代器
凡是可以作用于for循环的都属于可迭代对象
凡是可以作用于next()的都是迭代器
2.2.1 定义与特性
可迭代对象(Iterable)
定义:可迭代对象是指实现了iter()方法的对象,该方法返回一个迭代器对象,允许对象被遍历
特性:
1、可以使用for循环进行遍历
2、常见的可迭代对象包括列表(list)、元组(tuple)、集合(set)、字典(dict)、字符串(str)等
3、在迭代过程中,不会记忆之前的访问状态,每次都从头开始遍历
迭代器(Iterator)
定义:迭代器是指实现了iter()和next()方法的对象。其中,iter()方法返回迭代器对象本身(这通常是一个已经实现了迭代协议的对象,因此调用此方法通常只是简单地返回对象自身),而next()方法用于返回迭代器的下一个元素
特性:
1、可以通过next()函数获取下一个元素,直到遍历完所有元素时抛出StopIteration异常
2、迭代器只能单向遍历,不能反向遍历
3、在迭代过程中,会记忆之前的访问状态,每次调用next()方法时,会从上一次停止的位置开始遍历
4、迭代器实现了惰性计算,即只在需要时才生成下一个值,这使得它在处理大数据集时非常高效
2.2.2 关系与转换
关系:如果一个对象是迭代器,那么它一定是可迭代的。但反过来,如果一个对象是可迭代的,它不一定是迭代器。
转换:可以使用 iter() 函数将可迭代对象转换为迭代器。例如,iter([])会将一个空列表转换为一个迭代器对象。
我们如何判断一个对象时可迭代对象还是迭代器对象呢?
根据1.3可得需要用到 isinstance 来判别
eg:
from collections.abc import Iterable,Iterator # 第一步导入模块
name = "junjun" # 定义对象
print(isinstance(name,Iterable)) # 判断对象是否为可迭代对象,True,说明为可迭代对象
print(isinstance(name,Iterator)) # 判断对象是否为迭代器对象,False,说明不是迭代器对象
可得到一个结论:可迭代对象并不一定是迭代器对象
但是可以通过iter()将可迭代对象转换为迭代器
eg:
from collections.abc import Iterable,Iterator # 第一步导入模块
name = "junjun" # 定义对象
print(isinstance(name,Iterable)) # 判断对象是否为可迭代对象,True,说明为可迭代对象
print(isinstance(name,Iterator)) # 判断对象是否为迭代器对象,False,说明不是迭代器对象
name2 = iter(name) # 将name转换成迭代器对象
print(isinstance(name2,Iterable)) # 判断对象是否为可迭代对象,True,说明为可迭代对象
print(isinstance(name2,Iterator)) # 判断对象是否为迭代器对象,True,说明是迭代器对象
可以得到另一个结论:迭代器对象一定是可迭代对象
总结:
1、可迭代对象可以通过iter()转换成迭代器对象
2、如果一个对象拥有__iter__(),是可迭代对象,如果一个对象拥有__next__()和__iter__()方法,是迭代器对象
2.2.3 应用场景
可迭代对象:适用于需要被遍历但不需要惰性计算的场景
例如,当需要遍历一个列表中的所有元素时,可以直接使用for循环
迭代器:适用于需要惰性计算或需要自定义遍历方式的场景
例如,当需要遍历一个非常大的数据集时,使用迭代器可以避免一次性将所有数据加载到内存中。此外,迭代器还可以用于实现自定义的遍历逻辑,如逆序遍历或按特定步长遍历
三、迭代器协议(了解即可)
在Python中,迭代器协议是指一种用于定义可迭代对象(iterable)和迭代器(iterator)的协议它提供了一种标准的方法来使对象可迭代,并能够在循环中逐一访问元素
迭代器协议主要涉及两个方法:__iter__() 和 __next__()
1、__iter__() 方法:
① 对于迭代器对象来说,通常这个方法会返回迭代器对象本身,使得迭代器也可以作为可迭代对象使用。这意味着迭代器需要实现这个方法,但返回的值通常是 self
② 对于可迭代对象(如列表、元组等),__iter__() 方法的作用是返回一个迭代器对象,该对象用于遍历可迭代对象中的元素
2、__next__() 方法:
① 这个方法应该返回序列中的下一个元素
② 当没有更多的元素可以返回时,应该引发一个 StopIteration 异常,以通知迭代过程已经结束。
一个对象如果实现了这两个方法(或对于迭代器来说,主要是实现了 __next__() 方法,并且可能也实现了返回自身的 __iter__() 方法),那么它就被认为是一个迭代器
迭代器的好处包括:
1、节省内存:迭代器只保存当前迭代的元素和迭代状态,而不是保存整个容器的数据
2、支持惰性求值:迭代器只有在需要时才会计算下一个元素,可以在处理大量数据时减少计算量
3、支持无限序列:迭代器可以处理无限序列,因为它只需要在需要时生成下一个元素
4、简化代码:使用迭代器可以减少代码的复杂度,提高代码的可读性和可维护性
在Python中,很多内置类型和自定义对象都是可迭代的,并且可以通过调用 iter() 函数获取对应的迭代器。此外,生成器也是迭代器的一种特殊实现,它通过函数来实现迭代逻辑,并使用 yield 语句来产生值。
四、自定义迭代器类
在Python中,自定义迭代器类通常是通过实现迭代器协议来完成的
迭代器协议要求一个对象必须实现两个特殊方法:__iter__() 和 __next__()
然而,对于纯粹的迭代器对象来说,__iter__() 方法通常只是简单地返回对象自身,而真正的迭代逻辑则是由 __next__() 方法来实现的
先通过一个普通的类带大家回忆一下,类的相关知识
eg1:普通的类
class Test(object): # 定义了一个名为 Test 的类
# 初始值是1,逐步递增1
def __init__(self): # Test 类有一个初始化方法 __init__,设置了一个实例变量 num,初始值为 1
self.num = 1
def funa(self): # Test 类还有一个方法 funa,打印当前的 num 值,并将 num 增加 1
print(self.num)
self.num += 1
te = Test() # 创建了一个实例 te
# 用for循环取出
for i in range(5):
te.funa()
输出内容:
1
2
3
4
5
eg2:下面是一个自定义迭代器类的例子,这个类会生成一个指定范围内的整数序列:
class MyRangeIterator:
def __init__(self, start, end):
self.start = start
self.end = end
self.current = start - 1 # 初始化时current设为start的前一个值,以便第一次调用__next__()时返回start
def __iter__(self):
return self # 返回迭代器对象本身
def __next__(self):
if self.current < self.end:
self.current += 1 # 更新当前值
return self.current # 返回当前值
else:
raise StopIteration # 如果没有更多元素,则抛出StopIteration异常
# 使用自定义迭代器
iterator = MyRangeIterator(1, 5)
for num in iterator:
print(num) # 输出: 1 2 3 4
今天的分享就到这里了,希望能对大家有所帮助~