生成器(Generators)也是一种迭代器,但是你只能对其迭代一次。这是因为它们并没有把所有的值存在内存中,
而是在运行时生成值。你通过遍历来使用它们,要么用一个“for”循环,要么将它们传递给任意可
以进行迭代的函数和结构。大多数时候生成器是以函数来实现的。然而,它们并不返回一个值,
'''
#使用列表模式
def fibon(n):
a = b = 1
result = []
for i in range(n):
result.append(a)
a, b = b, a + b
return result
'''
# generator version
def fibon(n):
a = b = 1
for i in range(n):
yield a
a = b
b = a + b
for x in fibon(200000):
print(x)
#pass
程序执行顺序:
1、当程序执行for x in fibon(200000):时会调用fibon(n)函数,按照代码顺序执行,
a = b = 1
for i in range(n):
yield a
执行到yield a时,函数返回
2、返回值赋值给x后,执行print(x),然后再次循环时,程序指针又跳转到yield a,继续执行它下面的代码
a = b
b = a + b
执行完这2句后,继续它的循环
for i in range(n):
yield a
执行到yield a时,函数又返回
3、这就是一个循环,之后就是重复循环执行
这个例子在输入很大的参数时,用尽所有的资源,我们接下来测试一下
验证时,注释掉print(x),不让程序做任何输出
#使用列表模式,n=20w次,消耗了 14.682s
D:\python -m cProfile fibon.py
200006 function calls in 14.682 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 14.682 14.682 <string>:1(<module>)
1 7.819 7.819 14.681 14.681 fibon.py:11(<module>)
1 6.845 6.845 6.863 6.863 fibon.py:12(fibon)
1 0.001 0.001 14.682 14.682 {execfile}
200000 0.016 0.000 0.016 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.002 0.002 0.002 0.002 {range}
#使用生成器模式,n=20w次,消耗了 8.711s
D:\python -m cProfile fibon.py
200006 function calls in 8.711 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 8.711 8.711 <string>:1(<module>)
1 0.066 0.066 8.710 8.710 fibon.py:4(<module>)
200001 8.642 0.000 8.644 0.000 fibon.py:4(fibon)
1 0.001 0.001 8.711 8.711 {execfile}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.002 0.002 0.002 0.002 {range}
从对比的结果明显看出,使用生成器,使计算占用更少的资源,提高效率。
而是在运行时生成值。你通过遍历来使用它们,要么用一个“for”循环,要么将它们传递给任意可
以进行迭代的函数和结构。大多数时候生成器是以函数来实现的。然而,它们并不返回一个值,
而是yield(暂且译作“生出”)一个值。
yield是一个关键词,类似return, 不同之处在于,yield返回的是一个生成器
下面是一个计算斐波那契数列的生成器:'''
#使用列表模式
def fibon(n):
a = b = 1
result = []
for i in range(n):
result.append(a)
a, b = b, a + b
return result
'''
# generator version
def fibon(n):
a = b = 1
for i in range(n):
yield a
a = b
b = a + b
for x in fibon(200000):
print(x)
#pass
程序执行顺序:
1、当程序执行for x in fibon(200000):时会调用fibon(n)函数,按照代码顺序执行,
a = b = 1
for i in range(n):
yield a
执行到yield a时,函数返回
2、返回值赋值给x后,执行print(x),然后再次循环时,程序指针又跳转到yield a,继续执行它下面的代码
a = b
b = a + b
执行完这2句后,继续它的循环
for i in range(n):
yield a
执行到yield a时,函数又返回
3、这就是一个循环,之后就是重复循环执行
这个例子在输入很大的参数时,用尽所有的资源,我们接下来测试一下
验证时,注释掉print(x),不让程序做任何输出
#使用列表模式,n=20w次,消耗了 14.682s
D:\python -m cProfile fibon.py
200006 function calls in 14.682 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 14.682 14.682 <string>:1(<module>)
1 7.819 7.819 14.681 14.681 fibon.py:11(<module>)
1 6.845 6.845 6.863 6.863 fibon.py:12(fibon)
1 0.001 0.001 14.682 14.682 {execfile}
200000 0.016 0.000 0.016 0.000 {method 'append' of 'list' objects}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.002 0.002 0.002 0.002 {range}
#使用生成器模式,n=20w次,消耗了 8.711s
D:\python -m cProfile fibon.py
200006 function calls in 8.711 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 8.711 8.711 <string>:1(<module>)
1 0.066 0.066 8.710 8.710 fibon.py:4(<module>)
200001 8.642 0.000 8.644 0.000 fibon.py:4(fibon)
1 0.001 0.001 8.711 8.711 {execfile}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects}
1 0.002 0.002 0.002 0.002 {range}
从对比的结果明显看出,使用生成器,使计算占用更少的资源,提高效率。
注意:这个例子会消耗大量资源(CPU、内存),当设置n=100w次时,pc机运行了一会儿后就出现了内存不足的错误。
str对象是一个可迭代对象,而不是一个迭代器。这意味着它支持迭代,但我们不能直接对其进行迭代操作。那我们怎样才能对它实施迭代呢?
是时候学习下另一个内置函数,iter。它将根据一个可迭代对象返回一个迭代器对象。这里是我们如何使用它:
m_str = "hello python"
m_iter = iter(m_str)
next(m_iter)
# Output: 'h'