1. 程式人生 > >day 14 - 1 生成器

day 14 - 1 生成器

生成器

生成器
  生成器的本質就是迭代器
生成器的表現形式
  生成器函式
    生成器函式 —— 本質上就是我們自己寫得函式
  生成器表示式
生成器函式:
  含有 yield 關鍵字的函式就是生成器函式
  特點:
    呼叫函式的之後函式不執行,返回一個生成器
    每次呼叫 next 方法的時候會取到一個值
    直到取完最後一個,在執行 next 會報錯

從生成器中取值的幾個方法
  1、next
  2、for
  3、資料型別的強制轉換:佔用記憶體 print(list(g))

生成器函式

我們先來看下普通函式

def generator():
    print(1)
    
return 'a' ret = generator() print(ret)

接著來看生成器函式

#只要含有yield關鍵字的函式都是生成器函式
# yield 不能和 return 共用且需要寫在函式內
def generator():
    print(1)
    yield 'a'
#生成器函式:在執行之後會得到一個生成器作為返回值
ret = generator()   #此處的 ret 是一個生成器而不是值了
print(ret)          #此處在同過原來的呼叫方法呼叫的是記憶體地址
print(ret.__next__())   #通過 .__next__() 來呼叫函式的輸出內容

 

下面來看一個生成器函式的例子

#在取值時 會取到第一個 yield 時停止,然後等待下一次取值的動作開始,繼續取值到下一個 yield 
def generator():
    print(1)
    yield 'a'
    print(2)
    yield 'b'
    print(3)
    yield 'c'
g = generator()

ret = g.__next__()  #單獨執行第一次時:1 a
print(ret)
ret = g.__next__()  #即:可以控制執行的位置
print(ret)
ret = g.__next__
() print(ret) for i in g: #使用 for 迴圈也同樣可以 print(i) #但 for 迴圈不可以控制執行位置

 

寫一個函式 製造 200w 個娃哈哈

ef wahaha(*args):
    for i in range(2000000):
        yield "娃哈哈%s"%i
ret = wahaha(1000)

#呼叫
#for i in ret:
#    print(i)

#呼叫前 50 個
count=0
for i in ret:
    print(i)
    count+=1
    if count > 50:
        break
print(ret.__next__()) #這裡一起執行會接著 for 迴圈呼叫 ret ,返回第 51個

 

監聽檔案輸入的例子

#當檢查到檔案中有輸入含有 python 字元時就會在螢幕上列印
def tail(filename):
    f = open(filename,encoding='utf-8')  #檔案控制代碼
    while True:
        line = f.readline()
        if line.strip():
            yield line.strip()

ret = tail('D:/py/log/test.txt')
for i in ret:
    if 'python' in i:
        print('***',i)

 

生成器函式進階

關鍵字 send 的使用

#send 獲取下一個值的效果和 next 基本一致
#只是在獲取下一個值的時候,給上一 yield 的位置傳遞一個數據
#使用 send 的注意事項
    # 第一次使用生成器的時候 要、必須用 next 獲取下一個值
    # 最後一個 yield 不能接受外部的值

def generator():
    print(123)
    content = yield 1
    print('=====',content)
    print(456)
    yield 2

g = generator()
ret = g.__next__()
print('***',ret)
ret = g.send('hello')  #向函式 content 的位置傳值
print('***',ret)

 

獲取移動平均值(每次輸入一個值都會計算出一個平均值)

10 20 30 10
10 15 20 17.5
avg = sum/count

def average():
    sum = 0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum +=num
        count += 1
        avg = sum/count

avg = average()
avgs = avg.__next__()
avgs = avg.send(10)
avgs = avg.send(30)
avgs = avg.send(60)
avgs = avg.send(60)
print(avgs)

 預激生成器的裝飾器
獲取移動平均值進階與裝飾器的使用

#裝飾器的作用就是在使用者使用時,少寫一句 ret = g.__next__() 方便操作
def init(func):
    def inner(*args,**kwargs):
        ret = func(*args,**kwargs)
        ret.__next__()
        return ret
    return inner


@init
def average():
    sum =0
    count = 0
    avg = 0
    while True:
        num = yield avg
        sum += num
        count += 1
        avg=sum/count
        
avg = average()
ret = avg.send(10)
ret = avg.send(20)
ret = avg.send(60)
print(ret)
ret = avg.send(20)
ret = avg.send(20)
print(ret)

 

from 關鍵字的使用

#先來看一個 for 迴圈的例子,取出字串中所有的單個字元
def generator():
    a = 'abcde'
    b = '12345'
    for i in a:
        yield i
    for i in b:
        yield i
g = generator()
for i in g:
    print(i)

#使用 from 關鍵字取出
def generator():
    a = 'abcde'
    b = '12345'
    yield from a
    yield from b

g = generator()
for i in g:
    print(i)

 

生成器的表示式