成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

[譯]PEP 380--子生成器的語(yǔ)法

fevin / 3373人閱讀

摘要:提議以下的新的生成器語(yǔ)法將被允許在生成器的內(nèi)部使用其中表達(dá)式作用于可迭代對(duì)象,從迭代器中提取元素。子迭代器而非生成器的語(yǔ)義被選擇成為生成器案例的合理泛化。建議如果關(guān)閉一個(gè)子迭代器時(shí),引發(fā)了帶返回值的異常,則將該值從調(diào)用中返回給委托生成器。

導(dǎo)語(yǔ): PEP(Python增強(qiáng)提案)幾乎是 Python 社區(qū)中最重要的文檔,它們提供了公告信息、指導(dǎo)流程、新功能的設(shè)計(jì)及使用說明等內(nèi)容。對(duì)于學(xué)習(xí)者來說,PEP 是非常值得一讀的第一手材料,學(xué)習(xí)中遇到的大部分難題,都能在 PEP 中找到答案或者解決思路。

我翻譯了幾篇 PEP,這么做的目的一方面是為了加強(qiáng)學(xué)習(xí),另一方面也是為了鍛煉自己的英文水平。Python 與 English,都是如此重要。翻譯能將兩者巧妙地結(jié)合起來,真是一舉兩得。

本文介紹了子生成器的語(yǔ)法,即 yield from 語(yǔ)法。其它與生成器相關(guān)的 PEP 有 3 篇,翻譯的結(jié)果附在了本文末尾。若有對(duì)翻譯感興趣的同學(xué),可在 Github 上關(guān)注下我創(chuàng)建的項(xiàng)目 peps-cn


PEP原文 : https://www.python.org/dev/pe...

PEP標(biāo)題: Syntax for Delegating to a Subgenerator

PEP作者: Gregory Ewing

創(chuàng)建日期: 2009-02-13

合入版本: 3.3

譯者 :豌豆花下貓(Python貓 公眾號(hào)作者)

目錄

摘要

PEP接受

動(dòng)機(jī)

提議

StopIteration 的增強(qiáng)

形式語(yǔ)義

基本原理

重構(gòu)原則

結(jié)束方式

作為線程的生成器

語(yǔ)法

優(yōu)化

使用StopIteration來返回值

被拒絕的建議

批評(píng)

可選的提案

附加材料

參考資料

版權(quán)

摘要

為生成器提出了一種新的語(yǔ)法,用于將部分的操作委派給其它的生成器。這使得一部分包含“yield”的代碼段,可以被分離并放置到其它生成器中。與此同時(shí),子生成器會(huì)返回一個(gè)值,交給委派生成器(delegating generator)使用。

當(dāng)一個(gè)生成器再次 yield 被另一個(gè)生成器生成的值時(shí),該語(yǔ)法還創(chuàng)造了一些優(yōu)化的可能。

PEP接受

Guido 于 2011 年 6 月 26 日正式接受本 PEP。

動(dòng)機(jī)

Python 的生成器是一種協(xié)程,但有一個(gè)限制,它只能返回值給直接的調(diào)用者。這意味著包含了 yield 的代碼段不能像其它代碼段一樣,被拆分并放入到多帶帶的函數(shù)中。如果做了這樣的分解,就會(huì)導(dǎo)致被調(diào)用的函數(shù)本身成為一個(gè)生成器,并且必須顯式地迭代這個(gè)生成器,以便重新 yield 它產(chǎn)生的所有值。

如果只關(guān)心生成值的過程,那么可以不費(fèi)勁地使用如下的循環(huán):

for v in g:
    yield v

但是,如果在調(diào)用send()throw()close()的情況下,要使子生成器與調(diào)用者正確地交互,就相當(dāng)困難。如后面所說,必要的代碼非常復(fù)雜,因此想要正確地處理所有特殊情況,將會(huì)非常棘手。

一種新的語(yǔ)法被提出來解決此問題。在最簡(jiǎn)單的用例中,它等同于上面的 for-循環(huán),并且可以處理生成器的所有的行為,同時(shí)還能用簡(jiǎn)單而直接的方式進(jìn)行重構(gòu)。

提議

以下的新的生成器語(yǔ)法將被允許在生成器的內(nèi)部使用:

yield from 

