<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python 3.10 的首個(gè) PEP 誕生,內(nèi)置類型 zip() 將迎來(lái)新特性

          共 5729字,需瀏覽 12分鐘

           ·

          2020-08-04 09:52

          點(diǎn)擊上方“Python爬蟲(chóng)與數(shù)據(jù)挖掘”,進(jìn)行關(guān)注

          回復(fù)“書(shū)籍”即可獲贈(zèng)Python從入門到進(jìn)階共10本電子書(shū)

          ?無(wú)邊落木蕭蕭下,不盡長(zhǎng)江滾滾來(lái)。

          譯者前言:相信凡是用過(guò) zip() 內(nèi)置函數(shù)的人,都會(huì)贊同它很有用,但是,它的最大問(wèn)題是可能會(huì)產(chǎn)生出非預(yù)期的結(jié)果。PEP-618 提出給它增加一個(gè)參數(shù),可以有效地解決大家的痛點(diǎn)。

          這是 Python 3.10 版本正式采納的第一個(gè) PEP,「Python貓」一直有跟進(jìn)社區(qū)最新動(dòng)態(tài)的習(xí)慣,所以翻譯了出來(lái)給大家嘗鮮,強(qiáng)烈推薦一讀。(PS:嚴(yán)格來(lái)說(shuō),zip() 是一個(gè)內(nèi)置類(built-in type),而不是一個(gè)內(nèi)置函數(shù)(built-in function),但我們一般都稱它為一個(gè)內(nèi)置函數(shù)。)

          PEP原文:https://www.python.org/dev/peps/pep-0618

          PEP標(biāo)題:Add Optional Length-Checking To zip
          PEP作者:Brandt Bucher
          創(chuàng)建日期:2020-05-01
          合入版本:3.10
          譯者豌豆花下貓?@Python貓公眾號(hào)
          PEP翻譯計(jì)劃https://github.com/chinesehuazhou/peps-cn

          摘要

          本 PEP 建議給內(nèi)置的 zip 添加一個(gè)可選的 strict 布爾關(guān)鍵字參數(shù)。當(dāng)啟用時(shí),如果其中一個(gè)參數(shù)先被用盡了,則會(huì)引發(fā) ValueError 。

          動(dòng)機(jī)

          從作者的個(gè)人經(jīng)驗(yàn)和一份對(duì)標(biāo)準(zhǔn)庫(kù)的調(diào)查 來(lái)看,明顯有很多(如果不是絕大多數(shù))zip 用例要求可迭代對(duì)象必須是等長(zhǎng)的。有時(shí)候,周圍代碼的上下文可以保證這點(diǎn),但是要 zip 處理的數(shù)據(jù)通常是由調(diào)用者傳入的、單獨(dú)提供的或者以某種方式生成的。在這些情況下,zip 的默認(rèn)行為意味著錯(cuò)誤的重構(gòu)或邏輯錯(cuò)誤,很容易悄悄地導(dǎo)致數(shù)據(jù)丟失。這些 bug 不僅難以定位,甚至難以被覺(jué)察到。

          很容易想到造成這種問(wèn)題的簡(jiǎn)單案例。例如,以下代碼在 items 為一個(gè)序列(sequence)時(shí)可以良好地運(yùn)行,但是如果調(diào)用者將 item 重構(gòu)為一個(gè)可消耗的迭代器,則代碼會(huì)悄悄地產(chǎn)生縮短的、不匹配的結(jié)果:

          def?apply_calculations(items):
          ????transformed?=?transform(items)
          ????for?i,?t?in?zip(items,?transformed):
          ????????yield?calculate(i,?t)

          zip 還有幾種常見(jiàn)用法。慣用的技巧性用法特別容易出問(wèn)題,因?yàn)樗鼈兘?jīng)常被不完全了解代碼工作方式的用戶使用。下面是一個(gè)示例,解包到 zip 中以轉(zhuǎn)化成嵌套的可迭代對(duì)象:

          >>>?x?=?[[1,?2,?3],?["one"?"two"?"three"]]
          >>>?xt?=?list(zip(*x))

          另一個(gè)例子是將數(shù)據(jù)“分塊”成大小相等的組:

          >>>?n?=?3
          >>>?x?=?range(n?**?2),
          >>>?xn?=?list(zip(*[iter(x)]?*?n))

          在第一個(gè)例子中,非矩形數(shù)據(jù)通常會(huì)導(dǎo)致邏輯錯(cuò)誤。在第二個(gè)例子中,長(zhǎng)度不是 n 的倍數(shù)的數(shù)據(jù)通常也是錯(cuò)誤。因?yàn)檫@兩個(gè)習(xí)慣用法都會(huì)悄悄地忽略不匹配的尾部元素。

          最有說(shuō)服力的例子來(lái)自使用了 zip 的標(biāo)準(zhǔn)庫(kù)ast ,它在 literal_eval 里產(chǎn)生過(guò)一個(gè) bug,會(huì)直接丟棄不匹配的節(jié)點(diǎn):

          >>>?from?ast?import?Constant,?Dict,?literal_eval
          >>>?nasty_dict?=?Dict(keys=[Constant(None)],?values=[])
          >>>?literal_eval(nasty_dict)??#?Like?eval("{None:?}")
          {}

          實(shí)際上,筆者已經(jīng)在 Python 的標(biāo)準(zhǔn)庫(kù)和工具中找出了許多調(diào)用點(diǎn), 立即在這些位置啟用此新特性是恰當(dāng)?shù)摹?/p>

          基本原理

          一些評(píng)論者聲稱:布爾開(kāi)關(guān)常量是一種“代碼壞氣味(code-smell)”,或者與 Python 的設(shè)計(jì)哲學(xué)背道而馳。

          但是,Python 當(dāng)前在內(nèi)置函數(shù)上有幾個(gè)布爾關(guān)鍵字參數(shù)的用法,它們通常使用編譯期常量來(lái)調(diào)用:
          • compile(…,dont_inherit=True)

          • open(…,closefd=False)

          • print(…,flush=True)

          • sorted(…,reverse=True)

          標(biāo)準(zhǔn)庫(kù)中還有許多類似用法。

          這個(gè)新參數(shù)的想法和名稱最初是由 Ram Rachum 提出的。該議題收到了 100 多個(gè)回復(fù),而候選的“equal”也獲得了相近的支持?jǐn)?shù)。

          筆者對(duì)它們沒(méi)有很強(qiáng)烈的偏好,盡管“equal equals” 讀起來(lái)有點(diǎn)尷尬。它還可能(錯(cuò)誤地)暗示了 zip 的對(duì)象是相等的:

          >>>?z?=?zip([2.0,?4.0,?6.0],?[2,?4,?8],?equal=True)

          規(guī)范

          當(dāng)用關(guān)鍵字參數(shù) strict=True 調(diào)用內(nèi)置類 zip 時(shí),如果參數(shù)的長(zhǎng)度不同,則生成的迭代器會(huì)引發(fā) ValueError。這個(gè)異常就發(fā)生在迭代器正常停止迭代的地方。

          向上兼容

          此項(xiàng)更改是完全向上兼容的。當(dāng)前的 zip 不接受關(guān)鍵字參數(shù),默認(rèn)省略 strict 的“非嚴(yán)格”用法會(huì)保持不變。

          參考實(shí)現(xiàn)

          筆者設(shè)計(jì)了一個(gè) C 實(shí)現(xiàn)。

          用 Python 大致翻譯如下:

          def?zip(*iterables,?strict=False):
          ????if?not?iterables:
          ????????return
          ????iterators?=?tuple(iter(iterable)?for?iterable?in?iterables)
          ????try:
          ????????while?True:
          ????????????items?=?[]
          ????????????for?iterator?in?iterators:
          ????????????????items.append(next(iterator))
          ????????????yield?tuple(items)
          ????except?StopIteration:
          ????????if?not?strict:
          ????????????return
          ????if?items:
          ????????i?=?len(items)
          ????????plural?=?"?"?if?i?==?1?else?"s?1-"
          ????????msg?=?f"zip()?argument?{i+1}?is?shorter?than?argument{plural}{i}"
          ????????raise?ValueError(msg)
          ????sentinel?=?object()
          ????for?i,?iterator?in?enumerate(iterators[1:],?1):
          ????????if?next(iterator,?sentinel)?is?not?sentinel:
          ????????????plural?=?"?"?if?i?==?1?else?"s?1-"
          ????????????msg?=?f"zip()?argument?{i+1}?is?longer?than?argument{plural}{i}"
          ????????????raise?ValueError(msg)

          被拒絕的意見(jiàn)

          (1)添加 itertools.zip_strict

          這是 Python-Ideas 郵件列表上獲得最多支持的替代方案,因此值得在此處加以討論。它沒(méi)有任何嚴(yán)重的缺陷,如果本 PEP 被否絕,它是一個(gè)很好的替代。

          雖然考慮到這一點(diǎn),但是在 zip 中添加可選參數(shù)可以用較小的更改而更好地解決誘發(fā)此 PEP 的問(wèn)題。

          (2)依照先例

          itertools 中有一個(gè) zip_longest,這似乎讓人很有動(dòng)機(jī)再添加一個(gè) zip_strict。但是,zip_longest 在許多方面是一個(gè)更加復(fù)雜且特定的程序:它負(fù)責(zé)填寫缺失的值,但其它函數(shù)都不需要操心這種事。

          如果 zip 和 zip_longest 同時(shí)放在 itertools 中,或者都作為內(nèi)置函數(shù),那么在相同的地方添加 zip_strict 就確實(shí)是一個(gè)更有效的論點(diǎn)。然而,新的“strict”用法在接口和行為方面,相比起 zip_longest,更接近于 zip 的概念,但又不足以成為內(nèi)置對(duì)象??紤]到這個(gè)原因,令 zip 就地?cái)U(kuò)展出一個(gè)新的選項(xiàng),似乎是最自然的選擇。

          (3)易用性

          如果 zip 能夠防止此類 bug,那么用戶在調(diào)用的地方啟動(dòng)檢查,就會(huì)變得非常簡(jiǎn)單。與其編寫一套繁重的邏輯來(lái)處理,不如用這個(gè)新特性來(lái)直接檢查。

          有人還認(rèn)為,在標(biāo)準(zhǔn)庫(kù)中放一個(gè)新的函數(shù),相比在一個(gè)內(nèi)置函數(shù)上加關(guān)鍵字參數(shù),更“容易發(fā)現(xiàn)(discoverable)”。筆者不同意這一論斷。

          (4)維護(hù)成本

          盡管在提升易用性時(shí),具體的實(shí)現(xiàn)是個(gè)次要問(wèn)題,但重要的是要認(rèn)識(shí)到,添加新的程序比修改原有程序復(fù)雜得多。與此 PEP 一起提供的 CPython 實(shí)現(xiàn)非常簡(jiǎn)單,并且對(duì) zip 的默認(rèn)行為沒(méi)有顯著的性能影響,而在 itertools 中添加一個(gè)全新的程序?qū)⑿枰?/p>

          • 復(fù)制 zip 的許多現(xiàn)有邏輯,zip_longest 就是這么干的。? ?

          • 大刀闊斧地重構(gòu) zip 或 zip_longest 或這兩者,以便共享一個(gè)公共的或者繼承性的實(shí)現(xiàn)(這可能會(huì)影響性能)。

          (5)添加多個(gè)“模式”以供切換

          如果預(yù)期有三個(gè)或更多模式(mode),這個(gè)建議才會(huì)比二元標(biāo)志更有意義。最顯而易見(jiàn)的三種模式是:“最短的”(當(dāng)前 zip 的行為),“嚴(yán)格的”(本 PEP 提議的行為)和“最長(zhǎng)的”(itertools.zip_longest 的行為)。

          但是,除了當(dāng)前的默認(rèn)值以及本提案的“strict”模式,似乎不需要再添加其它模式。最可能的是添加一個(gè)“最長(zhǎng)的”模式,但這需要一個(gè)新的 fillvalue 參數(shù)(它對(duì)于前兩種模式都沒(méi)有意義),另外,itertools.zip_longest 已經(jīng)完美地處理了這種模式,若在 zip 中添加該模式,將會(huì)造成重復(fù)。目前尚不清楚哪一個(gè)是“顯而易見(jiàn)的”選擇:內(nèi)置 zip 上的 mode 參數(shù),還是已經(jīng)長(zhǎng)期存在于 itertools 中的 zip_longest。

          (6)給 zip 添加方法或者構(gòu)造函數(shù)

          考慮以下兩個(gè)被提出來(lái)的做法:

          >>>?zm?=?zip(*iters).strict()
          >>>?zd?=?zip.strict(*iters)
          尚不清楚哪個(gè)更好,或者哪個(gè)更差。如果 zip.strict 作為一個(gè)方法來(lái)實(shí)現(xiàn),則 zm 沒(méi)問(wèn)題,但是 zd 會(huì)出現(xiàn)幾種令人困惑的情況:
          • 返回不包裝在元組中的結(jié)果(如果 iters 僅包含一個(gè)元素,一個(gè) zip 迭代器)。
          • 參數(shù)類型錯(cuò)誤時(shí)拋出 TypeError(如果 iters 只包含一個(gè)元素,不是一個(gè) zip 迭代器)。
          • 否則,參數(shù)數(shù)量不對(duì)時(shí)拋出 TypeError。

          如果 zip.strict 是作為 classmethod ?或 staticmethod 實(shí)現(xiàn),則 zd 將成功執(zhí)行,而 zm 將不產(chǎn)生任何結(jié)果(這正是我們最初要避免的問(wèn)題)。

          本提案還面臨著更為復(fù)雜的問(wèn)題,因?yàn)?CPython 中 zip 內(nèi)置類的實(shí)現(xiàn)細(xì)節(jié)是未文檔化的。這意味著若選擇以上的某種行為,當(dāng)前的實(shí)現(xiàn)就會(huì)被“鎖定”(或至少要求對(duì)其進(jìn)行仿真)。

          (7)變更 zip 的默認(rèn)行為

          zip 的默認(rèn)行為沒(méi)有什么“錯(cuò)” ,因?yàn)樵谠S多情況下,這確實(shí)是正確處理大小不等的輸入的方法。例如,在處理無(wú)限迭代器時(shí),它非常有用。

          itertools.zip_longest 已經(jīng)用在仍然需要“額外”尾端數(shù)據(jù)的情況。

          (8)使用回調(diào)來(lái)處理剩余對(duì)象

          盡管基本上可以執(zhí)行用戶需要的任何操作,但此解決方案在處理常見(jiàn)問(wèn)題時(shí)(例如舍棄不匹配的長(zhǎng)度),變得不必要的復(fù)雜且不直觀。

          (9)引發(fā)一個(gè) AssertionError

          沒(méi)有內(nèi)置函數(shù)或內(nèi)置類的 API 會(huì)引發(fā) AssertionError。此外,官方文檔 這么寫的(它的全部):

          Raised when an assert statement fails.

          由于此功能與 Python 的 assert 語(yǔ)句無(wú)關(guān),因此不應(yīng)該引發(fā) AssertionError。用戶若希望在優(yōu)化模式下禁用檢查(像一個(gè) assert 語(yǔ)句),可以改用 strict = __debug__。

          (10)在 map 上添加類似的特性

          本 PEP 不建議對(duì) map 作任何更改,因?yàn)楹苌偈褂脦в卸鄠€(gè)可迭代參數(shù)的map。但是,本 PEP 的裁定可作為將來(lái)討論類似特性的先例(應(yīng)該出現(xiàn))。

          如果本 PEP 被拒絕,則 map 的那種特性實(shí)際上也不值得追求。如果通過(guò)了,則對(duì) map 的更改不需要新的 PEP(盡管像所有提案一樣,都應(yīng)仔細(xì)考慮其有用性)。為了保持一致性,它應(yīng)遵循此處討論的跟 zip 相同的 API 和語(yǔ)義。

          (11)什么也不做

          此建議可能最沒(méi)有吸引力。

          悄悄地將數(shù)據(jù)截?cái)嗍且环N特別令人討厭的 bug,而手寫一個(gè)健壯的解決方案卻并非易事。Python 自己的標(biāo)準(zhǔn)庫(kù)(前文提到的 ast)是有現(xiàn)實(shí)意義的反例,很容易就陷入本 PEP 試圖避免的那種陷阱。

          -------------------?End?-------------------

          往期精彩文章推薦:

          歡迎大家點(diǎn)贊,留言,轉(zhuǎn)發(fā),轉(zhuǎn)載,感謝大家的相伴與支持

          想加入Python學(xué)習(xí)群請(qǐng)?jiān)诤笈_(tái)回復(fù)【入群

          萬(wàn)水千山總是情,點(diǎn)個(gè)【在看】行不行

          /今日留言主題/

          隨便說(shuō)一兩句吧~~

          瀏覽 81
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  欧美成人精品在线观看 | 91AV精品久久 | 内射学生妹在线播放 | 三级网站在线免费 | 午夜精品一区二区三区在线播放 |