'''
生成器函数:
只要含有yield关键字的函数都是生成器函数,且该关键字只能写在函数里,并且yield不能与return共用
特点:
调用函数之后函数不执行,返回一个生成器
每次调用__next__方法后会取到一个值,知道取完最后一个,再执行__next__(or next())会报错
生成器本质上就是迭代器
生成器的表现形式:
生成器函数:生成器函数本质上就是我们自己写的函数
生成器表达式
生成器中取值的几个方法
1.next 2.for 3.数据类型的强制转换(耗内存)
'''
# def generator():
# print("这是生成器函数1")
# yield '生成器函数返回值1' # 与return 的作用类似,都可以返回值,但是yield返回值后并不会结束函数
# print("这是生成器函数2")
# yield '生成器函数返回值2'
# print("这是生成器函数3")
# yield '生成器函数返回值3'
#
# g = generator() # 返回的是一个生成器对象
# print(g.__next__()) # 通过__next__()函数可以迭代生成器,直到找到下一个yield为止
# 我们也可以通过for循环来迭代,其实for循环内部就实现了迭代器的方式,用for循环来读取生成器中的内容时,会全部读取,而不是一个一个读取
# for i in g:
# print("-----"+i)
#------------------------------------------------------------------------------------------------------------------------
# 下面是利用生成器来监听文件输入的例子
# def monitor(filename):
# obj = open(file=filename, encoding='utf-8')
# while True:
# line = obj.readline()
# if line.strip(): # 当读取的一行不为空才返回
# yield line.strip()
#
# g = monitor('filemonitor.txt') # 这里我们得到一个生成器对象
# # 下面是我们需要监听的内容,假设当文件被写入了含有python的内容时,我们可以将这行内容打印出来
# # 注意:在向文件写入完内容后必须保存才行。
# for i in g:
# if 'python' in i:
# print("包含python的一行是:",i)
#------------------------------------------------------------------------------------------------------------------------
# 生成器中send的使用形式
# def generator():
# print("这是生成器函数1")
# content = yield '生成器函数返回值1' # 用content接收send过来的值
# print("接收返回的值:",content)
# print('xxxxxxxxxxxxxxxxxx')
# yield '生成器返回值2'
#
# g = generator() # 返回的是一个生成器对象
# print(g.__next__()) # 通过__next__()函数可以迭代生成器,直到找到下一个yield为止
# ret = g.send("接收成功")
# print('---->',ret)
# 打印如下 这是生成器函数1
# 生成器函数返回值1
# 接收返回的值: 接收成功
# xxxxxxxxxxxxxxxxxx
# ----> 生成器返回值2
'''
send 获取下一个值的效果和next基本一致
只是在获取下一个值的时候,给上一个返回值的位置(即上一个yield的位置)传递一个数据
使用send的注意事项
在第一次使用生成器时,必须先使用__next__获取下一个值
最后一个yield不能接收外部的值
'''
#------------------------------------------------------------------------------------------------------------------------
# 生成器函数进阶(使用一个计算平均数的例子来演示----输入一个数,计算一次平均数)
#
# def average():
# sum = 0
# count = 0
# avg = 0
# while True:
# num = yield avg
# sum += num
# count += 1
# avg = sum / count
#
# avg_g = average()
# print(next(avg_g)) # 返回0
# print(avg_g.send(10)) # 返回10
# print(avg_g.send(20)) # 返回15
# 上述的就是一个利用生成器函数不断计算输入数的平均数的例子,不过在上述代码中,我们要先调用一个__next__(或者next()方法)方法,在能再调用send
# 对于这个问题,下面我们可以使用装饰器来解决
# 下面就是预激生成器的装饰器
# def init(function): # 在调用被装饰生成函数的时候首先用next激活生成器
# def inner(*args, **kwargs):
# g = function(*args, **kwargs)
# next(g)
# return g
# return inner
#
# @init
# def average():
# sum = 0
# count = 0
# avg = 0
# while True:
# num = yield avg
# sum += num
# count += 1
# avg = sum / count
#
# avg_g = average()
# avg_g = average()
# print(next(avg_g)) # 在装饰器中使用了next方法
# print(avg_g.send(10)) # 返回10
# print(avg_g.send(20)) # 返回15
# 在这里就少了上面一步先调用__next__的步骤
#------------------------------------------------------------------------------------------------------------------------
# def generator():
# a = [1,2,3]
# b = ('a','b','c')
# c = {'A':'a','B':'b'}
# yield from a # 将a容器中的元素一个一个返回
# yield from b # 将b容器中的元素一个一个返回
# yield from c # 将字典的键返回回去
#
# g = generator()
# for i in g:
# print(i)
# 注意 yield from 后面只能跟一个变量
#------------------------------------------------------------------------------------------------------------------------
'''
生成器的表达式
生成器的表达式与列表推导式是类似的,只是括号不一样而已,生成器表达式最终拿到的是生成器
'''
# a = [i*2 for i in range(10)] # 这就是列表推导式
# print(a)
#
# g = (i*2 for i in range(10)) # 这就是生成器表达式
# print(g)