其中 表達(dá)式作用于可迭代對(duì)象,從迭代器中提取元素。該迭代器會(huì)遍歷到耗盡,在此期間,它直接向包含 yield from 表達(dá)式的調(diào)用者生成器(即“委托生成器”)生成和接收值。

此外,當(dāng)該迭代器是一個(gè)生成器時(shí),則此生成器可以執(zhí)行 return 語(yǔ)句返回一個(gè)值,而該值將成為 yield from 表達(dá)式的值。

yield from 表達(dá)式的完整語(yǔ)義可通過生成器協(xié)議來描述如下:

迭代器返回的任何值都直接傳給調(diào)用者。

使用 send() 發(fā)送給委托生成器的任何值都直接傳給迭代器。如果發(fā)送的值是 None,則調(diào)用迭代器的 __next__() 方法。如果發(fā)送的值不是 None,則調(diào)用迭代器的 send() 方法。如果調(diào)用引發(fā)了 StopIteration,則恢復(fù)委托生成器。任何其它異常都會(huì)傳遞給委托生成器。

除 GeneratorExit 以外,任何傳給委托生成器的異常都會(huì)傳給迭代器的 throw() 方法。如果調(diào)用引發(fā) StopIteration,則恢復(fù)委托生成器。任何其它異常都會(huì)傳遞給委托生成器。

如果傳給委托生成器的是 GeneratorExit 異常,或者調(diào)用委托生成器的 close() 方法,則迭代器的 close() 方法會(huì)被調(diào)用(如果有)。如果調(diào)用時(shí)出現(xiàn)異常,則會(huì)傳給委托生成器。否則的話,在委托生成器中拋出 GeneratorExit。

yield from 表達(dá)式的值是迭代器終止時(shí)引發(fā)的 StopIteration 異常的第一個(gè)參數(shù)。

生成器里的 return expr 導(dǎo)致從生成器退出時(shí)引發(fā) StopIteration(expr)。

StopIteration的增強(qiáng)功能

為方便起見,StopIteration 異常被賦予了一個(gè) value 屬性,來保存它的第一個(gè)參數(shù),若無參數(shù),則為 None。

正式的語(yǔ)義

本節(jié)使用 Python 3語(yǔ)法。

1、RESULT = yield from EXPR 語(yǔ)句等同于以下語(yǔ)句:

_i = iter(EXPR)
try:
    _y = next(_i)
except StopIteration as _e:
    _r = _e.value
else:
    while 1:
        try:
            _s = yield _y
        except GeneratorExit as _e:
            try:
                _m = _i.close
            except AttributeError:
                pass
            else:
                _m()
            raise _e
        except BaseException as _e:
            _x = sys.exc_info()
            try:
                _m = _i.throw
            except AttributeError:
                raise _e
            else:
                try:
                    _y = _m(*_x)
                except StopIteration as _e:
                    _r = _e.value
                    break
        else:
            try:
                if _s is None:
                    _y = next(_i)
                else:
                    _y = _i.send(_s)
            except StopIteration as _e:
                _r = _e.value
                break
RESULT = _r

2、在生成器中,return value 語(yǔ)句在語(yǔ)義上等同于 raise StopIteration(value) ,除了一點(diǎn),當(dāng)前返回的生成器中的 except 子句無法捕獲該異常。

3、 StopIteration 異常的行為就像這樣定義:

class StopIteration(Exception):

    def __init__(self, *args):
        if len(args) > 0:
            self.value = args[0]
        else:
            self.value = None
        Exception.__init__(self, *args)
基本原理 重構(gòu)原則

上面提到的大多數(shù)語(yǔ)義,其背后的基本原理源于一種對(duì)生成器代碼進(jìn)行重構(gòu)的愿望。即希望可以將包含一個(gè)或多個(gè) yield 表達(dá)式的代碼段,分離進(jìn)一個(gè)多帶帶的函數(shù)中(使用常規(guī)手段來處理作用域范圍內(nèi)的變量引用,等等),并通過 yield from 表達(dá)式來調(diào)用該函數(shù)。

在合理可行的情況下,這種復(fù)合而成的生成器的行為應(yīng)該跟原始的非分離的生成器完全相同,包括調(diào)用 __next __() 、send()、throw() 和 close() 。

子迭代器(而非生成器)的語(yǔ)義被選擇成為生成器案例的合理泛化(generalization)。

所提出的語(yǔ)義在重構(gòu)方面具有如下限制:

一個(gè)捕獲了 GenetatorExit 卻不重新拋出的代碼塊,不能在完全保留相同行為的情況下被分離出去。

