20函数----生成器(generator)

生成器(generator)是迭代器()的一种,其本质上就是迭代器
分为生成器函数、生成器表达式
1、生成器函数
只要函数内部含有yield关键字,那么函数名()的结果就是生成器,并且不会执行函数内部代码

例1:

def func():
    print('--------first')
    yield 1  #相当于return,是第一次__next__()的返回值,会保存函数的运行状态挂起函数
    print('---------second')
    yield 2
    print('---------third')
    yield 3
    print('end')

g = func()  #不会执行代码
print(g)  #<generator object func at 0x0000009F9D3D94C0>
# # 生成器内含__iter__()、__next__()方法,所以生成器就是迭代器。接上面函数,得到函数结果
print(g.__next__())
print(g.__next__())

# 或者用for循环迭代
for i in g:
    print(i)

 2、模拟实现range()

def my_range(start, stop, setp=1):
    while start < stop:
        yield start
        start += setp

g = my_range(1,8,2)
print(next(g))
print(next(g))
print(next(g))
print(next(g))

 3、模拟实现 tail -f | grep '404'

# tail 命令可用于查看文件的内容,参数 -f 常用于查阅正在改变的日志文件。
# grep 命令用于查找文件里符合条件的字符串
import time
def tail(filepath):
    with open(filepath,'rb') as f:
        f.seek(0, 2)  # 使用seek()方法,则文件打开方式必须是'rb'(这句话错了。。。),0为偏移量,  2表示从文件末尾算起
        while True:
            line = f.readline()
            if line:
                yield line
            else:
                time.sleep(2)

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

for line in grep('404', tail('data.txt')):
    print(line)

 4、send()

def eater():
    print('ready to eat')
    while True:  #感觉这里一般都要有一个死循环,用来持续接收g.send()
        food = yield #1 yield相当于函数的return 2、food = yield,接受send()传过来的值,赋值给food,并让生成器继续向下运行
        print('eat the food:【{}】...'.format(food))

g = eater()
next(g) #需要事先“初始化”一次,让函数挂起在food=yield,等待调用g.send()方法为其传值
g.send('包子')
g.send('apple')
g.send('orange')
可以用装饰器来完成为所有表达式形式yield对应生成器的初始化操作
def init(func):
    def wrapper(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g) #完成首次的“初始化”
        return g
    return wrapper

@init  #eater=init(eater)
def eater():
    print('ready to eat')
    while True:
        food = yield
        print('eat the food:【{}】...'.format(food))

g = eater()
g.send('ccccc')
g.send('hhhhh')

  

def init(func):
    def wrapper(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g) #完成首次的“初始化”
        return g
    return wrapper

@init
def eater():
    print('ready to eat...')
    food_list = []
    while True:
        food = yield food_list  #后面g.send('aaa')的值发送给yield=food,后面的food_list是函数的返回值
        food_list.append(food)
        print(food_list)


g = eater() # 这时候的 g 已经是装饰器里“初始化”后返回的 g 了
g.send('aaa')
g.send('bbbb')
g.close()#结束迭代

5、最简单的生产者消费者

import time
def init(func):
    def wrapper(*args, **kwargs):
        g = func(*args, **kwargs)
        next(g) #完成首次的“初始化”
        return g
    return wrapper

@init
def consumer(name):
    print('i am {}, ready to eat....'.format(name))
    while True:
        food = yield
        print(food)
        print('{} eating...'.format(name))

def producer():
    c1 = consumer('cc')#这里就是运行了consumer(),函数挂起在food=yield,等待调用g.send()方法为其传值
    c2 = consumer('dd')
    for i in range(10):
        c1.send('生产了包子{}'.format(i))
        c2.send('生产了包子{}'.format(i))
        time.sleep(2)

producer()

 

posted @ 2021-04-03 18:12  cheng4632  阅读(688)  评论(0编辑  收藏  举报