欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python中的生成器和yield詳細(xì)介紹

 更新時(shí)間:2015年01月09日 10:45:37   投稿:junjie  
這篇文章主要介紹了Python中的生成器和yield詳細(xì)介紹,本文講解了列表推導(dǎo)與生成器表達(dá)式、斐波那契數(shù)列、生成器Generator、協(xié)程與yield表達(dá)式、使用生成器與協(xié)程等內(nèi)容,需要的朋友可以參考下

列表推導(dǎo)與生成器表達(dá)式

當(dāng)我們創(chuàng)建了一個(gè)列表的時(shí)候,就創(chuàng)建了一個(gè)可以迭代的對(duì)象:

復(fù)制代碼 代碼如下:

>>> squares=[n*n for n in range(3)]
>>> for i in squares:
 print i
 
0
1
4

這種創(chuàng)建列表的操作很常見,稱為列表推導(dǎo)。但是像列表這樣的迭代器,比如str、file等,雖然用起來(lái)很方便,但有一點(diǎn),它們是儲(chǔ)存在內(nèi)存中的,如果值很大,會(huì)很麻煩。

而生成器表達(dá)式不同,它執(zhí)行的計(jì)算與列表包含相同,但會(huì)迭代的生成結(jié)果。它的語(yǔ)法與列表推導(dǎo)一樣,只是要用小括號(hào)來(lái)代替中括號(hào):

復(fù)制代碼 代碼如下:

>>> squares=(n*n for n in range(3))
>>> for i in squares:
 print i
 
0
1
4

生成器表達(dá)式不會(huì)創(chuàng)建序列形式的對(duì)象,不會(huì)把所有的值都讀取到內(nèi)存中,而是會(huì)創(chuàng)建一個(gè)通過迭代并按照需求生成值的生成器對(duì)象(Generator)。

那么,還有沒有其它方法來(lái)產(chǎn)生生成器呢?

例子:斐波那契數(shù)列

例如有個(gè)需求,要生成斐波那契數(shù)列的前10位,我們可以這樣寫:

復(fù)制代碼 代碼如下:

def fib(n):
    result=[]
    a=1
    b=1
    result.append(a)
    for i in range(n-1):
        a,b=b,a+b
        result.append(a)
    return result
if __name__=='__main__':
    print fib(10)

數(shù)字很少時(shí),函數(shù)運(yùn)行良好,但數(shù)字很多時(shí),問題就來(lái)了,顯然生成一個(gè)幾千幾萬(wàn)長(zhǎng)度的列表并不是一個(gè)很好的主意。

這樣,需求就變成了:寫一個(gè)可以生成可迭代對(duì)象的函數(shù),或者說,不要讓函數(shù)一次返回全部的值,而是一次返回一個(gè)值。

這好像與我們的常識(shí)相違背,當(dāng)我們調(diào)用一個(gè)普通的Python函數(shù)時(shí),一般是從函數(shù)的第一行代碼開始執(zhí)行,結(jié)束于return語(yǔ)句、異常或者函數(shù)結(jié)束(可以看作隱式的返回None):

復(fù)制代碼 代碼如下:

def fib(n):
    a=1
    b=1
    for i in range(n-1):
        a,b=b,a+b
        return a
if __name__=='__main__':
    print fib(10)
>>>
1    #返回第一個(gè)值時(shí)就卡住了

函數(shù)一旦將控制權(quán)交還給調(diào)用者,就意味著全部結(jié)束。函數(shù)中做的所有工作以及保存在局部變量中的數(shù)據(jù)都將丟失。再次調(diào)用這個(gè)函數(shù)時(shí),一切都將從頭創(chuàng)建。函數(shù)只有一次返回結(jié)果的機(jī)會(huì),因而必須一次返回所有的結(jié)果。通常我們都這么認(rèn)為的。但是,如果它們并非如此呢?請(qǐng)看神奇的yield:
復(fù)制代碼 代碼如下:

def fib(n):
    a=1
    yield a
    b=1
    for i in range(n-1):
        a,b=b,a+b
        yield a
if __name__=='__main__':
    for i in fib(10):
        print i
>>>
1
1
2
3
5
8
13
21
34

生成器Generator

python中生成器的定義很簡(jiǎn)單,使用了yield關(guān)鍵字的函數(shù)就可以稱之為生成器,它生成一個(gè)值的序列:

復(fù)制代碼 代碼如下:

def countdown(n):
    while n>0:
        yield n
        n-=1
if __name__=='__main__':
    for i in countdown(10):
        print i

生成器函數(shù)返回生成器。要注意的是生成器就是一類特殊的迭代器。作為一個(gè)迭代器,生成器必須要定義一些方法,其中一個(gè)就是__next__()。如同迭代器一樣,我們可以使用next()函數(shù)(Python3是__next__() )來(lái)獲取下一個(gè)值:
復(fù)制代碼 代碼如下:

