Python基础(十)迭代器与生成器

前言

之前讲到set的时候,说到set没有查找其中元素的函数,我们可以通过循环迭代出set中的所有key。

介绍

迭代

首先先介绍迭代,其实就是通过for循环遍历序列,可以访问到序列中所有的元素,如:

for i in list(range(0, 3)):
    print(i, end=' ')  # 0 1 2
  • 只要是可迭代对象都是可以迭代,像set和dict我们都不知道key的位置,但是它们是可迭代对象所以自然可以迭代。通过isinstance判读是否为可迭代对象,记得导入模块
  • 能够通过for循环直接作用的这些对象都是可迭代对象 (Iterable)。
from collections.abc import Iterable
l = {1: "aa", 2: "bb",3:"cc"}
print(isinstance(l, Iterable))#True

没有key的位置,一样可以迭代可迭代对象,如字典:

l = {1: "aa", 2: "bb", 3: "cc"}
for k, v in l.items():
    print(k, v, end=";")  # 1 aa;2 bb;3 cc;
迭代器
  • 首先,可以被next函数调用的对象就是迭代器(Iterator)。
  • 我们看前面的示例都是通过for循环遍历到元素然后输出,而迭代器是一个可以记住遍历位置的对象。我们通过迭代器迭代到的元素,控制迭代(迭代器的迭代只能迭代下去,不能回退的)。
  • 是可迭代对象(Iterable)不代表可以被next函数调用,需要将其转为迭代器(Iterator)才能被next。
l = {1: "aa", 2: "bb", 3: "cc"}
it = iter(l)  # 创建迭代器
key = next(it) #迭代
print("key:", key, "value:", l.get(key))  # key: 1 value: aa
key = next(it)
print("key:", key, "value:", l.get(key))  # key: 2 value: bb

这样一次一次next太麻烦了,我们可以配合循环使用迭代器。StopIteration异常标志着循环结束,防止无限循环的发生。

import sys

l = {1: "aa", 2: "bb", 3: "cc"}
it = iter(l)  # 创建迭代器
while True: # 循环开始
    try:
        key = next(it) 
        print("key:", key, "value:", l.get(key))  # key: 1 value: aa
    except StopIteration:
    	# break
        sys.exit() # 没有下一个key退出循环
生成器
  • 一边循环一边计算的机制是生成器(generator)。
  • 含有yield的函数皆为生成器。
  • 生成器不仅可以直接作用于for循环也可以被next函数调用,算是将Iterable和Iterator结合了。所以,生成器也算是一种迭代器了。

创建生成器:
1.将一个列表生成式变为生成器

print(i * i for i in [1, 2, 3, 4])
# <generator object <genexpr> at 0x000001FF47D84CF0>

2.或构造带yield的函数
yield可理解为return,return也意味着循环的结束。

def change(num):
    for x in range(num):
        result = yield x  # yield =>return x
        print("result: ", result)


g = change(3)
print(next(g))
print('-----------')
print(next(g))
print('-----------')
print(next(g))
'''
0
-----------
result:  None
1
-----------
result:  None
2
'''

分析代码与结果:

  • 函数change因为有了yield所以变成了生成器,我们这里使用next函数驱使其迭代下去。
  • 第一次next进入函数中的循环,x为0,yield x=》return
    0,此时函数结束,同时result没有赋值。而yield与一般return不同,当下一次next生成器时,会跳转到上次停止的地方,也就是result赋值操作。
  • 第二次next,接入上次操作,result赋值,可惜 x已经被上一次的操作return了,所以不存在为None赋值给result。但是此时不像上一次并没有return退出,所以循环继续,yield x,return 1。

之前写的代码还可以更改,通过for循环隐式next迭代,结果与图上是一样的。

def change(num):
    for x in range(num):
        result = yield x  # yield =>return x
        print("result: ", result)


g = change(3)
for i in g:
    print(i)

对于生成器我们不仅可以使用next迭代,还可以调用send函数,功能如何请看示例:

def change(num):
    for x in range(num):
        result = yield x  # yield =>return x
        print("result: ", result)


g = change(3)
print(next(g))
print('-----------')
print(g.send(3))
print('-----------')
print(next(g))

'''
0
-----------
result:  3
1
-----------
result:  None
2
'''

分析结果:

  • 第一次的next老样子,到了yield x 跳出了函数,最后结束位置在result赋值。
  • 此时生成器使用了send函数传值3,继续迭代。接入上次结束位置,result=3,继续循环x变为1,返回1跳出函数。后面的结果一样就不分析了。
    注意:send函数如果不传参,效果和next函数一样。

总结

我这次文章在生成器上花的时间更多一些,一开始对于yield特别的不理解,幸亏csdn上人才辈出,看了几篇博客后终于弄清楚了。也希望我这篇文章能或多或少帮助大家理解吧。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值