python迭代器与生成器


title: python迭代器与生成器
data: 2018-4-7
categories:

  • python
    tags:
  • python

迭代器

迭代器(Iterator)是访问集合元素的一种方式。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。

迭代器有两个基本的方法:iter()next()

python中对常见的迭代器使用场景是循环语句for,它用迭代器封装集合,并且逐个访问集合元素以执行循环体。比如:

for num in range(5):
    print(num)

其中的range()返回一个包含所指定元素的集合,而for语句将其封装成一个迭代器后访问。
使用iter()调用可以将列表、集合转换成迭代器,比如下面的 t 就是一个迭代器:

>>> mylist = [1,3,4,8,6,9]
>>> t = iter(mylist)
>>> print(t)
<listiterator object at 0x00000000025F39B0>

迭代器和普通python对象的区别是迭代器有一个next()方法,每次调用该方法可以放回一个元素。调用者(比如for语句)可以通过不断调用next()方法来逐个访问集合元素。比如:

>>> iter = iter(range(5))
>>> print iter.next()
0
>>> print iter.next()
1
>>> print iter.next()
2
...

调用者可以一直这样调用next()方法来访问迭代器,直到next()返回StopIteration异常表示迭代已经完成。

创建一个迭代器

把一个类作为一个迭代器使用需要在类中实现两个方法 __iter__() __next__()
Python 的构造函数为 __init__(), 它会在对象初始化的时候执行。

__iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成。

__next__() 方法(Python 2 里是 next())会返回下一个迭代器对象。

创建一个返回数字的迭代器,初始值为 1,逐步递增 1:

#python3
class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    x = self.a
    self.a += 1
    return x
 
myclass = MyNumbers()
myiter = iter(myclass)
 
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))
print(next(myiter))

执行输出结果为:

1
2
3
4
5

StopIteration

StopIteration 异常用于标识迭代的完成,防止出现无限循环的情况,在 __next__() 方法中我们可以设置在完成指定循环次数后触发 StopIteration 异常来结束迭代。
在 10 次迭代后停止执行:

#python3
class MyNumbers:
  def __iter__(self):
    self.a = 1
    return self
 
  def __next__(self):
    if self.a <= 10:
      x = self.a
      self.a += 1
      return x
    else:
      raise StopIteration
 
myclass = MyNumbers()
myiter = iter(myclass)
 
for x in myiter:
  print(x)

执行输出结果为:

1
2
3
4
5
6
7
8
9
10

生成器

在 Python 中,使用了 yield 的函数被称为生成器(generator)。

跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。

在调用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行。

调用一个生成器函数,返回的是一个迭代器对象。

以下实例使用 yield 实现斐波那契数列:

#!/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
f = fibonacci(10) # f 是一个迭代器,由生成器返回生成
 
while True:
    try:
        print (next(f), end=" ")
    except StopIteration:
        sys.exit()

执行以上程序,输出结果如下:

0 1 1 2 3 5 8 13 21 34 55

使用 yield

#!/usr/bin/python3
import sys

def fibonacci(n,w=0): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        yield a
        a, b = b, a + b
        print('%d,%d' % (a,b))
        counter += 1
f = fibonacci(10,0) # f 是一个迭代器,由生成器返回生成

while True:
    try:
        print (next(f), end=" ")
    except :
        sys.exit()

输出结果:

0 1,1
1 1,2
1 2,3
2 3,5
3 5,8
5 8,13
8 13,21
13 21,34
21 34,55
34 55,89
55 89,144

不使用 yield

#!/usr/bin/python3

import sys

def fibonacci(n,w=0): # 生成器函数 - 斐波那契
    a, b, counter = 0, 1, 0
    while True:
        if (counter > n): 
            return
        #yield a
        a, b = b, a + b
        print('%d,%d' % (a,b))
        counter += 1
f = fibonacci(10,0) # f 是一个迭代器,由生成器返回生成

while True:
    try:
        print (next(f), end=" ")
    except :
        sys.exit()

输出结果:

1,1
1,2
2,3
3,5
5,8
8,13
13,21
21,34
34,55
55,89
89,144

区别

第二种没有yield时,函数只是简单执行,没有返回迭代器f。这里的迭代器可以用生成l列表来理解一下:

>>> l = [i for i in range(0,15)]
>>> print(l)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]
>>> m = (i for i in range(0,15))
>>> print(m)
<generator object <genexpr> at 0x104b6f258>
>>> for g in m:
...     print(g,end=', ')
... 
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,

这里的m就像上面的f一样,是迭代器。

参考:http://www.runoob.com/python3/python3-iterator-generator.html 下面的笔记

原文地址:https://www.cnblogs.com/id88/p/14210843.html