天天看点

迭代器、生成器和yield的知识总结(非原创、归纳总结各类资料)一、什么是迭代器二、创建迭代器三、迭代器的使用

环境说明: 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函数。