国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

Python高級語法之:一篇文章了解yield與Generator生成器

kamushin233 / 3096人閱讀

摘要:與子生成器是開始引入的新特性。我們把這種一個生成器中調(diào)用的另一個生成器叫做子生成器,而這個子生成器由關(guān)鍵字生成。由于子生成器很常用,所以引入了新的語法來簡化這個代碼。下次,會繼續(xù)對之前的結(jié)果進行乘方,直到結(jié)果超過為止。

Python高級語法中,由一個yield關(guān)鍵詞生成的generator生成器,是精髓中的精髓。它雖然比裝飾器、魔法方法更難懂,但是它強大到我們難以想象的地步:小到簡單的for loop循環(huán),大到代替多線程做服務(wù)器的高并發(fā)處理,都可以基于yield來實現(xiàn)。

理解yield:代替return的yield

簡單來說,yield是代替return的另一種方案:

return就像人只有一輩子,一個函數(shù)一旦return,它的生命就結(jié)束了

yield就像有“第二人生”、“第三人生”甚至輪回轉(zhuǎn)世一樣,函數(shù)不但能返回值,“重生”以后還能再接著“上輩子”的記憶繼續(xù)返回值

我的定義:yield在循環(huán)中代替return,每次循環(huán)返回一次值,而不是全部循環(huán)完了才返回值。

yield怎么念?

return我們念“返回xx值”,我建議:yield可以更形象的念為"嘔吐出xx值“,每次嘔一點。

一般我們進行循環(huán)迭代的時候,都必須等待循環(huán)結(jié)束后才return結(jié)果。
數(shù)量小的時候還行,但是如果循環(huán)次數(shù)上百萬?上億?我們要等多久?
如果循環(huán)中不涉及I/O還行,但是如果涉及I/O堵塞,一個堵幾秒,后邊幾百萬個客戶等著呢,銀行柜臺還能不能下班了?

所以這里肯定是要并行處理的。除了傳統(tǒng)的多線程多進程外,我們還可以選擇Generator生成器,也就是由yield代替return,每次循環(huán)都返回值,而不是全部循環(huán)完了才返回結(jié)果。

這樣做的好處就是——極大的節(jié)省了內(nèi)存。如果用return,那么循環(huán)中的所有數(shù)據(jù)都要不斷累計到內(nèi)存里直到循環(huán)結(jié)束,這個不友好。
而yield則是一次一次的返回結(jié)果,就不會在內(nèi)存里累加了。所以數(shù)據(jù)量越大,優(yōu)勢就越明顯。

有多明顯?如果做一百萬的簡單數(shù)字計算,普通的for loop return會增加300MB+的內(nèi)存占用!而用yield一次一次返回,增加的內(nèi)存占用幾乎為0MB!

yield的位置

既然yield不是全部循環(huán)完了再返回,而是循環(huán)中每次都返回,所以位置自然不是在for loop之后,而是在loop之中。

先來看一般的for loop返回:

def square(numbers):
    result = []
    for n in numbers:
        result.append( n**2 )
    return result    #在for之外

再來看看yield怎么做:

def square(numbers):
    for n in numbers:
        yield n**2    #在for之中

可以看到,yield在for loop之中,且函數(shù)完全不需要寫return返回。

這時候如果你print( square([1,2,3]) )得到的就不是直接的結(jié)果,而是一個
如果要使用,就必須一次一次的next(...)來獲取下一個值:

>>> results = square( [1,2,3] )
>>> next( result )
1
>>> next( result )
4
>>> next( result )
9
>>> next( result )
ERROR: StopIteration

這個時候更簡單的做法是:

for r in results:
    print( r )

因為in這個關(guān)鍵詞自動在后臺為我們調(diào)用生成器的next(..)函數(shù)

什么是generator生成器?
只要我們在一個函數(shù)中用了yield關(guān)鍵字,函數(shù)就會返回一個生成器對象,兩者是相輔相成的。有了這個對象后,我們就可以使用一系列的操作來控制這個循環(huán)結(jié)果了,比如next(..)獲取下一個迭代的結(jié)果。

