19-迭代器、生成器【进阶】

迭代器

须知:迭代是一个重复的过程,且每次重复都是基于上一次的结果而来

eg1:这只是单纯的重复,且每次结果都一样

while True:
    print('123')

eg2:这是一次重复过程,且每次都是基于上一次得到结果

l=['a','b','c']
n=0
while n<len(l):
    print(l[n])
    n+=1

目的:能够迭代取值!!

1、迭代器:迭代取值的工具

2、可迭代对象:

在python中,但凡内置有__iter__方法的对象,都是可迭代对象(比如:str  list  tuple  dict  set  file

以下都是可迭代对象:str1="hello"   list1=['a','b','c']   tup1=(1,2,3)    dic={'x':1,'y':2}    s1={'a','b','c'}    f=open('a.txt','w',encoding='utf-8')

特点:内置有__iter__方法的都可以是可迭代对象执行完该方法得到一个迭代器对象

3、迭代器对象:

注:file(文件)既有__iter__,也有__next__方法,则文件本身就是迭代器对象。

3-1)获取方式:执行可迭代对象的__iter__方法,拿到的返回值就是迭代器对象。   

3-2)特点:内置有__next__方法,执行该方法能得到值;

                   内置有__iter__方法,执行该方法拿到迭代器本身

l='psy'  #l为可迭代对象
iter_l=l.__iter__()  #iter_l为迭代器对象
while True:
    try:
        res=iter_l.__next__()
        print(res)
    except StopIteration:
        break

分析2和3:

可迭代对象:内置有__iter__方法         迭代器对象:内置有__iter__和__next__方法

可迭代对象不一定是迭代器对象          迭代器对象一定是可迭代对象。

4、迭代器的优点

4-1)提供了一种可不依赖索引的取值方法====》利用迭代器对象的__next__方法

        但是此方法较为麻烦:(1)要先把可迭代对象变成迭代器对象(__iter__方法)

                                         (2)使用迭代器对象的__next__方法,会报错(使用try: except;避免)

        So引入for循环====》迭代器循环     【in后面必须要是可迭代对象】

l='psy'  #l为可迭代对象
for item in l:
    print(item)

4-2)迭代器更省空间

5、迭代器的缺点

    取值麻烦,只能一个一个的取值,从前往后,不能回头

生成器    利用yield关键字

不恰当的例子:函数就像母鸡生鸡蛋

before:原先母鸡生鸡蛋:

def chicken():
    print('===>first')
    return 1
    print('===>second')
    return 2
    print('===>third')
    return 3
res=chicken()
print(res)

注:此时遇到return 就返回,所以最终只能生一个鸡蛋

now:利用生成器(yield),母鸡生鸡蛋:

def chicken():
    print('===>first')
    yield 1
    print('===>second')
    yield 2
    print('===>third')
    yield 3
obj=chicken() 
print(obj)  #<generator object chicken at 0x000001E00ED92C50>

注:此时的obj是一个生成器,但是obj下面有__iter__和__next__方法,所以obj也是迭代器对象【利用for循环,可以得到里面的值】

1、生成器:

    (1)函数内包含yield关键字

    (2)再调用函数,就不会执行函数体代码,拿到的返回值是一个生成器对象

2、实质

生成器本质就是迭代器【===》咋用迭代器,就咋用生成器】

针对上面的obj(obj=chicken(),此时obj是一个生成器,也是一个迭代器,利用for循环得到结果)

for item in obj:
    print(item)

这两行代码的实际流程:(1)iter_obj=obj.__iter__() 拿到迭代器;

                                     (2)出发iter_obj.__next__() 拿到该方法的返回值,赋值给item;

                                    (3)周而复始,直到函数内不再有yield,则取值完毕;

                                    (4)for 会自动检测到StopIteration异常,结束循环。

3、yield理解

(1)提供了一种自定义迭代器的方法

【可以在函数内使用yield关键字,调用函数拿到的结果就是一个生成器,生成器就是迭代器】

(2)yield可以像return一样用于返回值,区别:return只能返回一次值,yield能够返回多次值

【因为yield可以保存函数执行的状态

4、yield进阶  【一个小例子(小猪吃东西)】

4-1)简单版

def eat(name):
    print('{} is ready to eat'.format(name))
    while True:
        food=yield   #一开始的时候,food为None,因为没有传值
        print('eat {}'.format(food))
pig=eat('胖猪')
print(pig)  #<generator object eat at 0x0000026BFF3CF678>
#1、必须初始化,让函数停在yield位置
pig.__next__()  #胖猪 is ready to eat
#2、接下来就是喂猪,利用send
"""
send有两个功能:(1)给yield传值。(2)同__next__功能
"""
pig.send('泔水')  #eat 泔水
pig.send('猪粮')  #eat 猪粮

4-2)较难版   【自己多琢磨琢磨吧。。。。。。】

def eat(name):
    print('{} is ready to eat'.format(name))
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food)
        print('eat {}'.format(food_list))
pig=eat('瘦猪')
print(pig)  #<generator object eat at 0x000001F62EBBF678>
#1、必须初始化,让函数停在yield位置
res=pig.__next__()
print(res)
"""
瘦猪 is ready to eat
[]
"""
res1=pig.send('泔水')
print(res1)
"""
eat ['泔水']
['泔水']
"""
print('***')
res2=pig.send('猪粮')
print(res2)
"""
eat ['泔水', '猪粮']
['泔水', '猪粮']
"""

迭代器和生成器的总结  

1、迭代器:

可迭代对象:只有__iter__方法                   可迭代对象通过__iter__方法,得到迭代器对象

迭代器对象:有__iter__和__next__方法     迭代器对象通过__iter__方法得到它本身,迭代器对象通过__next__方法得到值

for循环就是迭代循环,能被for循环的,一定是可迭代对象。

2、生成器

    在函数内部加上yield关键字,得到一个生成器!

补充:列表生成式生成器表达式

1、列表生成式【便捷】    ====>针对数据量比较小

eg:生成一个列表,为['egg0','egg1','egg2',......'egg100']

before:

eggs=[]
for i in range(101):
    eggs.append('egg{}'.format(i))

now:利用列表生成式

eggs=['egg{}'.format(i) for i in range(101)]

还可以加上判断

eggs=['egg{}'.format(i) for i in range(101) if i>10]

列表生成式的语法:[expression  for item in iteration  if condition]  《=等价=》  [表达式   for循环   if判断]

但是:列表生成式占内存空间,所以引入:生成器表达式

2、生成器表达式      ====>针对数据量比较大

针对上题:

eggs=('egg{}'.format(i) for i in range(101))
print(eggs)  #<generator object <genexpr> at 0x000002399DFBF678>
#发现eggs具有__iter__和__next__  所以生成器本身就是迭代器
#此时可通过以下方法取值
print(eggs.__next__())  #egg0
print(next(eggs))  #egg1

生成器表达式的语法:(expression  for item in iteration  if condition)  《=等价=》  (表达式   for循环   if判断)

3、练习题

(1)将names=['psy','xk','dd']中的字符变成大写

names=['psy','xk','dd']
res=[name.upper() for name in names]
print(res)  #['PSY', 'XK', 'DD']

(2)将names=['psy','xk','dd_good']中以good结尾的名字过滤,然后保存剩下的长度

names=['psy','xk','dd_good']
res=[len(name) for name in names if not name.endswith('good')]
print(res)  #[3, 2]

转载于:https://my.oschina.net/pansy0425/blog/3026929

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值