自學Python4.7-生成器(方式一:生成器函數)

自學Python之路-Python基礎+模塊+面向對象
自學Python之路-Python網絡編程
自學Python之路-Python併發編程+數據庫+前端
自學Python之路-djangohtml

自學Python4.7 - 生成器(方式一:生成器函數)

定義:生成器(generator)是一個包含yield關鍵字的函數,當它被調用的時候,在函數體中的代碼不會被執行,而是會返回一個迭代器。
          (一個函數調用時返回一個迭代器,那這個函數就叫作生成器(generator);      
              若是函數中包含yield語法,那這個函數就會變成生成器;)前端

  • 生成器是一個特殊的程序,能夠被用做控制循環的迭代行爲
  • 生成器相似於返回值爲數組的一個函數,這個函數能夠接收參數,能夠被調用,可是,不一樣於通常的函數會一次性返回包含了全部數值的數組,生成器一次 只產生一個值,這樣消耗的內粗數量大大減小,並且容許調用函數能夠很快的開始處理前幾個返回值。所以,生成器看起來像一個函數可是表現的卻像一個迭代器

python提供了兩種基本的生成器方式:python

  • 生成器函數:也是用def來定義,利用關鍵字yield一次返回一個結果,阻塞,從新開始
                         每次請求一個值,就會執行生成器中的代碼,知道遇到一個yield或者return語句
                         ①yield語句意味着應該生成一個值
                         ②return語句意味着要中止執行(不生成任何東西,只有在一個生成器中使用時才能進行無參數調用)
  • 生成器表達式:返回一個對象,這個對象只有在須要的時候才產生結果

1.  生成器函數:  

      爲何叫生成器函數?由於他隨着時間的推移生成了一個數值隊列。通常的函數在執行完畢以後會返回一個值而後退出,可是生成器函數會自動掛起,而後從新拾起繼續執行,他會利用yield關鍵字關起函數,給調用者返回一個值,同時保留了當前的足夠多的狀態,可使函數繼續執行。
     生成器和迭代協議是密切相關的,可迭代的對象都有一個__next()__成員方法,這個方法要麼返回迭代的下一項,要麼引發異常結束迭代。
     爲了支持迭代協議,擁有yield語句的函數被編譯爲生成器,這類函數被調用時返回一個生成器對象,返回的對象支持迭代接口,即成員方法__next()__繼續從中斷處執行執行。
數據庫

def func():   #func是函數稱爲生成器,當執行此函數func()時會獲得一個迭代器。
    yield 1
    yield 2
    yield 3
    yield 4
temp = func()
print(temp.__next__())
print(temp.__next__())
print(temp.__next__())
print(temp.__next__())

def creat_counter(n):
    print('create counter')
    while True:
        yield n
        print('increment n')
        n += 1
cnt = creat_counter(2)
print(cnt)
print(next(cnt))
print(next(cnt))
print(next(cnt))

分析以上的列子:django

  • 在create_counter函數中出現了關鍵字yield,預示着這個函數每次只產生一個結果值,這個函數返回一個生成器(經過第一行輸出能夠看出來),用來產生連續的n值
  • 在創造生成器實例的時候,只須要像普通函數同樣調用就能夠,可是這個調用卻不會執行這個函數,這個能夠經過輸出看出來
  • next()函數將生成器對象做爲本身的參數,在第一次調用的時候,他執行了create_counter()函數到yield語句,返回產生的值2
  • 咱們重複的調用next()函數,每次他都會從上次被掛起的地方開始執行,直到再次遇到了yield關鍵字
def cube(n):
    for i in range(n):
        yield i ** 3
for i in cube(5):
    print(i)

從理解函數的角度出發咱們能夠將yield類比爲return,可是功能確實徹底不一樣,在for循環中,會自動遵循迭代規則,每次調用next()函數,因此上面的結果不難理解。編程

舉例1:數組

舉例2:網絡

舉例3: 取不到值會報錯併發

 

舉例4: 使用for循環取值函數

 

舉例5.1  : 打印出10個哇哈哈

 

舉例5.2若是如今有10個哇哈哈, 我如今只想用5個

迭代器依舊延續向下走:

舉例6

def generator():
    print('123')
    content = yield 1
    print('=========',content)
    print(456)
    yield 2
g = generator()
ret = g.__next__()
print("******",ret)
ret = g.send("hello")
print("**********",ret)

send 獲取下一個值的效果和next基本一致,只是在獲取下一個值得時候,給上一個yield的位置傳遞一個數據

使用send的注意事項:

  • 第一次使用生成器的時候,是用next獲取下一個值
  • 函數最後一個yield不能接受外部的值

舉例7.1:
獲取移動平均值:
10   20   30   10 
   15  20   17.5

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.__next__()
avg1 = avg_g.send(10)
avg1 = avg_g.send(20)
avg1 = avg_g.send(30)
print(avg1)

舉例7.2:   預激生成器的裝飾器完成獲取移動平均值

def init(func):   #裝飾器
    def inner(*args,**kwargs):
        g = func(*args,**kwargs)    #g = average()
        g.__next__()
        return g
    return inner

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

avg_g = average()   #===> inner
ret = avg_g.send(10)
print(ret)
ret = avg_g.send(20)
print(ret)

以上程序執行步驟:

舉例8 :

在python3裏面的新功能 yield from 

 

 

.

相關文章
相關標籤/搜索