yieldgenerator的關(guān)系,簡單來說就是一個起因一個結(jié)果:只要寫上yield, 其所在的函數(shù)就立馬變成一個對象。

xrange:用生成器實現(xiàn)的range

Python中我們使用range()函數(shù)生成數(shù)列非常常用。而xrange()的使用方法、效果幾乎一模一樣,唯一不同的就是——xrange()返回的是生成器,而不是直接的結(jié)果。
如果數(shù)據(jù)量大時,xrange()能極大的減小內(nèi)存占用,帶來卓越的性能提升。

當(dāng)然,幾百、幾千的數(shù)量級,就直接用range好了。

多重yield

有時候我們可能會在一個函數(shù)中、或者一個for loop中看到多個yield,這有點不太好理解。
但其實很簡單!

一般情況下,我們寫的:

for n in [1,2,3]:
    yield n**2

實際上它的本質(zhì)是生成了這個東西:

yield 1**2
yield 2**2
yield 3**2

也就是說,不用for loop,我們自己手寫一個一個的yield,效果也是一樣的。

你每次調(diào)用一次next(..),就得到一個yield后面的值。然后三個yield的第一個就會被劃掉,剩兩個。再調(diào)用一次,再劃掉一個,就剩一個。直到一個都不剩,next(..)就返回異常。
一旦了解這個本質(zhì),我們就能理解一個函數(shù)里寫多個yield是什么意思了。

更深入理解yield:作為暫停符的yield

從多重yield延伸,我們可以開始更進一步了解yield到底做了些什么了。

現(xiàn)在,我們不把yield看作是return的替代品了,而是把它看作是一個suspense暫停符。
即每次程序遇到y(tǒng)ield,都會暫停。當(dāng)你調(diào)用next(..)時候,它再resume繼續(xù)。

比如我們改一下上面的程序:

def func():
    yield 1**2
    print("Hi, Im A!")

    yield 2**2
    print("Hi, Im B!")

    yield 3**2
    print("Hi, Im C!")

然后我們調(diào)用這個小函數(shù),來看看yield產(chǎn)生的實際效果是什么:

>>> f = func()
>>> f


>>> next( f )
1

>>> next( f )
Hi, Im A!
4

>>> next( f )
Hi, Im B!
9

>>> next( f )
Hi, Im C!
ERROR: StopIteration

從這里我們可以看到:

第一次調(diào)用生成器的時候,yield之后的打印沒有執(zhí)行。因為程序yield這里暫停了

第二次調(diào)用生成器的時候,第一個yield之后的語句執(zhí)行了,并且再次暫停在第二個yield

第三次調(diào)用生成器的時候,卡在了第三個yield。

第四次調(diào)用生成器的時候,最后一個yield以下的內(nèi)容還是執(zhí)行了,但是因為沒有找到第四個yield,所以報錯。

所以到了這里,如果我們能理解yield作為暫停符的作用,就可以非常靈活的用起來了。

yield fromsub-generator子生成器

yield from是Python 3.3開始引入的新特性。
它主要作用就是:當(dāng)我需要在一個生成器函數(shù)中使用另一個生成器時,可以用yield from來簡化語句。

舉例,正常情況下我們可能有這么兩個生成器,第二個調(diào)用第一個:

def gen1():
    yield 11
    yield 22
    yield 33

def gen2():
    for g in gen1():
        yield g
    yield 44
    yield 55
    yield 66

可以看到,我們在gen2()這個生成器中調(diào)用了gen1()的結(jié)果,并把每次獲取到的結(jié)果yield轉(zhuǎn)發(fā)出去,當(dāng)成自己的yield出來的值

我們把這種一個生成器中調(diào)用的另一個生成器叫做sub-generator子生成器,而這個子生成器由yield from關(guān)鍵字生成。

由于sub-generator子生成器很常用,所以Python引入了新的語法來簡化這個代碼:yield from