>>> c=countdown(10)
>>> c.next()
10
>>> c.next()
9

每當(dāng)生成器被調(diào)用的時(shí)候,它會(huì)返回一個(gè)值給調(diào)用者。在生成器內(nèi)部使用yield來(lái)完成這個(gè)動(dòng)作。為了記住yield到底干了什么,最簡(jiǎn)單的方法是把它當(dāng)作專門給生成器函數(shù)用的特殊的return。調(diào)用next()時(shí),生成器函數(shù)不斷的執(zhí)行語(yǔ)句,直至遇到y(tǒng)ield為止,此時(shí)生成器函數(shù)的”狀態(tài)”會(huì)被凍結(jié),所有的變量的值會(huì)被保留下來(lái),下一行要執(zhí)行的代碼的位置也會(huì)被記錄,直到再次調(diào)用next()繼續(xù)執(zhí)行yield之后的語(yǔ)句。

next()不能無(wú)限執(zhí)行,當(dāng)?shù)Y(jié)束時(shí),會(huì)拋出StopIteration異常。迭代未結(jié)束時(shí),如果你想結(jié)束生成器,可以使用close()方法。

復(fù)制代碼 代碼如下:

>>> c.next()
1
>>> c.next()
StopIteration
>>> c=countdown(10)
>>> c.next()
10
>>> c.close()
>>> c.next()
StopIteration

協(xié)程與yield表達(dá)式

yield語(yǔ)句還有更給力的功能,作為一個(gè)語(yǔ)句出現(xiàn)在賦值運(yùn)算符的右邊,接受一個(gè)值,或同時(shí)生成一個(gè)值并接受一個(gè)值。

復(fù)制代碼 代碼如下:

def recv():
    print 'Ready'
    while True:
        n=yield
        print 'Go %s'%n
>>> c=recv()
>>> c.next()
Ready
>>> c.send(1)
Go 1
>>> c.send(2)
Go 2

以這種方式使用yield語(yǔ)句的函數(shù)稱為協(xié)程。在這個(gè)例子中,對(duì)于next()的初始調(diào)用是必不可少的,這樣協(xié)程才能執(zhí)行可通向第一個(gè)yield表達(dá)式的語(yǔ)句。在這里協(xié)程會(huì)掛起,等待相關(guān)生成器對(duì)象send()方法給它發(fā)送一個(gè)值。傳遞給send()的值由協(xié)程中的yield表達(dá)式返回。

協(xié)程的運(yùn)行一般是無(wú)限期的,使用方法close()可以顯式的關(guān)閉它。

如果yield表達(dá)式中提供了值,協(xié)程可以使用yield語(yǔ)句同時(shí)接收和發(fā)出返回值。

復(fù)制代碼 代碼如下:

def split_line():
    print 'ready to split'
    result=None
    while True:
        line=yield result
        result=line.split()
>>> s=split_line()
>>> s.next()
ready to split
>>> s.send('1 2 3')
['1', '2', '3']
>>> s.send('a b c')
['a', 'b', 'c']

注意:理解這個(gè)例子中的先后順序非常重要。首個(gè)next()方法讓協(xié)程執(zhí)行到y(tǒng)ield result,這將返回result的值None。在接下來(lái)的send()調(diào)用中,接收到的值被放到line中并拆分到result中。send()方法的返回值就是下一條yield語(yǔ)句的值。也就是說,send()方法可以將一個(gè)值傳遞給yield表達(dá)式,但是其返回值來(lái)自下一個(gè)yield表達(dá)式,而不是接收send()傳遞的值的yield表達(dá)式。

如果你想用send()方法來(lái)開啟協(xié)程的執(zhí)行,必須先send一個(gè)None值,因?yàn)檫@時(shí)候是沒有yield語(yǔ)句來(lái)接受值的,否則就會(huì)拋出異常。

復(fù)制代碼 代碼如下:

>>> s=split_line()
>>> s.send('1 2 3')
TypeError: can't send non-None value to a just-started generator
>>> s=split_line()
>>> s.send(None)
ready to split

使用生成器與協(xié)程

乍看之下,如何使用生成器和協(xié)程解決實(shí)際問題似乎并不明顯。但在解決系統(tǒng)、網(wǎng)絡(luò)和分布式計(jì)算方面的某些問題時(shí),生成器和協(xié)程特別有用。實(shí)際上,yield已經(jīng)成為Python最強(qiáng)大的關(guān)鍵字之一。

比如,要建立一個(gè)處理文件的管道:

復(fù)制代碼 代碼如下:

import os,sys
def default_next(func):
    def start(*args,**kwargs):
        f=func(*args,**kwargs)
        f.next()
        return f
    return start
@default_next
def find_files(target):
    topdir=yield
    while True:
        for path,dirname,filelist in os.walk(topdir):
            for filename in filelist:
                target.send(os.path.join(path,filename))