如果將 StopIteration 異常拋進(jìn)了委托生成器中,則分離的生成器的行為跟原始代碼的行為可能會(huì)不同。

由于這些用例幾乎不存在,因此不值得為支持它們而考慮額外的復(fù)雜性。

結(jié)束方式

當(dāng)在 yield from 處掛起時(shí),并且使用 close() 方法顯式地終止委托生成器時(shí),關(guān)于是否要一并終止子迭代器,存在一些爭(zhēng)議。一個(gè)反對(duì)的論據(jù)是,如果在別處存在對(duì)子迭代器的引用,這樣做會(huì)導(dǎo)致過早結(jié)束它。

對(duì)非引用計(jì)數(shù)型的 Python 實(shí)現(xiàn)的考慮,導(dǎo)致了應(yīng)該顯式地結(jié)束的結(jié)論,以便在所有類型的 Python 實(shí)現(xiàn)上,顯式地結(jié)束子迭代器與非重構(gòu)的迭代器,能具有相同的效果。

這里做的假設(shè)是,在大多數(shù)用例中,子迭代器不會(huì)被共享。在子迭代器被共享的稀有情況下,可通過一個(gè)阻塞調(diào)用 throw() 和 close() 的裝飾器來實(shí)現(xiàn),或者使用除 yield from 以外的方法來調(diào)用子迭代器。

作為線程的生成器

使生成器能夠 return 值的動(dòng)機(jī),還考慮到使用生成器來實(shí)現(xiàn)輕量級(jí)的線程。當(dāng)以這種方式使用生成器時(shí),將輕量級(jí)線程的計(jì)算擴(kuò)散到許多函數(shù)上就會(huì)是合理的。人們希望能夠像調(diào)用普通函數(shù)一樣調(diào)用子生成器,傳遞給它參數(shù)并接收返回值。

使用提議的語(yǔ)法,像以下的表達(dá)式

y = f(x)

其中 f 是一個(gè)普通的函數(shù),就可以被轉(zhuǎn)化成一個(gè)委托調(diào)用

y = yield from g(x)

其中 g 是生成器。通過把 g 想象成一個(gè)普通的能被 yield 語(yǔ)句掛起的函數(shù),人們可以推斷出結(jié)果代碼的行為。

當(dāng)以這種方式把生成器作為線程使用時(shí),通常人們不會(huì)對(duì) yield 所傳入或傳出的值感興趣。但是,也有一些例子,線程可以作為 item 的生產(chǎn)者或消費(fèi)者。yield from 表達(dá)式允許線程的邏輯被擴(kuò)散到所需的盡可能多的函數(shù)中,item 的生產(chǎn)與消費(fèi)發(fā)生在任意的子函數(shù)中,并且這些 item 會(huì)自動(dòng)路由到/去它們的最終來源/目的地。

對(duì)于 throw()close() ,可以合理地預(yù)期,如果從外部向線程內(nèi)拋入了一個(gè)異常,那么首先應(yīng)該在線程掛起處的最內(nèi)部的生成器中引發(fā),再?gòu)哪抢锵蛲鈧鬟f;而如果線程是從外部調(diào)用 close() 來終結(jié)的,那也應(yīng)該從最內(nèi)部往外地終止處于活動(dòng)態(tài)的生成器鏈。

語(yǔ)法

所提出的特定語(yǔ)法被選中,像它的含義所暗示,并沒有引入任何新的關(guān)鍵詞,且清晰地突出了它與普通 yield 的不同。

優(yōu)化

當(dāng)存在一長(zhǎng)串生成器時(shí),使用專門的語(yǔ)法就為優(yōu)化提供了可能性。這種生成器鏈可能存在,例如,當(dāng)遞歸遍歷樹結(jié)構(gòu)時(shí)。在鏈上傳遞 __next__() 的調(diào)用與 yield 返回值,可能造成 O(n) 開銷,最壞情況下會(huì)是 O(n**2)。

可能的策略是向生成器對(duì)象添加一個(gè)槽(slot)來保存委派給它的生成器。當(dāng)在生成器上調(diào)用 __next__() 或 send() 時(shí),首先檢查該槽,如果非空,則它引用的生成器將會(huì)被激活。如果引發(fā)了 StopIteration,該槽會(huì)被清空,并且主生成器會(huì)被激活。