上面gen2()的代碼可以簡化為:

def gen2():
    yield from gen1()
    yield 44
    yield 55
    yield 66

這樣看起來是不是更"pythonic"了呢?:)

所以只要記住:yield from只是把別人嘔吐出來的值,直接當(dāng)成自己的值嘔吐出去。

遞歸+yield能產(chǎn)生什么?

一般我們只是二選一:要不然遞歸,要不然for循環(huán)中yield。有時候yield就可以解決遞歸的問題,但是有時候光用yield并不能解決,還是要用遞歸。
那么怎么既用到遞歸,又用到y(tǒng)ield生成器呢?

參考:Recursion using yield

def func(n):
    result = n**2
    yield result
    if n < 100:
        yield from func( result )

for x in func(100):
    print( x )

上面代碼的邏輯是:如果n小于100,那么每次調(diào)用next(..)的時候,都得到n的乘方。下次next,會繼續(xù)對之前的結(jié)果進行乘方,直到結(jié)果超過100為止。

我們看到代碼里利用了yield from子生成器。因為yield出的值不是直接由變量來,而是由“另一個”函數(shù)得來了。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/43207.html

相關(guān)文章

  • Python “黑魔法” Generator Coroutines

    摘要:主程序通過喚起子程序并傳入數(shù)據(jù),子程序處理完后,用將自己掛起,并返回主程序,如此交替進行。通過輪詢或是等事件框架,捕獲返回的事件。從消息隊列中取出記錄,恢復(fù)協(xié)程函數(shù)。然而事實上只有直接操縱的協(xié)程函數(shù)才有可能接觸到這個對象。 首發(fā)于 我的博客 轉(zhuǎn)載請注明出處 寫在前面 本文默認讀者對 Python 生成器 有一定的了解,不了解者請移步至生成器 - 廖雪峰的官方網(wǎng)站。 本文基于 Pyth...

    李文鵬 評論0 收藏0
  • [python] 關(guān)于 python高級特性

    摘要:開始本文主要記錄廖大教程中高級特性這一節(jié)的內(nèi)容,并寫下我的一些理解。廖大的教程中是這樣說的函數(shù)是順序執(zhí)行,遇到語句或者最后一行函數(shù)語句就返回。 前言 用 python 差不多半年多了,從去年暑假開始接觸,從開始的懵逼,到寫了一些小爬蟲總算入門之后,許多作業(yè)也是能用 python 就用 python,基本拋棄了 C++。但是還是有些過于急躁了,能夠?qū)懸恍┖喍痰拇a,但是對于 python...

    Pines_Cheng 評論0 收藏0
  • python高級特性

    摘要:常規(guī)的使用來統(tǒng)計一段代碼運行時間的例子輸出結(jié)果總結(jié)其實是一門特別人性化的語言,但凡在工程中經(jīng)常遇到的問題,處理起來比較棘手的模式基本都有對應(yīng)的比較優(yōu)雅的解決方案。 python的高級特性 名詞與翻譯對照表 generator 生成器 iterator 迭代器 collection 集合 pack/unpack 打包/解包 decorator 裝飾器 context manager ...

    yexiaobai 評論0 收藏0
  • 當(dāng)談?wù)摰鲿r,我談些什么?

    摘要:示例代碼如下此示例中可以看出,當(dāng)?shù)鹘K止時,通過拋出異常告知迭代器已耗盡。但如果迭代器所指向的數(shù)據(jù)結(jié)構(gòu)在其存在時發(fā)生了插入或刪除操作,則迭代器將可能失效。與的情形類似,對進行任何插入操作也將損壞迭代器。 花下貓語:之前說過,我對于編程語言跟其它學(xué)科的融合非常感興趣,但我還說漏了一點,就是我對于 Python 跟其它編程語言的對比學(xué)習(xí),也很感興趣。所以,我一直希望能聚集一些有其它語言基...

    王軍 評論0 收藏0

發(fā)表評論

0條評論

kamushin233

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<