Python——生成器&推导式

生成器

生成器的本质就是迭代器,那么还为什么有生成器呢,两者唯一的不同就是迭代器都是Python给你提供能够的已经写好的工具或者通过数据转化得来的。而生成器是需要我们自己用Python代码构建的工具。

特点:

1.取一次就没有了

2.不取不执行(惰性运算),next,for,list,不进行取值操作时,不会执行。

3. 列表生成式和生成器表达式是不一样的,一个是返回值,一个是返回生成器。

生成器的构建方式:

在python中有两种方式来创建生成器:

  • 通过生成器函数

  • 通过生成器推导式

生成器函数:

首先我们来一个简单的函数结构:

1
2
3
4
5
def func():
    print('111')
    return 222
result = func()
print(result)

没得问题,那么在看看生成器函数是啥样的。

1
2
3
4
5
6
def func():
    print('111')
    yield 222
result = func()
print(result)
# <generator object func at 0x000002980E331C10>

以这样打印,就给打印了个这东西。这意思是,当函数看到返回值是yield的时候,就说明这个函数时一个生成器函数。返回的是一个生成器。那么要调用怎么办呢。

1
2
3
4
5
6
def func():
    print('111')
    yield 222
result = func()  #这会还不会调用,而是获取到一个生成器
ret = result.__next__() #这个时候函数才会被执行。
print(ret)   #而且yield会将func返回的222给ret

就是将return该成yield,再用next来提取就成了。

还有yield可以写多个,一个next对应一个yield,next多了就会报错。

1
2
3
4
5
6
7
8
9
10
11
def func():
    print('111')
    yield 222
    print('222')
    yield 333
    print('333')
    yield 444
result = func()
print(next(result))
print(next(result))
print(next(result))

发现它的用处了吗~?? 那就是可以暂停函数执行,并返回出来。这样带来的好处是可以暂时执行其他的,然后再返回执行下面的代码。

当一个数字循环不用保存而只是使用一次的话,那么使用yield是非常省内存的方法。

1
2
3
4
5
6
def func():
    for i in range(10000):
        yield '包子'+ str(i)
v = func()
for i in range(200):
    print(v.__next__())

send方法:

1
2
3
4
5
6
7
8
9
def func():
    for i in range(10000):            #3-10-17
        count = yield str(i)+'来了'    #4-8-11-15-18
        print(f'{count}再吃包子{i}')    #9-16
v = func()                             #1
print(v.__next__())                    #2-5
for i in range(2):                     #6-13
    v2 = v.send(i)                     #7-14-19
    print(v2)                          #12-20

这里比较绕哦,需要好好看。

send和next的相同点,不同点:

相同点:

  • 都可以让商城器对应的yield向下执行一次

  • 都可以获取到yield生成的值

不同点:

  • 第一次获取yield值智能用next,不能用send(可以用send(None))

  • send可以给上一个yield传递值

yield from:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
def func():
    lis =[1,2,3,4,5]
    yield lis
v = func()
print(next(v))
'''
[1,2,3,4,5]
'''
def func():
    lis =[1,2,3,4,5]
    yield from lis
v = func()
print(next(v))
print(next(v))
print(next(v))
print(next(v))
'''
1
2
3
4
5
'''

yield from的主要作用是将列表中的每一个元素返回一次。next多了还是会报错。没啥鸟用。了解即可。

生成器表达式:

1
2
3
4
5
gen = (i**2 for i in range(10))
for i2 in gen:
    print(i2)
 
gen = (i for i in range(10) if i > 2) for i2 in gen: print(i2)

生成器测试题:

1
2
3
4
5
6
7
8
def demo():
    for i in range(4):
        yield i
g = demo()
g1 = (i for i in g)
g2 = (i for i in g1)
print(list(g1))
print(list(g2))
1
2
3
4
5
6
7
8
9
def add(n,i):
    return n+i
def test():
    for i in range(4):
        yield i
g = test()
for n in [1,10]:
    g = (add(n,i) for i in g)
print(list(g))

  

推导式

主要目的是为了方便将比较单一且有规律的做法使用简单的语句进行处理。

缺点是比较占用内存资源。

基本语句:

1
2
lis = [ i for i in range(10)]
print(lis)

这样就生成了一个0-9的列表。

推导式的分类:

  1. 循环推导式

     #[变量(值) for 变量 in iterable]

  2. 筛选推导式

     #[变量 for 变量 in iterable if 条件]

列表推导式:

1
2
3
4
5
6
7
lis = [ i for i in range(10)]     #基本格式
lis = [ i if i > 3 else 8 for i in range(10)]   #循环range,得出的结果依次判断,如果成立将添加,如果不成立就改成8
lis = [i for i in range(10) if i > 3]   #循环range,得出的结果依次判断,如果为True,那么就添加,如果为False,就不添加
lis = [lambda x:x*i for i in range(10)]  #得到的是循环10次的lambda表达式,如果lis[0](2),那么意思是巡行第1个lambda函数,将2传入到你,将得到18结果。
def num():
    return [lambda x:i * x for i in range(4)]
print([m(2) for m in num()])

字典推导式:

1
2
3
4
5
6
7
8
9
lis1 = ['a','b','c']
lis2 = ['1','2','3']
dic = {lis1[i]:lis2[i] for i in range(len(lis1))}
print(dic)
lis1 = 'abc'
lis2 = '123'
dic = {lis1[i]:lis2[i] for i in range(len(lis1))}
print(dic)

集合推导式:

1
2
3
lis = [1,2,3,4,5,2,2,1,1,3,2,1]
s = {i for i in lis}
print(s)

生成器函数和列表生成器不同之处:

1
2
3
4
5
6
7
8
9
10
11
12
13
def func1():
    return (lambda x:i*x for i in range(4))
 
def func2():
    return [lambda x:i*x for i in range(4)]
print([m(2) for m in func1()] )
print([m(2) for m in func2()] )
 
 
'''
[0, 2, 4, 6]
[6, 6, 6, 6]
'''

  

posted @   新兵蛋Z  阅读(424)  评论(0编辑  收藏  举报
编辑推荐:
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
阅读排行:
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
点击右上角即可分享
微信分享提示