-
比较生成器和列表生成式
-
代码演示
import time
start_time = time.time()
list_1 = (x*2 for x in range(10) )
stop_time = time.time()
print(list_1)
print(“the list_1 run time is %s” % (stop_time-start_time))
start_time = time.time()
list_2 = [x*2 for x in range(10) ]
stop_time = time.time()
print(list_2)
print(“the list_2 run time is %s” % (stop_time-start_time))
“”"
运行结果:
<generator object at 0x0000011FACD1ED60> 生成器只有一个列表地址,并没有具体的数值
the list_1 run time is 0.0
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18]
the list_2 run time is 0.0
“”"
生成器和生成式的对比
-
- 生成器只有在调用的时候才会生成相应的数据
-
生成式可以直接打印列表,生成器只能打印地址
-
生成式可以通过下角标获取元素,生成器不行
-
生成器可以通过 __ next()__ 函数获得生成器(generator)的下一个返回值
list_1 = (x*2 for x in range(100000000))
for x in list_1:
print(x)
list_1.next
list_1.next
list_1.next
-
-
- 只有一个__next()__用来记录当前位置,没有方法访问前面的元素,只能往后面走
-
generator非常强大。如果推算的算法比较复杂,用类似列表生成式的for循环无法实现的时候,还可以用函数来实现。
- 比如,著名的斐波拉契数列(Fibonacci),除第一个和第二个数外,任意一个数都可由前两个数相加得到:
1, 1, 2, 3, 5, 8, 13, 21, 34, …
斐波拉契数列用列表生成式写不出来,但是,用函数把它打印出来却很容易:
def fib(sum):
a, b, c = 0, 1, 0
while c < sum:
print(b)
a, b = b, a + b
c += 1
fib(6)
斐波那契数列
-
- 仔细观察,可以看出,fib函数实际上是定义了斐波拉契数列的推算规则,可以从第一个元素开始,推算出后续任意的元素,这种逻辑其实非常类似generator。也就是说,上面的函数和generator仅一步之遥。要把fib函数变成generator,只需要把print(b)改为yield b就可以了:
def fib(sum):
a, b, c = 0, 1, 0
while c < sum:
#print(b)
yield b # 代码执行到这里,会跳出这个函数,并将b的值返回到使用next的代码处
a, b = b, a + b
c += 1
print(fib(6)) # 这里得到的就是生成器
p = fib(6)
print(next§)
print(next§)
print(“做点别的事情”)
print(next§)
print(p.next())
print(next§)
print(p.next())
第二种生成器生成方式
-
- 这就是定义generator的另一种方法。如果一个函数定义中包含yield关键字,那么这个函数就不再是一个普通函数,而是一个generator:
f = fib(6)
f
<generator object fib at 0x104feaaa0
-
- 这里,最难理解的就是generator和函数的执行流程不一样。函数是顺序执行,遇到return语句或者最后一行函数语句就返回。而变成generator的函数,在每次调用next()的时候执行,遇到yield语句返回,再次执行时从上次返回的yield语句处继续执行。
-
在上面fib的例子,我们在循环过程中不断调用yield,就会不断中断。当然要给循环设置一个条件来退出循环,不然就会产生一个无限数列出来。同样的,把函数改成generator后,我们基本上从来不会用next()来获取下一个返回值,而是直接使用for循环来迭代:
for n in fib(6):
print(n)
-
- 但是用for循环调用generator时,发现拿不到generator的return语句的返回值。如果想要拿到返回值,必须捕获StopIteration错误,返回值包含在StopIteration的value中:
def fib(sum):
a, b, c = 0, 1, 0
while c < sum:
yield b
a, b = b, a + b
c += 1
return “返回值只能传递给异常”
g = fib(3)
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!