通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。在Python中,这种一边循环一边计算的机制,称为生成器(Generator)。
简单生成器
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]改成(),就创建了一个generator:
>>> L = [x * x for x in range(10)]
>>> L
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
>>> g = (x * x for x in range(10))
>>> g
<generator object <genexpr> at 0x104feab40>
创建L和g的区别仅在于最外层的[]和(),L是一个list,而g是一个generator。
我们可以直接打印出list的每一个元素,但我们怎么打印出generator的每一个元素呢?
如果要一个一个打印出来,可以通过generator的next()方法:
>>> g.next()
0
>>> g.next()
1
>>> g.next()
4
>>> g.next()
9
>>> g.next()
16
>>> g.next()
25
>>> g.next()
36
>>> g.next()
49
>>> g.next()
64
>>> g.next()
81
>>> g.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
我们讲过,generator保存的是算法,每次调用next(),就计算出下一个元素的值,直到计算到最后一个元素,没有更多的元素时,抛出StopIteration的错误。
当然,上面这种不断调用next()方法实在是太变态了,正确的方法是使用for循环,因为generator也是可迭代对象:
>>> g = (x * x for x in range(10))
>>> for n in g:
... print n
...
0
1
4
9
16
25
36
49
64
81
所以,我们创建了一个generator后,基本上永远不会调用next()方法,而是通过for循环来迭代它。
带yield 语句的生成器
仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。
也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print b改为yield b就可以了:
def fib(max):
n, a, b = 0, 0, 1
while n < max:
yield b
a, b = b, a + b
n = n + 1
这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
>>> fib(6)
<generator object fib at 0x104feaaa0>
这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
举个简单的例子,定义一个generator,依次返回数字1,3,5:
>>> def odd():
... print 'step 1'
... yield 1
... print 'step 2'
... yield 3
... print 'step 3'
... yield 5
...
>>> o = odd()
>>> o.next()
step 1
1
>>> o.next()
step 2
3
>>> o.next()
step 3
5
>>> o.next()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
可以看到,odd不是普通函数,而是generator,在执行过程中,遇到yield就中断,下次又继续执行。执行3次yield后,已经没有yield可以执行了,所以,第4次调用next()就报错。
回到fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。
同样的,把函数改成generator后,我们基本上从来不会用next()来调用它,而是直接使用for循环来迭代:
>>> for n in fib(6):
... print n
...
1
1
2
3
5
8
加强的生成器
在 python2.5 中,一些加强特性加入到生成器中,所以除了 next()来获得下个生成的值,用户可以将值回送给生成器[send()],在生成器中抛出异常,以及要求生成器退出[close()]
def gen(x):
count = x
while True:
val = (yield count)
if val is not None:
count = val
else:
count += 1
f = gen(5)
print f.next()
print f.next()
print f.next()
print '===================='
print f.send(9)
print f.next()
print f.next()
输出
5
6
9
10
11
[参考如下(http://www.liaoxuefeng.com/wiki/001374738125095c955c1e6d8bb493182103fac9270762a000/00138681965108490cb4c13182e472f8d87830f13be6e88000)
<script type="text/javascript">
$(function () {
$('pre.prettyprint code').each(function () {
var lines = $(this).text().split('\n').length;
var $numbering = $('<ul/>').addClass('pre-numbering').hide();
$(this).addClass('has-numbering').parent().append($numbering);
for (i = 1; i <= lines; i++) {
$numbering.append($('<li/>').text(i));
};
$numbering.fadeIn(1700);
});
});
</script>
版权声明:本文为博主原创文章,未经博主允许不得转载。
分享到:
相关推荐
Python生成器是Python编程语言中的一个强大特性,它允许开发者创建迭代器,而无需显式地定义`__iter__`和`__next__`方法。生成器在内存管理上非常高效,因为它们按需生成值,而不是一次性生成所有数据。这在处理大量...
总结来说,Python生成器是一种高效的编程工具,它使得程序能够有效地处理大量数据,而不需要占用过多的内存资源。通过生成器,我们可以构建出无限的迭代器,或者通过惰性求值逐个产生数据,从而节省内存并提高程序的...
Python 生成器和迭代器 Python 生成器和迭代器是 Python 编程语言中两个重要的概念,它们都是用于处理可迭代对象的。下面我们将对这两个概念进行详细的解释和分析。 一、什么是生成器? 在 Python 中,使用了 ...
python生成器使用笔记
Python生成器和迭代器
Python生成器表达式是Python编程语言中的一种高效内存管理机制,它允许程序员创建迭代器而无需定义一个完整的类。生成器表达式与列表推导式非常相似,但在内存使用和性能方面有着显著的区别。列表推导式一次性计算并...
Python生成器是一种特殊的迭代器,它们允许我们定义一个可以暂停执行并保留其内部状态的函数。在需要时,生成器可以恢复执行并产生序列中的下一个值。生成器简化了迭代器的实现,避免了手动管理迭代状态的复杂性。 ...
Python生成器,或称Generator,是一种特殊的迭代器,它的特点是其内部使用了`yield`语句,这使得生成器能够记住执行状态,并在下次调用时恢复。生成器的优势在于它们能够在运行时按需生成数据,而不是一次性生成所有...
在Python编程中,生成器是一种高效处理迭代数据的机制。与传统的迭代器不同,生成器使用yield关键字来产生值,而不是一次性生成所有值。这种“懒加载”的方式可以显著减少内存使用,特别是在处理大型数据集或无限...
### Python生成器的使用方法与示例代码详解 #### 一、引言 在Python编程中,生成器是一种特殊的迭代器,它允许我们创建一种能够动态生成数据的函数。相比于传统的返回列表的方法,生成器更加高效,因为它并不一次...
Python生成器是编程中一种非常高效且节省内存的工具,特别是在处理大数据集或者无限序列时。它们遵循Python的迭代器协议,允许你在需要时按需生成下一个值,而不是一次性加载整个序列到内存中。生成器有两种主要形式...
在Python编程语言中,生成器(Generator)和迭代器(Iterator)是两种非常重要的概念,它们主要用于处理大量数据或无限序列,以节省内存资源。理解它们的区别和使用方式对于高效编程至关重要。 一、生成器 1.1 ...
Python 生成器是一种特殊的迭代器,它允许在执行过程中暂停并保存状态,使得函数能够从上次停止的地方继续执行。这种特性使得生成器在处理大量数据或者无限序列时非常高效,因为它不需要一次性生成所有元素,而是按...
Python生成器推导式: 生成器推导式(generator expression)的用法与列表推导式非常相似,在形式上生成器推导式使用圆括号(parentheses)作为定界符,而不是列表推导式所使用的方括号(square brackets)。 与列表...
本篇文章将深入探讨Python生成器中的`next()`方法和`send()`方法,以及它们之间的区别。 首先,让我们理解`next()`方法。`next()`方法用于迭代生成器,当调用`next(g)`时,它会执行生成器函数直到遇到第一个`yield`...
生成器本质上也是一个迭代器,我的一点理解的话,它也有点像只能执行一轮的单链表,通过 obj.__next__()就获得了当前指针(并不是真的指针)的指向值,同时将将指针指向一下个,过程不可逆,最后一个元素执行完之后...
生成器是 Python 初级开发者最难理解的概念之一,虽被认为是 Python 编程中的高级技能,但在各种项目中可以随处见到生成器的身影,你得不得去理解它、使用它、甚至爱上它。 提到生成器,总不可避免地要把迭代器拉...