'''
生成器函數:
只要含有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)