Fork me on GitHub

Python 生成器和迭代器

1. 生成器

  • 通过列表生成式,可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个
    包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数
    的元素占用的空间都白白浪费了。所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的
    过程中不断推算出后续的元素呢?这样,就不必创建完整的list,从而节省大量的空间。
  • 在Python中,这种一边循环一边计算的机制,称为生成器(generator)
# 列表生成式,值一下子,全部计算出来:
L = [ x*2 for x in range(5)]
L   # 输出: [0, 2, 4, 6, 8]

# 创建生成器, 列表元素是推算出来的:
G = ( x*2 for x in range(5))
G   # 输出: <generator object <genexpr> at 0x1077d9db0>
next(G) # 每执行一次 next(),输出一个元素, 等价于 G.__next__(), Python 2.x : G.next()


# 创建生成器的第二种方式: 使用函数(yield 关键字)
# 斐波拉契数列(Fibonacci)
def fib(times):
    n = 0
    a, b = 0, 1
    while n < times:
        print(b)
        a, b = b, a+b
        n += 1
    return 'done'

fib(5)


# 生成器(ipython 中操作)
def fib():
    print("=== start ===")
    a, b = 0, 1
    for i in range(5):
        print("=== 1 ===")
        yield b
        print("=== 2 ===")
        a, b = b, a+b
        print("=== 3 ===")
    print("=== stop ===")

a = fib()
a   # 输出: <generator object fib at 0x23355>
next(a)   # 等价于 a.__next__()
# 输出:
# === start ===
# === 1 ===
#   1

# 此时,fib()函数就是生成器,可以使用循环来迭代
for num in a:
    print(num)

1.1 send 方法

# 示例:
# ipython3 中操作
def gen():
    i = 0
    while i<5:
        temp = yield i
        print(temp)
        i+=1

a = gen()

a.__next__()    # 输出: 0
a.__next__()    # 输出: None
c = a.send("haha")  # 输出: haha
print(c)        # 输出: 2

# 说明: 程序执行到yield时,gen函数暂时停止,同时返回i的值;
# temp 接收send过来的值(haha);
# a.__next__() 等价 a.send(None)
# 若是第一次直接调用 a.send("haha"), 程序会报错

2. 迭代器

  • 迭代是访问集合元素的一种方式。
  • 迭代器是一个可以记住遍历的位置的对象;
  • 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束;
  • 迭代器只能往前不会后退;

2.1 可迭代对象

  • 可以直接作用于 for 循环的数据类型有以下几种:
    • 集合数据类型:list, tuple, dict, set, str等;
    • generator, 包括生成器和带 yieldgeneration function;
    • 这些可以直接作用于for循环的对象统称为可迭代对象(Iterable)
  • 可以使用 isinstance() 判断一个对象是否是 Iterable对象;
  • 拥有内置方法 __iter__() ;
# 示例:
from collections import Iterable
isinstance([], Iterable)    # True

2.2 迭代器

  • 可以被 next() 函数调用并不断返回下一个值的对象称为迭代器(Iterator);
  • 可以使用 isinstance() 判断一个对象是否是 Iterator 对象;
# 示例:
from collections import Iterator
isinstance((x for x in range(10), Iterator)  # True
isinstance([], Iterator)  # False

2.3 iter()函数

  • 生成器都是 Iterator 对象;
  • list, dict, str虽然是 Iterable,却不是 Iterator;
  • 可以使用 iter() 函数把 list,dict, str等 Iterable 变成 Iterator;
# 示例:
from collections import Iterator
isinstance(iter([]), Iterator)  # True

参考资料:

posted @ 2018-03-11 00:35  小a的软件思考  阅读(145)  评论(0编辑  收藏  举报