python之生成器

先来看几个推导式:列表推导式,集合推导式,字典推导式

#列表推导式 格式:[表达式 for 变量 in 旧列表]
#将0-100中的偶数加5,组成新的列表
list=[x+5 for x in range(0,100) if x%2==0]
print(list)

#集合推导式  格式:{表达式 for 变量 in 旧列表}
#类似列表推导式,在列表推导式基础上添加了一个去除重复项的功能
list=[1,2,3,2,5,1,9]
set={x for x in list if x<5}
print(set)

#字典推导式
#将字典中的key和value值交换
dict={1:'a',2:'b',3:'c',4:'d',5:'e'}
newdict={value:key for key,value in dict.items()}

运行结果:

[5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31, 33, 35, 37, 39, 41, 43, 45, 47, 49, 51, 53, 55, 57, 59, 61, 63, 65, 67, 69, 71, 73, 75, 77, 79, 81, 83, 85, 87, 89, 91, 93, 95, 97, 99, 101, 103]
{1, 2, 3}
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}

通过各种推导式(生成式),可以用很少的代码实现创建一个新的列表/字典,但是受到内存限制,列表容量肯定是有限的。比如如果需要创建一个包含100万个元素的列表,不仅占用很大的存储空间,而且如果使用时仅仅之需要访问前面的几个元素,那后面的绝大多数元素占用的空间就都白白浪费了。

所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?

这样就不必创建完整的list,从而节省大量的空间,这种一边循环一边计算的机制,在python中叫做生成器,generator

先来看一个简单的生成器1:通过列表推导式方式

#生成器1
#将列表推导式的[]改成(),就变成了生成器

list=(x+5 for x in range(0,100) if x%2==0)
print(list)
print(type(list))

#有两种方式可以通知生成器生成元素
#方式一:通过调用__next__()方式得到元素
print(list.__next__())

#方式二:使用next()来获取生成器中的元素
print(next(list))

运行结果:

<generator object <genexpr> at 0x000001703A8C17D8>
<class 'generator'>
5
7

生成器2:借助函数+yield组合为一个生成器

#生成器2:借助函数完成
#只要函数中出现了yield关键字,函数就变成生成器了
'''
步骤:
1.定义一个函数,函数中使用yield关键字,yield起到return+暂停的作用
2.调用函数,接收调用函数返回的结果
3.得到的结果就是生成器
4.借助next()得到元素
'''
def func():
    n=0
    while True:
        n+=1
        # print(n)
        yield n#不加yield就是一个死循环,yield类似return+暂停作用

g=func()
print(type(g))#g为一个生成器
print(next(g))
print(next(g))

运行结果:

<class 'generator'>
1
2

生成器的应用-斐波拉契数列

#斐波那契数列0,1,1,2,3,5,8……
def fib(len):
    a,b=0,1
    n=0
    while n<len:
        # print(b)
        yield b #yield=return b的值+暂停
        a,b=b,a+b
        n+=1
    return '没有更多元素了'

f=fib(5)
print(next(f))#打印1
print(next(f))#接着从暂停处的下一行开始执行
print(next(f))
print(next(f))
print(next(f))
#print(next(f))

运行结果:

1
1
2
3
5

生成器在开发程序中的应用-协程

先看一个例子:

def task1(n):
    for i in range(1,n):
        print('正在搬第{}块砖'.format(i))

def task2(n):
    for i in range(1,n):
        print('正在听第{}首歌'.format(i))

g1=task1(5)
g2=task2(5)

运行结果:

正在搬第1块砖
正在搬第2块砖
正在搬第3块砖
正在搬第4块砖
正在听第1首歌
正在听第2首歌
正在听第3首歌
正在听第4首歌

以上例子中的两个任务,实现的是先做完任务1再做任务2,如果想要实现任务1和任务2交替进行,如搬第1块砖,听第1首歌则需要用到协程

将上面的代码改为:

#生成器在开发程序中的应用-协程
#进程>线程>协程(几个任务交替进行)
#实现搬一块砖,听一首歌

def task1(n):
    for i in range(1,n):
        print('正在搬第{}块砖'.format(i))
        yield None #只用yield的暂停功能,不返回任何值

def task2(n):
    for i in range(1,n):
        print('正在听第{}首歌'.format(i))
        yield None

g1=task1(5)#task1变为生成器1
g2=task2(5)#task2变为生成器2

while True:
    try:
        next(g1)#执行完任务1,暂停
        next(g2)#执行任务2,暂停
    except:
        break

运行结果:

正在搬第1块砖
正在搬第2块砖
正在搬第3块砖
正在搬第4块砖
正在听第1首歌
正在听第2首歌
正在听第3首歌
正在听第4首歌

拓展:迭代器和生成器的区别

#可迭代的对象:生成器,列表,集合,字典,字符串
'''
迭代是访问集合元素的一种方式,迭代器是一个可以记住遍历的位置的对象
迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束
迭代器只能往前不会后退
'''
#判断一个对象是否可迭代
from collections import Iterable

#判断列表
list=[1,2,3]
f=isinstance(list,Iterable)
print(f)
#判断字符串
f=isinstance('abc',Iterable)
print(f)
#判断整型
f=isinstance(123,Iterable)
print(f)
#判断生成器
g=(x+1 for x in range(10))
f=isinstance(g,Iterable)
print(f)

运行结果:

True
True
False
True

可迭代的对象不一定是迭代器,还需要看这个对象是否支持调用next()函数

但是可以通过iter函数来将可迭代的对象变成迭代器

'''
可迭代+可以被next()函数调用并不断返回下一个值得对象称为迭代器:Iterator
可迭代的对象不一定是迭代器
'''

#列表是可迭代的,但不是迭代器(不能使用next()函数)
list=[1,2,3,4,5]
# print(next(list)) #报错,返回list不是一个迭代器

#通过iter函数将可迭代对象变成迭代器
g=iter(list)
print(next(g)) #打印1

所以迭代器和生成器的关系如下图:生成器是迭代器中的一种,迭代器包括生成器,还包括借助iter()转换后的列表,元组等。

 

  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值