python3 生成器

本文深入探讨Python中的列表生成式及生成器的使用方法,包括列表生成式的基本语法、生成器的工作原理及其优势,同时提供了丰富的代码示例帮助理解。

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

列表生成式:

[x**2 for x in range(10)]
        从这里部分取出元素
这部分执行结果
    结果放到这个列表中
>>> a= [x for x in range(10)]
>>> print(a)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> b= [x**2 for x in range(10)]
>>> print(b)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

列表生成式中放函数方法

>>> def f(n):
...     return n**2
...
>>> b= [f(x) for x in range(10)]
>>> print(b)
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]

将列表元素或者元组元素赋值给几个变量,变量要和其中的元素个数相同

>>> s =('123','xyz',3)
>>> a,b,c = s
>>> print("a=%s,b=%s,c=%s"%(a,b,c))
a=123,b=xyz,c=3
>>> s1 = [2,3,'x']
>>> d,e,f = s1
>>> print("d=%s,e=%s,f=%s"%(d,e,f))
d=2,e=3,f=x

生成器:本身是一个可迭代的对象

生成器节约内存空间,用一次拿一次。

生成器只是一个工具,等要用的时候这个工具才会生成需要的值,这样可以节约内存,用一次才生成一次。 不能进行跳过生成,只能进行逐一生成值。
>>> s = (x*2 for x in range(10))
>>> print(s)
<generator object <genexpr> at 0x00000270ACC5C2B0>
>>> s.__next__() #函数__next__()进行生成值,等同于next(s)
0
>>> s.__next__()
2
>>> s.__next__()
4
>>> next(s) #等同于 s.__next__()
6
>>> next(s)
8
>>> next(s)
10

超过了生成器生成限制条件后会报 StopIteration

>>> s = (x*2 for x in range(5)) #此处范围为0-4
>>> next(s) # 0
0
>>> next(s) # 1
2
>>> next(s) # 2
4
>>> next(s) # 3
6
>>> next(s) # 4
8
>>> next(s) #超出范围,报错
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

使用for循环遍历生成器(for循环的作用遍历可迭代对象)

什么是可迭代对象??

对象有__iter__()方法的都是可迭代对象。

for循环的时候 for会去用next()去处理 ,同时 也做了超出范围的限制的停止迭代生成,这个过程中变量打印后就没有再被引用了 内存空间被回收

>>> s = (x*2 for x in range(5)) #生成器
>>> for i in s: # s生成器是一个可迭代的对象
...     print(i)
...
0
2
4
6
8

定义生成器:

>>> def f(): #定义生成器对象
...     print('OK')
...     yield 1  #yield关键字
...     print('OK2')
...     yield 2
...
>>> g = f() #生成器赋给g变量
>>> print(g)
<generator object f at 0x000001BDAD1EC2B0> 
>>> next(g)  #next()方法
OK
1
>>> next(g)
OK2
2
>>> next(g) #超出范围后StopIteration
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration

生成器代码执行顺序:

生成器执行到yield时就会返回对应的值完成该次的运行,下次调用接着上一次的yield后的代码继续执行,以此类推。

def fib(max):
    n,a,b =0,0,1 #第3步执行
    yield a #第4步执行 返回a的值,此时完成第一个next(g)生成,打印值a
    while n <max-1: #第6步执行
        yield b #第7步执行 返回b的值,此时完成第二个 next(g)生成,打印值b
        a, b = b, a + b #第9步执行
        n += 1 #第10步执行  此处完成后while循环第一轮结束第二轮开始走到 yield b的时候完成第三个next(g)生成,打印值b, 后续的继续循环生成到第9个的时报StopIteration错(此处限制只能生成8个)。

g = fib(8)  #第1步执行
print(next(g)) #第2步执行
print(next(g)) #第5步执行
print(next(g)) #第8步执行
print(next(g))
print(next(g))
print(next(g))
print(next(g))

生成器传参的方法send()

>>> def f():
...     a = yield 1 #传值从第二次开始
...     yield a 
...     yield 3
...
>>> b = f()
>>> print(b.send(None)) #第一次生成时需要参数为None,没有参数
1
>>> print(b.send('what')) #输入参数what,yield返回参数a为what
what
>>> print(b.send(None))
3

注意yield关键字传值的时机。 通过send()方法传值给yield参数,第一次传入的参数为None

import time
def consumer(name):
    print("%s prepares to eat the Baozi"%name)
    while True:
        baozi = yield
        print("Baozi [%s] is coming,%s eats all"%(baozi,name))


def maker(name):
    a = consumer('A') # 两个吃包子的人生成器
    b = consumer('B')
    a.__next__() # 生成器第一次生成时不需要输入参数
    b.__next__()
    print ("%s prepares to make the Baozi."%name)
    for i in  range(10):
        time.sleep(1)
        nowTime = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime())
        print('\nTwo Baozi have made sucessfully! %s'%nowTime)
        a.send(i) # 包子轮数传值使用send()方法传入生成器在while true中循环生成
        b.send(i)
maker(name='Li Lei')
例子: 
def add(s, x):
    return s + x


def gen():
    for  i in range(4):
        yield i


base = gen()
for n in [1, 10]:
    base = (add(i, n) for i in base)


print(list(base))

 运行结果为:

[20,21,22,23]

核心语句就是:

for n in [1, 10]:
  base = (add(i + n) for i in base)
在执行list(base)的时候,开始检索,然后生成器开始运算了。关键是,这个循环次数是2,也就是说,有两次生成器表达式的过程。必须牢牢把握住这一点。

生成器返回去开始运算,n = 10而不是1没问题吧,这个在上面提到的文章中已经提到了,就是add(i+n)绑定的是n这个变量,而不是它当时的数值。

然后首先是第一次生成器表达式的执行过程:base = (10 + 0, 10 + 1, 10 + 2, 10 +3),这是第一次循环的结果(形象表示,其实已经计算出来了(10,11,12,3)),然后第二次,base = (10 + 10, 11 + 10, 12 + 10, 13 + 10) ,终于得到结果了[20, 21, 22, 23].





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值