這將減少一系列 C 函數(shù)調(diào)用的委托開銷,并不涉及 Python 代碼的執(zhí)行。一種可能的增強(qiáng)方法是在循環(huán)中遍歷整個(gè)生成器鏈,并直接激活最后一個(gè)生成器,盡管 StopIteration 的處理會(huì)比較復(fù)雜。

使用StopIteration來返回值

有多種方法可以將生成器的返回值傳回。也有一些替代的方法,例如將其存儲(chǔ)為生成器-迭代器對(duì)象的屬性,或?qū)⑵渥鳛樽由善鞯?close() 方法的調(diào)用值返回。然而,本 PEP 提議的機(jī)制很有吸引力,有如下理由:

使用泛化的 StopIteration 異常,可以使其它類型的迭代器輕松地加入?yún)f(xié)議,而不必增加額外的屬性或 close() 方法。

它簡(jiǎn)化了實(shí)現(xiàn),因?yàn)樽由善鞯姆祷刂底兊每捎玫狞c(diǎn)與引發(fā)異常的點(diǎn)相同。延遲到任意時(shí)間都需要在某處存儲(chǔ)返回值。

被拒絕的建議

一些想法被討論并且拒絕了。

建議:應(yīng)該有一些方法可以避免對(duì)__next__() 的調(diào)用,或者用帶有指定值的 send() 調(diào)用來替換它,目的是支持對(duì)生成器作裝飾,以便可以自動(dòng)地執(zhí)行初始的 __next__() 。

決議:超出本提案的范圍。這種生成器不該與 yield from 一起使用。

建議:如果關(guān)閉一個(gè)子迭代器時(shí),引發(fā)了帶返回值的 StopIteration 異常,則將該值從 close() 調(diào)用中返回給委托生成器。

此功能的動(dòng)機(jī)是為了通過關(guān)閉生成器,傳信號(hào)給傳入生成器的最后的值。被關(guān)閉的生成器會(huì)捕獲 GeneratorExit ,完成其計(jì)算并返回一個(gè)結(jié)果,該結(jié)果最終成為 close() 調(diào)用的返回值。

決議:close() 與 GeneratorExit 的這種用法,將與當(dāng)前的退出(bail-out)與清理機(jī)制的角色不兼容。這要求在關(guān)閉子生成器后、關(guān)閉一個(gè)委托生成器時(shí),該委托生成器可以被恢復(fù),而不是重新引發(fā) GeneratorExit。但這是不可接受的,因?yàn)檎{(diào)用 close() 進(jìn)行清理的意圖,無法保證委托生成器能正確地終止。

通過其它方式,可以更好地處理向消費(fèi)者告知(signal)最后的值的問題,例如發(fā)送一個(gè)哨兵值(sentinel value)或者拋入一個(gè)被生產(chǎn)者與消費(fèi)者都認(rèn)可的異常。然后,消費(fèi)者可以檢查該哨兵或異常,通過完成其計(jì)算并正常地返回,來作響應(yīng)。這種方案在存在委托的情況下表現(xiàn)正確。

建議:如果 close() 不返回值,如果出現(xiàn) StopIteration 中帶有非 None 的值,則拋出一個(gè)異常。

決議:沒有明確的理由如此做。忽略返回值在 Python 中的任何其它地方,都不會(huì)被視為錯(cuò)誤。

批評(píng)

根據(jù)本提案,yield from 表達(dá)式的值將以跟普通 yield 表達(dá)式非常不同的方式得出。這意味著其它不包含 yield 表達(dá)式的語(yǔ)法可能會(huì)更合適,但到目前為止,還沒有提出可接受的替代方案。被拒絕的替代品包括 call、delegate 和 gcall。

有人提議,應(yīng)該使用子生成器中除 return 以外的某些機(jī)制,來處理 yield from 表達(dá)式的返回值。但是,這會(huì)干擾將子生成器視為可掛起函數(shù)的目的,因?yàn)樗荒芟衿渌瘮?shù)一樣 return 值。

有人批評(píng),說使用異常來傳遞返回值是“濫用異常”,卻沒有任何具體的理由來證明它。無論如何,這只是一種實(shí)現(xiàn)的建議;其它機(jī)制可以在不丟失本提案的任何關(guān)鍵特性的情況下使用。