@default_next
def opener(target):
    while True:
        name=yield
        f=open(name)
        target.send(f)
   
@default_next
def catch(target):
    while True:
        f=yield
        for line in f:
            target.send(line)
           
@default_next
def printer():
    while True:
        line=yield
        print line


然后將這些協(xié)程連接起來(lái),就可以創(chuàng)建一個(gè)數(shù)據(jù)流處理管道了:
復(fù)制代碼 代碼如下:

finder=find_files(opener(catch(printer())))
finder.send(toppath)

程序的執(zhí)行完全由將數(shù)據(jù)發(fā)送到第一個(gè)協(xié)程find_files()中來(lái)驅(qū)動(dòng),協(xié)程管道會(huì)永遠(yuǎn)保持活動(dòng)狀態(tài),直到它顯式的調(diào)用close()。

總之,生成器的功能非常強(qiáng)大。協(xié)程可以用于實(shí)現(xiàn)某種形式的并發(fā)。在某些類型的應(yīng)用程序中,可以用一個(gè)任務(wù)調(diào)度器和一些生成器或協(xié)程實(shí)現(xiàn)協(xié)作式用戶空間多線程,即greenlet。yield的威力將在協(xié)程,協(xié)同式多任務(wù)處理(cooperative multitasking),以及異步IO中得到真正的體現(xiàn)。

相關(guān)文章

  • 詳解Django定時(shí)任務(wù)模塊設(shè)計(jì)與實(shí)踐

    詳解Django定時(shí)任務(wù)模塊設(shè)計(jì)與實(shí)踐

    這篇文章主要介紹了詳解Django定時(shí)任務(wù)模塊設(shè)計(jì)與實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2019-07-07
  • 教你實(shí)現(xiàn)Ubuntu安裝Python

    教你實(shí)現(xiàn)Ubuntu安裝Python

    這篇文章主要為大家介紹了Ubuntu安裝Python的實(shí)現(xiàn)過程詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-06-06
  • Python報(bào)錯(cuò)no?module?named?torch的幾種原因及解決方案

    Python報(bào)錯(cuò)no?module?named?torch的幾種原因及解決方案

    這篇文章主要給大家介紹了關(guān)于Python報(bào)錯(cuò)no?module?named?torch的幾種原因及解決方案,這是小白時(shí)常犯的錯(cuò),這個(gè)報(bào)錯(cuò)一般說明在你電腦當(dāng)前環(huán)境下沒有安裝torch這個(gè)模塊,但也有其他情況,需要的朋友可以參考下
    2023-10-10
  • PyCharm中代碼字體大小調(diào)整方法

    PyCharm中代碼字體大小調(diào)整方法

    在本篇文章里小編給大家分享了關(guān)于PyCharm中代碼字體大小調(diào)整方法以及相關(guān)知識(shí)點(diǎn),需要的朋友們學(xué)習(xí)下。
    2019-07-07
  • python:解析requests返回的response(json格式)說明

    python:解析requests返回的response(json格式)說明

    這篇文章主要介紹了python:解析requests返回的response(json格式)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來(lái)看看吧
    2020-04-04
  • 基于Python實(shí)現(xiàn)PDF區(qū)域文本提取工具

    基于Python實(shí)現(xiàn)PDF區(qū)域文本提取工具

    這篇文章主要為大家介紹了如何通過Python實(shí)現(xiàn)一個(gè)非常精簡(jiǎn)的圖像化的PDF區(qū)域選擇提取工具,文中示例代碼講解詳細(xì),感興趣的小伙伴可以學(xué)習(xí)一下
    2021-12-12
  • python TCP Socket的粘包和分包的處理詳解

    python TCP Socket的粘包和分包的處理詳解

    這篇文章主要介紹了python TCP Socket的粘包和分包的處理詳解,分享了相關(guān)代碼示例,小編覺得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-02-02
  • Python?實(shí)現(xiàn)一個(gè)全連接的神經(jīng)網(wǎng)絡(luò)

    Python?實(shí)現(xiàn)一個(gè)全連接的神經(jīng)網(wǎng)絡(luò)

    這篇文章主要介紹了Python?實(shí)現(xiàn)一個(gè)全連接的神經(jīng)網(wǎng)絡(luò),文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-06-06
  • 學(xué)Python 3的理由和必要性

    學(xué)Python 3的理由和必要性

    在本篇文章里小編給大家整理的是關(guān)于學(xué)Python 3的理由的優(yōu)勢(shì),有興趣的朋友們跟著學(xué)習(xí)參考下。
    2019-11-11
  • Python使用openpyxl讀寫excel文件的方法

    Python使用openpyxl讀寫excel文件的方法

    本篇文章主要介紹了Python使用openpyxl讀寫excel文件的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06

最新評(píng)論