Python之生成器和迭代器

本文深入探讨了Python中的生成器和迭代器,包括生成器的创建方式(列表推导式和函数定义)、使用方法(next()和__next__()),以及通过yield关键字实现的功能。此外,还介绍了迭代器的概念、判断对象是否可迭代的方法以及如何将可迭代对象转化为迭代器。最后,阐述了生成器在协程中的应用,展示了如何实现多任务的交替执行。
摘要由CSDN通过智能技术生成

 

 

生成器简介:

通过列表生成式(列表推导式),我们可以直接创造一个列表。但是,受到内存限制,列表容量肯定是有限的。 而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,要是我们仅仅需要访问前面几个元素, 那后面绝大多数元素占用的空间都会被白白浪费了。所以,如果列表元素可以按照某种算法推导出来,那我 们就可以在循环的过程中不断推算出后续的元素。这样就不必创建完整的list,从而节省大量的空间。在Python 中,这种一边循环一边计算的机制,称为生成器:generator

得到生成器方式:

1.通过列表推导式的方式得到生成器,将外部中括号换为括号。

2.借助函数完成,函数中存在yield,该函数就是一个生成器。

生成器的使用:

一个列表推导式:

newlist = [x + 1 for x in range(10)]
print(type(newlist))
print(newlist)

输出:

<class 'list'>
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

仅仅将中括号换为括号。

g = (x + 1 for x in range(10))
print(type(g))  # 一个生成器对象,可迭代
print(g)

输出:

<class 'generator'>
<generator object <genexpr> at 0x0000028FC47E5AC0>

可以看到,得到了一个生成器。

生成器,可以进行迭代,当迭代到里面没有元素时会报错:StopIteration

生成器可以借助以下方式进行迭代:  

next(生成器名)             #builtins 系统内置函数

生成器名._next_()        #生成器内部方法

g = (x * 3 for x in range(10))

while True:
    try:
        e = next(g)
        s = g.__next__()
        print(e)
        print(s)
    except:
        print('生成器的元素已迭代完毕,没有更多元素了!')
        break

输出:

0
3
6
9
12
15
18
21
24
27
生成器的元素已迭代完毕,没有更多元素了!

可见,next()和_next_()可以对生成器进行迭代。且迭代完毕后,再迭代会报错。

用函数定义生成器:

#只要函数里出现了yield关键字,说明函数就不是函数 了,变成了一个生成器对象

步骤:

1.定义一个函数,里面有yield关键字,它决定了函数运行在哪里暂停

2.调用函数,接收调用的结果,结果即为生成器

3.借助next()和_next()_,得到元素

###举例说明###

def func():
    n = 0
    while True:
        n += 1
        print(n)
        yield n  # 动作:   return n  + 暂停(保留现场)
        print('JJ')


g = func()
print(g)  # g为生成器对象

print(next(g))  # 调用next()时,程序进入了func()执行代码,直到遇到yield,把n返回并退出函数
print(next(g))  # 第二次调用时,其实是从yield下方开始执行代码

1.定义函数后,用一个变量接住调用函数后的返回值,该变量就变成了一个生成器。

2.第一次迭代该生成器的时候,相当于执行了func()函数,并且当执行到yield时,函数暂停,返回n的值。

3.第二次迭代生成器的时侯,函数从yield的下一行开始执行,经while True循环,再到yield 返回n并暂停。

不用递归,得到斐波那契数列:

其中,用到了生成器:

def fib():
   i,j = 0,1
   while True:
      yield i
      i,j = j,i+j

fi = fib()   #fi是一个可以产生Fibonacci数列的生成器
for i in range(8):
    print(fi.__next__())

输出:

0
1
1
2
3
5
8
13

yield关键字和send(value):

yield是产生的意思,send是递送的意思,可简单理解为yield是生成器向外产生元素,而send是向生成器里递送值的行为。

###举例说明###

