自學Python4.8-生成器(方式二:生成器表達式)

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

自學Python4.8 - 生成器(方式二:生成器表達式)

 

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

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

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

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

2.  生成器表達式: 

 生成器表達式來自於迭代和列表解析的組合,生成器表達式和列表解析相似,可是他使用尖括號而不是方括號括起來的。數據庫

print([ x ** 3 for x in range(5)]) # 列表推導式
print((x ** 3 for x in range(5))) # 生成器表達式
print(list(x ** 3 for x in range(5)))# 二者之間轉換

輸出:django

for n in (x ** 3 for x in range(5)):
    print('%s, %s' % (n, n * n))  # 就操做而言,生成器表若是使用大量的next()函數會顯得十分不方便,for循環會自動出發next函數  

輸出:編程

[每個元素或者是和元素相關的操做 for 元素 in 可迭代數據類型] #遍歷以後挨個處理數組

[知足條件的元素相關的操做 for 元素 in 可迭代數據類型 if 元素相關的條件] #篩選功能網絡

舉例1:
30之內全部能被3整除的數
 
舉例2:
30之內全部能被3整除的數的平方
舉例3:
找到嵌套列表中名字含有兩個‘e’的全部名字
names = [['Tom', 'Billy', 'Jefferson', 'Andrew', 'Wesley', 'Steven', 'Joe'],
         ['Alice', 'Jill', 'Ana', 'Wendy', 'Jennifer', 'Sherry', 'Eva']]
ret = [name for lst in names for name in lst if name.count('e') ==2]
print(ret)

字典推導式多線程

舉例1:併發

將一個字典的key和value對調

舉例2:

合併大小寫對應的value值,將k統一成小寫

 

舉例3:

集合推導式,自帶結果去重功能

 

3. 生成器函數與協程生成器表達式比較

  一個迭代既能夠被寫成生成器函數,也能夠被協程生成器表達式,均支持自動和手動迭代。並且這些生成器只支持一個active迭代,也就是說生成器的迭代器就是生成器自己。

def recv():
    print('Are your ready:')
    while True:
        n = yield  #yield語句還有更給力的功能,做爲一個語句出如今賦值運算符的右邊,接受一個值,或同時生成一個值並接受一個值
        print('總共用了 %s 秒' % n)
c = recv()
c.__next__()
c.send(100)
c.send(300)

輸出:

解釋:以上這種方式使用yield語句的函數稱爲協程。在這個例子中,對於__next__的初始調用是必不可少的,這樣協程才能執行可通向第一個yield表 達式的語句。在這裏協程會掛起,等待相關生成器對象send()方法給它發送一個值。傳遞給send()的值由協程中的yield表達式返回。 協程的運行通常是無限期的,使用方法close()能夠顯式的關閉它。

def split_line():
    print('ready to split')
    result = None
    while True:
        line = yield result  #若是yield表達式中提供了值,協程可使用yield語句同時接收和發出返回值
        result = line.split()
s = split_line()
s.__next__()
print(s.send('1,2,3'))

輸出:

解釋:

這個例子中的前後順序很是重要。首個next()方法讓協程執行到yield result,這將返回result的值None。
在接下來的send()調用中,接收到的值被放到line中並拆分到result中。
send()方法 的返回值就是下一條yield語句的值。也就是說,send()方法能夠將一個值傳遞給yield表達式,可是其返回值來自下一個yield表達式,而不是接收send()傳遞的值的yield表達式。

③  若是想用send()方法來開啓協程的執行,必須先send一個None值,由於這時候是沒有yield語句來接受值的,不然就會拋出異常

def split_line():
    print('ready to split')
    result = None
    while True:
        line = yield result  #若是yield表達式中提供了值,協程可使用yield語句同時接收和發出返回值
        result = line.split()
s=split_line()
print(s.send('1 2 3'))

輸出:

def split_line():
    print('ready to split')
    result = None
    while True:
        line = yield result  #若是yield表達式中提供了值,協程可使用yield語句同時接收和發出返回值
        result = line.split()
s=split_line()
print(s.send(None))
print(s.send('1 2 3'))

輸出:

④ 生成器的功能很是強大。協程能夠用於實現某種形式的併發。在某些類型的應用程序中,能夠用一個任務調度器和一些生成器或協程實現協做式用戶空 間多線程,即greenlet。

yield的威力將在協程,協同式多任務處理(cooperative multitasking),以及異步IO中獲得真正的體現。

 

 

 

...

相關文章
相關標籤/搜索