环境说明: python3.7
通过查阅各类资料,总结一下迭代器相关知识,作为资料留存,方便以后查阅温习。
一、什么是迭代器
迭代器是实现了__next__()方法的对象(这个方法在调用时不需要任何参数),它是访问可迭代序列的一种方式,通常其从序列的第一个元素开始访问,直到所有的元素都被访问才结束。 [注意]:迭代器只能前进不能后退
[迭代器的优点]:
使用迭代器不要求事先准备好整个迭代过程中的所有元素。迭代器仅仅在迭代到某个元素时才计算该元素,而在这之前或之后元素可以不存在或者被销毁。因此迭代器适合遍历一些数量巨大甚至无限的序列。
以python2.x中的range函数和xrange函数为例,range函数返回的是列表,xrange函数返回的是迭代器,所以range函数占用的内存空间比xrange大,因此,在python3.x中,改进range函数返回迭代器,取消xrange函数。
二、创建迭代器
(一)使用iter(iterable)可将可迭代序列转换为迭代器
a=[1,2,3,4]
b=(1,2,3)
str='Tomwenxing'
print(iter(a))
print(iter(b))
print(iter(str))
输出如下:
<list_iterator object …>
<tuple_iterator object …>
<str_iterator object …>
说明: 并不是所有的数据类型/结构都能转换为迭代器,列表、元组、字符串等本身就是iterable,因此可以通过iter函数生成迭代器。
(二)自定义支持iterable的类
与上面“说明”一致,如果我们定义了一个支持iterable的类,那么我们也可以使用iter函数生成对应的迭代器。
Python中迭代器的本质,每次调用__next__()方法都返回下一个元素或抛出StopIteration的容器对象
由于Python中没有“迭代器”这个类,因此具有以下两个特性的类都可以称为“迭代器”类:
1、有__next__()方法,返回容器的下一个元素或抛出StopIteration异常
2、有__iter__()方法,返回迭代器本身
如下例所示,通过在Fib类中定义上述两个函数,就可以认为Fib是支持iterable。
class Fib(object):
def __init__(self,length):
self.length=length
self.curLength,self.preNum,self.curNum=0,0,1
def __iter__(self):
return self
def __next__(self):
if self.curLength<self.length:
r=self.curNum
self.preNum,self.curNum=self.curNum,self.preNum+self.curNum
self.curLength=self.curLength+1
return r
raise StopIteration()
if __name__=="__main__":
length=5
for n in Fib(length):
print(n)
输出如下:
1
1
2
3
5
(三)生成器可看成是一个迭代器
在 Python 中,使用了 yield 的函数被称为生成器(generator)。
yield 的作用就是把一个函数变成一个 generator,带有 yield 的函数不再是一个普通函数,Python 解释器会将其视为一个 generator,调用该函数不会执行,而是返回一个生成器对象(generator 对象)。生成器对象可看成是一个迭代器对象,使用方法一样。
在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
if __name__ == '__main__':
f = fibonacci(10) # f 是一个生成器,可看成是一个迭代器。
print(type(f))
输出如下:
<class ‘generator’>
三、迭代器的使用
(一)使用next函数迭代
例1:
a=[1,2,3,4]
it=iter(a)
print(next(it))
print(next(it))
例2:
class Fib(object):
def __init__(self,length):
self.length=length
self.curLength,self.preNum,self.curNum=0,0,1
def __iter__(self):
return self
def __next__(self):
if self.curLength<self.length:
r=self.curNum
self.preNum,self.curNum=self.curNum,self.preNum+self.curNum
self.curLength=self.curLength+1
return r
raise StopIteration()
if __name__=="__main__":
fib=Fib(5)
print(next(fib))
it=iter(fib)
print(next(it))
特别说明: 通过上述案例,总结:Fib类的对象可直接被next函数调用迭代,Fib类的对象转换成迭代器后也可被next函数调用迭代。疑问:与可迭代序列类比,Fib类对象不是应该转换成迭代器后才可被next函数调用吗,为什么可直接被next函数调用?什么原理,怎么个过程啊,请大神指教!
例3:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
if __name__ == '__main__':
f = fibonacci(10) # f 是一个生成器,可看成是一个迭代器。
print(type(f))
print(next(f))
(二)使用for循环迭代
如下例:
#!/usr/bin/python3
import sys
def fibonacci(n): # 生成器函数 - 斐波那契
a, b, counter = 0, 1, 0
while True:
if (counter > n):
return
yield a
a, b = b, a + b
counter += 1
if __name__ == '__main__':
f = fibonacci(10) # f 是一个生成器,可看成是一个迭代器。
print(type(f))
for num in f:
print(num)
特别说明: 在执行for循环时,每执行一次,暗含会调用一次next函数。