<Python进阶读书笔记>之(二) 生成器

来源:互联网 发布:美国指数型基金数据 编辑:程序博客网 时间:2024/05/18 10:21

一. 可迭代对象(Iterable) 和迭代器(Iterator)

Python中任意的对象, 只要它定义了可以返回一个迭代器的iter方法, 或者定义了可以支持下标索引的getitem方法, 那么它就是一个可迭代对象. 简单说, 可迭代对象就是能提供迭代器的任意对象. 那迭代器又是什么呢?

任意对象, 只要定义了next(Python2) 或者next方法, 它就是一个迭代器. 就这么简单.

现在我们来理解迭代(iteration). 当我们使用一个循环来遍历某个东西时, 这个过程本身就叫迭代.

二. 生成器(Generators)

1. 生成器基本概念

生成器也是一种迭代器, 但是你只能对其迭代一次. 这是因为它们并没有把所有的值存在内存中, 而是在运行时生成值. 你通过遍历来使用它们, 要么用一个“for”循环, 要么将它们传递给任意可以进行迭代的函数和结构. 大多数时候生成器是以函数来实现的. 然而, 它们并不返回一个值, 而是yield一个值. 这里有个生成器函数的简单例子:

def generator_function():    for i in range(10):        yield ifor item in generator_function():    print(item)

输出:

0123456789

这个案例并不是非常实用. 生成器最佳应用场景是:你不想同一时间将所有计算出来的大量结果集分配到内存当中, 特别是结果集里还包含循环. 这样做会消耗大量资源. 许多Python 2里的标准库函数都会返回列表, 而Python 3都修改成了返回生成器, 因为生成器占用更少的资源.

下面是一个计算斐波那契数列的生成器:

# generator versiondef fibon(n):    a = b = 1    for i in range(n):        yield a        a, b = b, a + bfor x in fibon(100):    print(x)

用这种方式, 我们可以不用担心它会使用大量资源. 然而, 之前如果我们这样来实现的话:

def fibon(n):    a = b = 1    result = []    for i in range(n):        result.append(a)        a, b = b, a + b    return result

2. 理解生成器的”生成”

在测试前你需要再知道一个Python内置函数:next(). 它允许我们获取一个序列的下一个元素. 那我们来验证下我们的理解:

def generator_function():    for i in range(3):        yield igen = generator_function()print(next(gen))  # Output: 0print(next(gen))  # Output: 1print(next(gen))  # Output: 2print(next(gen))  # Error# Output: Traceback (most recent call last):#            File "<stdin>", line 1, in <module>#         StopIteration

我们可以看到, 在yield掉所有的值后, next()触发了一个StopIteration的异常. 基本上这个异常告诉我们, 所有的值都已经被yield完了. 你也许会奇怪, 为什么我们在使用for循环时没有这个异常呢?答案很简单. for循环会自动捕捉到这个异常并停止调用next().

3. 内置数据类型中的可迭代对象

my_string = "Yasoob"print(next(my_string))# Output: Traceback (most recent call last):#      File "<stdin>", line 1, in <module>#    TypeError: str object is not an iterator

这个异常说那个str对象不是一个迭代器. 对, 就是这样!它是一个可迭代对象, 而不是一个迭代器. 这意味着它支持迭代, 但我们不能直接对其进行迭代操作. 那我们怎样才能对它实施迭代呢?是时候学习下另一个内置函数, iter. 它将根据一个可迭代对象返回一个迭代器对象. 这里是我们如何使用它:

my_iter = iter("Yasoob")print(next(my_iter))# Output: 'Y'

参考文献

  1. Python进阶
0 0
原创粉丝点击