Python迭代器是为了解决遍历数据集合的问题而来的。在Python中,可以使用for循环遍历列表、元组、字典等数据集合,但是对于大型数据集合或者需要进行复杂的数据处理时,这种方法可能会导致内存占用过大或者处理速度过慢的问题。
迭代器提供了一种延迟计算数据的方法,只有当需要使用数据时,才会进行计算并返回结果。这种方式可以有效减少内存占用,并且可以提高代码的执行效率。
什么是迭代器?
迭代器是一个可以记住遍历位置的对象,它从集合的第一个元素开始访问,直到所有元素被访问完毕。迭代器只能向前不会后退。由__iter__、__next__实现
二、迭代器示例
python设计迭代器的原因:是为了寻求一种不依赖索引也能够进行迭代取值的方案,所以python给那些没有索引的数据类型都内置了一个功能,叫__iter__功能,如果我们不想或者不能依赖索引进行迭代取值,那我们就可以调用python给我们提供的这个功能就可以了,
只要调用了__iter__方法,那么python就会
将迭代对象转化为迭代器对象
,有了这个迭代器对象,我们就可以不依赖索引进行迭代取值了,那这个迭代器对象是怎么不依赖于索引进行迭代取值呢?
d = {"key1": 1, "key2": 2, "key3": 3}
res = d.__iter__() # 将可迭代对象转化为迭代器
print(res)
print(res.__next__()) # key1
print(res.__next__()) # key2
print(res.__next__()) # key3
print(res.__next__()) # 这时取值已经取完,将抛出StopIteration异常
"""
迭代器节约内存资源,把迭代器比喻成一只老母鸡,这里只能下三只蛋,下完后就死了,不能重新调用生成,如果想再次生成,就自己再新建一只老母鸡。
就是说如果这个老母鸡一辈子可以生1000个鸡蛋,肯定不是它肚子里直接就存着1000个鸡蛋,而是一个一个来的,我想说的是节约内存资源,效率高
while第一次循环就已经取完了老母鸡里的鸡蛋,然后老母鸡就死了,所以第二次循环是取不到值的,直接捕获异常break了。那么我们就需要重新再造一只老母鸡
while True:
try:
print(res.__next__())
except StopIteration:
break
while True:
try:
print(res.__next__())
except StopIteration:
break
其他的类型只要有__iter__方法的数据类型---列表、元组、字符串、集合、还有文件,不管有索引还是没有索引,都可以用这种方法进行迭代取值。
# 针对上面使用的while循环,直接使用for循环要简单很多(上面与for循环原理一样)
d = {"key1": 1, "key2": 2, "key3": 3}
for key in d:
print(key)
迭代器调用iter()方法:
print(res.__iter__()) # res是迭代器,打印迭代器本身
即然调用iter()打印的是迭代器本身,那么这种方式没有意义,为什么要设计出来呢?真的就是没有意义吗?不,这种方式的出现是
为了让for循环的工作原理统一起来,不管for循环的in后面跟的是可迭代对象,还是迭代器对象,都可以采用同一套运行机制,如果我们for i in 一个可迭代对象,它会去调用这个可迭代对象的__iter__方法,把它转换成一个迭代器,如果这里本身放的就是一个迭代器对象,那我for循环的工作原理不变,还是会
去调用它的__iter__(迭代器对象的__iter__),拿到的结果也是一个迭代器
列表、元组、集合、字典都没有__next__方法,所以他们是可迭代对象,文件对象有__iter__、__next__,是迭代器对象
三、for循环原理
1.调用__iter__()方法将可迭代对象转化为迭代器对象
2.while循环不断调用迭代器对象的__next__()方法,直到所有元素都被遍历。
3.在每次调用__next__()方法时,迭代器会返回下一个元素。如果没有更多元素,next()方法会抛出StopIteration异常。
4.for循环捕获StopIteration异常,结束循环。
字典的values()、keys()、items()都是可迭代对象:
print({"key1":123}.items().__iter__().__next__()) # ('key1', 123),先转换成了迭代器,然后取值。实际上这是执行了for循环原理。
# 所以得出for循环可直接遍历:
for k,v in {"key1": 123}.items(): #print({"key1": 123}.items())------>dict_items([('key1', 123)])
print(k) # key1
print(v) # 123
list、tuple工作原理:
for循环的原理就是这三个步骤,所以说list和tuple的工作原理也是这三步(如,list("hello")),先生成空列表;然后调用符串下面的__iter__方法,转成一个迭代器,然后调用迭代器下面的__next__方法拿到返回值,把返回值放在空列表里面。
四、迭代器与生成器区别
迭代器是一种工具,它可以遍历访问可迭代对象中的所有元素,但是它并不是可迭代对象。
生成器是一种特殊的迭代器,它可以通过函数来实现。生成器函数使用yield语句来返回一个值,每次调用生成器函数时,都会从上一次yield语句处继续执行。因此,生成器可以延迟计算,只有在需要时才会生成下一个元素,从而节省内存。
生成器与迭代器示例:
# 迭代器示例
class Counter:
def __init__(self, n):
self.n = n
self.current = 0
def __iter__(self):
return self
def __next__(self):
if self.current < self.n:
num = self.current
self.current += 1
return num
else:
raise StopIteration
# 生成器示例
def counter(n):
current = 0
while current < n:
yield current
current += 1
# 生成器表达式生成生成器
gen = (x for x in range(1, 4))
print(type(gen)) # <class 'generator'>
print(next(gen)) # Output: 1
print(next(gen)) # Output: 2
print(next(gen)) # Output: 3
计算序列中元素之和:
# 使用迭代器计算序列中所有元素的和
def iter_sum(nums):
total = 0
it = iter(nums)
while True:
try:
total += next(it)
except StopIteration:
break
return total
# 使用生成器计算序列中所有元素的和
def gen_sum(nums):
total = 0
for num in nums:
total += num
return total