初学者python笔记(迭代器、生成器、三元表达式、列表解析、send()与yield())


可迭代对象是我们非常熟悉的一个名词,之前也简单介绍过 能被for循环的,就是可迭代对象, 但其实,这里面的水更深。

迭代器与for循环的关系

1. 迭代器协议

对象必须体统一个__next__方法,执行该方法要么返回迭代中的下一项,要么引起一个StopIteration异常,以终止迭代(只能往后走,不能往前退)

2. 可迭代对象

实现了迭代器协议的对象就是可迭代对象

3. for循环的本质

先将对象变为可迭代对象,再循环所有对象,全都是使用迭代器协议,一次一次得调用协议中的__next__方法
注意:
字符串、列表、元组、字典、集合、文件对象都不是可迭代对象,它们根本不存在next方法,只不过在for循环时,调用了它们内部的__iter__方法,把它们变成了可迭代对象

4. 强大的for循环机制

基于迭代器协议提供一个统一的可以遍历所有对象的方法,不管是有序的列表、字符串、元组,还是无序的集合、字典、文件,都可以通过for循环来遍历

5. 迭代器如何工作的
x = 'world'
iter_test=x.__iter__()  #用__iter__将x字符串变为可迭代对象
print(iter_test)  #这样会打印出该可迭代对象的编码
#成为可迭代对象后,就有了可迭代对象专有的next方法,就可以一步一步操作
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())
print(iter_test.__next__())

运行结果:
w
o
r
l
d
将字符串中的字符一个一个全部输出了

6. while循环模拟for循环与迭代器的结合
x = 'world'
iter_x = x.__iter__()  #将字符串变成可迭代对象
while True:  #循环遍历可迭代对象
    try:
        print(iter_x.__next__())  #输出每次遍历的结果
    except StopIteration:  #如果出现StopIteration,就终止
        print('迭代完毕了,循环终止了')
        break

运行结果:
w
o
r
l
d
迭代完毕了,循环终止了

7. 用内置函数next()取值可迭代对象
x = ['may','you','be','happy']
iter_x=x.__iter__()  #用__iter__将x字符串变为可迭代对象
#用内置函数next()取值可迭代对象
print(next(iter_x))
print(next(iter_x))
print(next(iter_x))
print(next(iter_x))

运行结果:
may
you
be
happy

生成器(迭代器的亲兄弟)

1. 迭代器与可迭代对象

通过以上的分析就可以看出,遵循迭代器协议的对象就是可迭代对象,这个可迭代对象就是迭代器

2. 生成器本质

自动实现可迭代协议的一种数据类型,这类数据默认已经iter过了,因此默认存在__next__方法

  1. 生成器函数:
    函数的返回值用yield而不是用return,这样返回的数据就是一个生成器,默认的可迭代对象,拥有__next__方法
def test():
    yield 'ok'
res = test()
print(res)
print(next(res))

三元表达式

name = '乌索普'
res = '骗子' if name == '乌索普' else '勇敢的海上战士'
#三元表达式,将if为True要执行的 表达放在if前面,if后接else
#这里的意思:如果name变量值为'乌索普',就将'骗子'赋值给res,
#否则赋值成'勇敢的海上战士'
print(res)

运行结果:
骗子

列表解析与生成器表达式

1. 普通赋值
egg = []
for i in range(10):
    egg.append('鸡蛋%s'%i)
print(egg)

运行结果:
[‘鸡蛋0’, ‘鸡蛋1’, ‘鸡蛋2’, ‘鸡蛋3’, ‘鸡蛋4’, ‘鸡蛋5’, ‘鸡蛋6’, ‘鸡蛋7’, ‘鸡蛋8’, ‘鸡蛋9’]

2. 列表解析(快速赋值)
egg = []
egg = ['鸡蛋%s'%i for i in range(10)]
print(egg)

甚至可以这样:

egg = []
egg = ['鸡蛋%s'%i for i in range(10) if i>=5]  #一个三元表达式
print(egg)

但是要注意。不存在四元表达式,所有不能:

egg = ['鸡蛋%s'%i for i in range(10) if i>=5 else i]
3. 生成器表达式
chicken = ('鸡%s' %i for i in range(10))  #制作一个生成器
print(chicken)  #输出生成器,会显示它是一个可迭代对象
print(chicken.__next__())  #用__next__方法一个一个输出可迭代对象
print(chicken.__next__())
print(next(chicken))
print(next(chicken))

运行结果:
鸡0
鸡1
鸡2
鸡3

Ps:列表解析与生成器表达式都是一种便利的编程方式,不过生成器表达式更节省内存,因为它是基于迭代器协议一个一个取值的

yield()与send()

1. 生成器的yield可以有多个
def test():
    print('this is line one')  #yield可以有多个,执行一次就停一下
    yield 1
    print('this is line two')
    yield 2
t = test()  #运行函数并将返回值赋给t,返回值是一个生成器
next(t)  #调用生成器,执行第一次
next(t)  #执行第二次

运行结果:
this is line one
this is line two

2. 运行迭代器的三种方法

分别是:next, next(), send()

def test():
    print('this is line one')  #yield可以有多个,执行一次就停一下
    yield 1
    print('this is line two')
    yield 2
    print('this is line three')
    yield 3
t = test()  #运行函数并将返回值赋给t,返回值是一个生成器
next(t)  #调用生成器,执行第一次
t.send('123')
#用send()传入一个值给当时停住的那个yield,此时第一个yield已经执行了,所以为第二个
#相当于传入一个值,让函数运行并返回传入的该值
t.__next__()  #执行第三次

运行结果:
this is line one
this is line two
this is line three

3. 不可退原理

生成器只能遍历一次

def test():
    for i in range(4):
        yield i
t = test()
t1 = (i for i in t)
#t1得到的就是生成器一个一个运行返回的值,但是t1此时并没有接收任何值,
#直到有了输出命令,生成器才开始执行,生成值,且不可退
t2 = (i for i in t1)
#因为生成器不可退,t1已经将生成器执行到了StopIteration,
#故再遍历t1已经没有生成器去运行了,因此会输出空列表
print(list(t1))  #list也遵循for循环协议,将生成器的内容提取出来组成一个列表
print(list(t2))

运行结果:
[0, 1, 2, 3]
[]

本篇可以说是生成器的完整剖析,生成器的内容大都囊括了。从最基本的原理到最终使用迭代器,贯穿了迭代器、生成器、三元表达式、列表解析、生成器函数、生成器表达式、send()与yield() 等多个方面的内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

鸿蒙Next

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

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

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

打赏作者

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

抵扣说明:

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

余额充值