五分钟就弄懂了,Python中的生成器(1)

本文详细比较了Python中的生成器和列表生成式,展示了它们在代码效率和执行流程上的差异,并以斐波拉契数列为例说明了生成器的使用。同时,讨论了如何处理生成器的返回值和其在系统化学习中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  • 比较生成器和列表生成式

  • 代码演示

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行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值