def gen():
    i = 0
    print('jsy')
    while i<5:
        temp =yield i   #先执行关键字操作,返回i,暂停代码;下次再执行时,send给yield一个返回值'你好'
        print('temp:',temp)
        i +=1
    return '没有更多的数据!'

g = gen()

print(g.send(None))   #第一次使用生成器时,不能向生成器传入非空的值(必须空值)
n = g.send('你好') 
print(n)

print(next(g))
print(next(g))
print(g.__next__())

输出:

jsy
0
temp: 你好
1
temp: None
2
temp: None
3
temp: None
4

注意:在第一次迭代时不可以使用send向生成器里传非空值(可以传空值),因为是生成器的第一               次启动。

           生成器第一次启动时,可用send(None)或next()或_next_()

生成器的应用:

Python里引入了协程的概念,进程>线程>协程。

生成器可在协程中应用,实现线程中多任务的切换。

#例如:迅雷下载文件,可将文件切块分配给多个线程下载,从而使下载速度加快 当一个线程里有多任务时,引入协程

def task1(n):
    for i in range(n):
        print('正在下载第{}个”文件“'.format(i))
        yield None

def task2(n):
    for i in range(n):
        print('正在吃第%s碗饭'%(i))
        yield None

# task1(5)
# task2(5)
#实现函数打印顺序交替执行
g1 = task1(5)
g2 = task2(5)
while True:
    try:
        g1.__next__()
        g2.__next__()
    except:
        break

输出:

正在下载第0个”文件“
正在吃第0碗饭
正在下载第1个”文件“
正在吃第1碗饭
正在下载第2个”文件“
正在吃第2碗饭
正在下载第3个”文件“
正在吃第3碗饭
正在下载第4个”文件“
正在吃第4碗饭

迭代器:

1.迭代是访问集合元素的一种方式。迭代器是一个可以记住遍历位置的对象。

2.迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。

3.迭代器只能往前不会后退。

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

5.生成器是可迭代的,同时也是迭代器的一种

6.可迭代的不一定是迭代器,迭代器一定可迭代

###如何判断一个对象是可迭代的?

isinstance()

from collections.abc import Iterable
from collections.abc import Iterator   #导入后可用来检测是否是迭代器
list1 = [1,2,5,3,6]
print(isinstance(list1,Iterable))  #判断是否是可迭代的
print(isinstance('ass',Iterable))

print(isinstance('ass',Iterator))
print(isinstance(list1,Iterator))
print(isinstance(15,Iterable))  #整型不可迭代

# print(next(list1))  #报错,列表不是迭代器

输出:

True
True
False
False
False

注意:使用isinstance()可验证出列表,集合,字典,元组是可迭代的。但是它们不能使用next(),             可知它们不是迭代器。

           还可以通过collection中的Iterator类型判断:isinstance(' ',Iterator)

###使用iter()将可迭代对象转化为迭代器

list1 = [1,2,3,4,5]
list1 = iter(list1)
print(list1)  #利用iter转换为迭代器
print(next(list1))
print(list1.__next__())

输出:

<list_iterator object at 0x000002AF077F3C40>
1
2

生成器和迭代器(放在一起看):

生成器:

1.生成器是迭代器的一种,在使用函数来创建生成器时,函数每调用便可产生一个迭代器(生成器),所以生成器可返回迭代器。

2.在使用生成器运行的过程中,每次遇到 yield 时函数会暂停并保存当前所有的运行信息,返回 yield 的值, 并在下一次执行 next() 方法时从当前位置继续运行,所以具有高效性,简洁性,节省内存;且可通过yield关键字位置的变化来完成不同功能的实现,添加了一分灵活性。

3.生成器更多借函数来实现功能。

迭代器:

1.一个迭代器对象必须是定义了__iter__()方法和next()方法的对象。

2.节约内存(循环过程中,数据不用一次读入,在处理文件对象时特别有用,因为文件也是迭代器对象)

3.不依赖索引取值、实现惰性计算(需要时再取值计算)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

谁动了我的马卡龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值