有人建議,使用與 StopIteration 不同的異常來返回值,例如 GeneratorReturn。但是,還沒有令人信服的實(shí)際理由被提出,并且向 StopIteration 添加 value 屬性減輕了從異常(該異常可能存在也可能不存在)中提取返回值的所有困難。此外,使用不同的異常意味著,與普通函數(shù)不同,生成器中不帶值的 return,將不等同于 return None

可選的提案

之前已經(jīng)提到了類似的提議,有些語(yǔ)法使用 yield 而不是 yield from。雖然 yield 更簡(jiǎn)潔,但是有爭(zhēng)議的是,它看起來與普通的 yield 太相似了,可能在閱讀代碼時(shí)會(huì)忽視了其中的差異。

據(jù)作者所知,之前的提案只關(guān)注于 yield 產(chǎn)生值,因此遭受到了批評(píng),即他們所替代的兩行 for 循環(huán)并沒有足夠令人厭煩,不足以讓人為新的語(yǔ)法辯護(hù)。通過處理完整的生成器協(xié)議,本提案提供了更多的好處。

附加材料

本提案的語(yǔ)法的一些用例已經(jīng)被提供出來,并且基于上面概括的第一個(gè)優(yōu)化的原型也已實(shí)現(xiàn)。

Examples and Implementation

可以從跟蹤器問題的 issue 11682 中獲得針對(duì) Python 3.3 實(shí)現(xiàn)的升級(jí)版本。

參考資料

[1] https://mail.python.org/pipermail/python-dev/2011-June/112010.html

[2] http://www.cosc.canterbury.ac.nz/greg.ewing/python/yield-from/

[3] http://bugs.python.org/issue11682

版權(quán)

本文檔已經(jīng)放置在公共領(lǐng)域。源文檔:

https://github.com/python/pep...

-------------(譯文完)-------------

相關(guān)鏈接:

PEP背景知識(shí) :學(xué)習(xí)Python,怎能不懂點(diǎn)PEP呢?

PEP翻譯計(jì)劃 :https://github.com/chinesehua...

[[譯] PEP 255--簡(jiǎn)單的生成器](https://mp.weixin.qq.com/s/vj...

[[譯] PEP 342--增強(qiáng)型生成器:協(xié)程](https://mp.weixin.qq.com/s/M7...

[[譯] PEP 525--異步生成器](https://mp.weixin.qq.com/s/fy...


公眾號(hào)【Python貓】, 專注Python技術(shù)、數(shù)據(jù)科學(xué)和深度學(xué)習(xí),力圖創(chuàng)造一個(gè)有趣又有用的學(xué)習(xí)分享平臺(tái)。本號(hào)連載優(yōu)質(zhì)的系列文章,有喵星哲學(xué)貓系列、Python進(jìn)階系列、好書推薦系列、優(yōu)質(zhì)英文推薦與翻譯等等,歡迎關(guān)注哦。PS:后臺(tái)回復(fù)“愛學(xué)習(xí)”,免費(fèi)獲得一份學(xué)習(xí)大禮包。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/43194.html

相關(guān)文章

  • []PEP 342--增強(qiáng)型成器:協(xié)程

    摘要:新語(yǔ)法表達(dá)式語(yǔ)句可以被用在賦值表達(dá)式的右側(cè)在這種情況下,它就是表達(dá)式。表達(dá)式必須始終用括號(hào)括起來,除非它是作為頂級(jí)表達(dá)式而出現(xiàn)在賦值表達(dá)式的右側(cè)。 showImg(https://segmentfault.com/img/bVbnQsb?w=4344&h=2418);PEP原文 : https://www.python.org/dev/pe... PEP標(biāo)題: Coroutines v...

    Cheng_Gang 評(píng)論0 收藏0
  • 異步等待 Python 協(xié)程

    摘要:輔之以事件循環(huán),協(xié)程可用于異步處理,尤其是在中。當(dāng)前支持的協(xié)程基于增強(qiáng)型生成器,于版本開始采用。新的特性中,異步還有兩種新用途異步內(nèi)容管理器和迭代器。 現(xiàn)在 Python 已經(jīng)支持用協(xié)程進(jìn)行異步處理。但最近有建議稱添加協(xié)程以全面完善 Python 的語(yǔ)言結(jié)構(gòu),而不是像現(xiàn)在這樣把他們作為生成器的一個(gè)類型。此外,兩個(gè)新的關(guān)鍵字———異步(async)和等待(await),都該添加到 Pyt...

    NicolasHe 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<