迭代器 / 生成器

2021-08-13  本文已影响0人  慕知

一,迭代器

1,前提

# 1)单纯的重复不是迭代
while True:
    msg = input('>>: ').strip()
    print(msg)
# >>: 3
# 3
# >>: 4
# 4



# 2)while循环是一个迭代的过程
info=['aa','bb','cc','dd']
i=0
while i < len(info):
    print(info[i])
    i+=1
# aa
# bb
# cc
# # dd

2,可迭代对象

#索引进行迭代取值仅适用于:字符串,列表,元祖
#字典、集合等非序列类型不适用
#可迭代对象都能满足迭代取值
abc='good'
abc.__iter__()   # .__iter__()打开的都是可迭代对象


info=[1,2,4]
info.__iter__()



3,迭代器对象

#1,迭代器对象内置的有iter和next方法的对象,打开的文件本身就是一个迭代器对象
#2,执行迭代器对象.iterm()方法得到的仍然是迭代器本身
#3,执行迭代器.next()方法就会计算出迭代器的下一个值

info=(1,4,5)
new=info.__iter__()
print(next(new))
print(next(new))
print(next(new))
# 1
# 4
# 5





注意事项:
# 1)如果再执行,超过了元祖定义的元素数量就会报错
print(next(new))
#     print(next(new))
# StopIteratio

#2)以上迭代到最没有值会报错,如果想反复循环或者得出第一个值的需求,只能重新定义如下:
new=info.__iter__()
print(next(new))
... ...

4,for / while

实现StopIteration: #捕捉异常终止循环

# StopIteration: #捕捉异常终止循环
info={'lili','peter','ssen'}
i=iter(info)
while True:
    try:            #检测以下的语法
        print(next(i))
    except StopIteration:        #捕捉到一场终止循环
        break
# peter
# lili
# ssen






#for 循环实现迭代
abc=[1,2,3]
for i in abc:
    print(i)
# 1
# 2
# 3
# 工作原理:
#1)先调用可迭代对象abc内置的iter方法拿到一个迭代对象
#2)调用该迭代器对象的next方法取到的值赋值给iterm,执行循环体完成一次循环
#3)知道捕捉到StopIteration异常,结束迭代

二,生成器

1)yield

例1)
# yield相当于return,返回当前函数
def foo():
    print('111')
    yield
    print('222')
    yield
    print('333')
    yield

f=foo().__iter__()
next(f)
#111

next(f)
# 111
# 222

next(f)
# 111
# 222
# 333







例2)
def foo(start,stop,step=1):
    print('start...')
    while start < stop:
        yield start
        start+=step
    print('end...')

g=foo(0,3).__iter__()
print(g)
# <generator object foo at 0x1049e39e0>
print(next(g))
# start...
# 0

print(next(g))
# start...
# 0
# 1

print(next(g))
# start...
# 0
# 1
# 2

print(next(g)) # 会报错
# start...
# 0
# 1
# 2
# end...
# StopIteration

补充

def func():
    print('11111')
    yield 1
    print('22222')
    yield 2
    print('33333')
    yield 3

f=func()
print(f)
# <generator object func at 0x1034579e0>    生成器就是迭代器

res=next(f)
# 11111   只要出发next,就会触发函数本身,即使在赋值也会返回值

print(res)
# # 1




# 如果直接next方式如下
g=func()
g.__next__()
# 11111

g.__next__()
# 11111
# 22222


yield可以返回多次值;
函数的暂停和与再继续状态是由yield保存

2)yield表达式应用

示例1

def eater(name):
    print('%s ready to eat' % name)
    while True:
        food=yield
        print('%s start to eat %s' %(name,food))

e=eater('mz')   # 生成一个迭代器
print(e)
# <generator object eater at 0x1006439e0>

# #初始化方式一:
# next(e)
# # mz ready to eat

#初始化方式二:
e.send(None)
# mz ready to eat

# 从暂停的位置传值给yield,yield再赋值给food
e.send('apple')
# mz ready to eat
# mz start to eat apple

# 继续传值,会再yield的状态下继续执行
e.send('banana')
# mz ready to eat
# mz start to eat apple
# mz start to eat banana




示例2

def eater():
    print('吃什么呢')
    while True:
        food=yield
        print('吃%s啦'% food)

f=eater()
print(f)
# <generator object eater at 0x104b239e0>

next(f)       # 此步骤非常重要!必须要先执行一次!
# 需要事先”初始化”一次,让函数挂起在food=yield,等待调用g.send()方法为其传值
# ready to eat      #执行结果

f.send('汉堡')
# 吃什么呢
# 吃汉堡啦

f.send('牛排')
# 吃什么呢
# 吃汉堡啦
# 吃牛排啦


示例升级版

def init(func):
    def wrapper(*args,**kwargs):
        g=func(*args,**kwargs)
        next(g)
        return g
    return wrapper

@init

def eater():
    print('吃什么呢')
    while True:
        food=yield
        print('吃%s啦'% food)

a=eater()
# 吃什么呢

a.send('鸡腿')
# 吃什么呢
# 吃鸡腿啦

a.send('冰淇淋')
# 吃什么呢
# 吃鸡腿啦
# 吃冰淇淋啦

示例再升级版

def init(func):
    def wrapper(*args,**kwargs):
        f=func(*args,**kwargs)
        next(f)
        return f
    return wrapper

@init
def eater():
    print('吃什么呢')
    food_list=[]
    while True:
        food=yield food_list
        food_list.append(food)


a=eater()

print(a.send('蛋糕'))
# 吃什么呢
# ['蛋糕']

print(a.send('牛奶'))
# 吃什么呢
# ['蛋糕']
# ['蛋糕', '牛奶']

print(a.send('巧克力'))
# 吃什么呢
# ['蛋糕']
# ['蛋糕', '牛奶']
# ['蛋糕', '牛奶', '巧克力']



示例

# 实现tail -f的功能

import time
def tail(filepath):
    with open(filepath,'rb') as f:
        f.seek(0,2)
        while True:
            line=f.readline()
            if line:
                yield line
            else:
                time.sleep(0.2)

def grep(pattern,lines):
    for line in lines:
        line=line.decode('utf-8')
        if pattern in line:
            yield line



# 执行以下向access.log这个文件输入内容
with open('access.log',mode='at',encoding='utf-8') as f:
    f.write("aaa404aa\n")



# 执行函数,便会出现以下内容
for line in grep('404',tail('access.log')):
    print(line,end='')

#aaa404aa



分析:
# 函数里有yield,则以下是个迭代器(或生成器)
g=tail('access.log')
print(g)
# <generator object tail at 0x104f74510>

for line in g:
    print(line)
#这个时候只要access.log这个文件出现新内容,就会输出到屏幕上


上一篇 下一篇

猜你喜欢

热点阅读