>>?...Ellipsis在你輸入了三個(gè)點(diǎn)之后,Python 解釋器非但不會(huì)報(bào)錯(cuò),反而還會(huì)返回給你「Ellipsis」這么一個(gè)信息。那么這個(gè)有趣的東西是什..." />
<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 中有趣的 Ellipsis 對(duì)象

          共 5265字,需瀏覽 11分鐘

           ·

          2020-08-04 12:43


          什么是Ellipsis

          在 Python 中你可能有時(shí)候會(huì)看到一個(gè)奇怪的用法,就像是這樣:

          >>>?...
          Ellipsis

          在你輸入了三個(gè)點(diǎn)之后,Python 解釋器非但不會(huì)報(bào)錯(cuò),反而還會(huì)返回給你「Ellipsis」這么一個(gè)信息。那么這個(gè)有趣的東西是什么呢?

          查閱 Python 官方文檔后可以看到,它是一個(gè)**「內(nèi)置常量」**(Built-in Constant)。經(jīng)常用于對(duì)用戶(hù)自定義的容器數(shù)據(jù)類(lèi)型進(jìn)行切片用法的擴(kuò)展。

          這也就意味著它可能是會(huì)作為一個(gè)「小眾且另類(lèi)」的語(yǔ)法糖來(lái)使用,但如果你用于 Python 中的容器數(shù)據(jù)類(lèi)型(比如列表)進(jìn)行切片索引時(shí),可能會(huì)引發(fā)錯(cuò)誤:

          >>>?nums?=?list(range(10))
          >>>?nums
          [0,?1,?2,?3,?4,?5,?6,?7,?8,?9]
          >>>?nums[...]
          Traceback?(most?recent?call?last):
          ??File?"",?line?1,?in?
          TypeError:?list?indices?must?be?integers?or?slices,?not?ellipsis

          除此之外,如果你使用的是 Python 2 的解釋器,那么壓根就不支持 Ellipsis 的用法,從一開(kāi)始輸入時(shí)就報(bào)錯(cuò):

          $?python2
          WARNING:?Python?2.7?is?not?recommended.?
          This?version?is?included?in?macOS?for?compatibility?with?legacy?software.?
          Future?versions?of?macOS?will?not?include?Python?2.7.?
          Instead,?it?is?recommended?that?you?transition?to?using?'python3'?from?within?Terminal.

          Python?2.7.16?(default,?Nov??9?2019,?05:55:08)?
          [GCC?4.2.1?Compatible?Apple?LLVM?11.0.0?(clang-1100.0.32.4)?(-macos10.15-objc-s?on?darwin
          Type?"help",?"copyright",?"credits"?or?"license"?for?more?information.
          >>>?...
          ??File?"",?line?1
          ????...
          ????^
          SyntaxError:?invalid?syntax

          雖然說(shuō)在列表中使用 Ellipsis 會(huì)報(bào)錯(cuò),但是碰到這種情況你會(huì)發(fā)現(xiàn)解釋器返回給你的是這樣的東西:

          >>>?nums?=?[1,2,3]
          >>>?nums
          [1,?2,?3]
          >>>?nums[1]?=?nums
          >>>?nums
          [1,?[...],?3]

          可以看到,這里我們將 nums 中的第二個(gè)元素替換成自身,就會(huì)形成不斷地遞歸嵌套賦值,而解釋器最后直接給出了頭尾兩個(gè)元素之外,其他全部元素都會(huì)被 ... 所囊括在內(nèi)。

          根據(jù) Python 官方的另一處文檔,Ellipsis 本身也不支持任何操作,僅僅只是一個(gè)單例對(duì)象(Singleton)

          誰(shuí)能想到,Guido van Rossum 這么一位被人稱(chēng)為「仁慈的獨(dú)裁者」的 Python 之父采納 Ellipsis 的原因竟然是因?yàn)椋河腥苏J(rèn)為三個(gè)省略號(hào)的寫(xiě)法可愛(ài)。(原文為:「Some folks thought it would be cute to be able to write incomplete code like this」)

          應(yīng)用

          要說(shuō)這個(gè)看起來(lái)「雞肋」的 Ellipsis 類(lèi)型對(duì)象沒(méi)有用,這個(gè)說(shuō)法似乎也不正確。因?yàn)樗鳛橐环N奇怪的語(yǔ)法糖也被應(yīng)用到了某些地方。

          Numpy 中的切片

          雖然官方說(shuō) Ellipsis 主要用于用戶(hù)自定義容器類(lèi)型的切片操作,但是在我搜索了許久之后發(fā)現(xiàn)用 Ellipsis 來(lái)實(shí)現(xiàn)所謂的切片操作的貌似只有 Numpy。

          使用 Python 做數(shù)據(jù)分析、挖掘或機(jī)器學(xué)習(xí)相關(guān)的朋友一定對(duì) Numpy 高性能的科學(xué)計(jì)算庫(kù)并不陌生。在 Numpy 中我們真正的使用 Ellipsis 來(lái)進(jìn)行切片索引:

          >>>?import?numpy?as?np
          >>>?arr?=?np.arange(9).reshape((3,3))
          >>>?arr
          array([[0,?1,?2],
          ???????[3,?4,?5],
          ???????[6,?7,?8]])

          需要注意的是,Ellipsis 主要是對(duì)二維以上的數(shù)組才起作用:

          >>>?arr[...,1:2]
          array([[1],
          ???????[4],
          ???????[7]])
          >>>?arr[2,?...]
          array([6,?7,?8])

          從結(jié)果中我們看到,Ellipsis 三個(gè)省略號(hào)的寫(xiě)法其實(shí)就等價(jià)于 arr[:, 1:2] 冒號(hào)的寫(xiě)法。但是在使用過(guò)程中 Ellipsis 只能出現(xiàn)一次

          >>>?ndarr?=?np.arange(24).reshape((2,3,4))
          >>>?ndarr
          array([[[?0,??1,??2,??3],
          ????????[?4,??5,??6,??7],
          ????????[?8,??9,?10,?11]],

          ???????[[12,?13,?14,?15],
          ????????[16,?17,?18,?19],
          ????????[20,?21,?22,?23]]])
          >>>?ndarr[:,?:,?:]
          array([[[?0,??1,??2,??3],
          ????????[?4,??5,??6,??7],
          ????????[?8,??9,?10,?11]],

          ???????[[12,?13,?14,?15],
          ????????[16,?17,?18,?19],
          ????????[20,?21,?22,?23]]])
          >>>?ndarr[...,?...,?...]
          Traceback?(most?recent?call?last):
          ??File?"",?line?1,?in?
          IndexError:?an?index?can?only?have?a?single?ellipsis?('...')

          Ellipsis 在 Numpy 中出現(xiàn)的意義在于,當(dāng)你的數(shù)組是高維的數(shù)組時(shí),那么可以直接使用它來(lái)作為選取其他維度的等價(jià)寫(xiě)法,以下例子來(lái)源于 Numpy 官方文檔:

          >>>?z?=?np.arange(81).reshape(3,3,3,3)
          >>>?z[1,...,2]?#?等價(jià)于?z[1,?:,:,?2]
          array([[29,?32,?35],
          ???????[38,?41,?44],
          ???????[47,?50,?53]])

          Type Hint 類(lèi)型注解

          自從 PEP 484 之后,Python 解釋器開(kāi)始支持類(lèi)型注解。所謂的類(lèi)型注解無(wú)非就是在 Python 實(shí)際代碼中能像注釋那樣對(duì)當(dāng)中的一些參數(shù)或返回值添加類(lèi)型注釋?zhuān)拖袷沁@樣:

          def?add(x:?int,?y:?int)?->?int:
          ????return?x?+?y

          如果你是有使用過(guò) Java 或者 Go 這類(lèi)對(duì)類(lèi)型注解要求較為嚴(yán)格的編譯型語(yǔ)言,那么相信對(duì)此并不陌生,無(wú)論是變量還是方法,都要寫(xiě)上對(duì)應(yīng)的類(lèi)型以防編譯報(bào)錯(cuò);但即便沒(méi)有接觸過(guò)這類(lèi)編譯型語(yǔ)言也不要緊,將其理解為注釋即可,這樣的注釋是能被編輯器或 IDE 所支持,在你要查看函數(shù)定義或文檔時(shí)會(huì)給予提示。

          但是 Type Hint 僅僅只是一種「協(xié)定」,告訴別人你的方法里參數(shù)是如何、最后返回的是什么僅此而已,無(wú)論是加與不加都不會(huì)影響最終代碼的效果,影響的僅僅只是代碼的可讀性罷了。

          如果你的方法有多個(gè)返回值,我們不可能對(duì)每個(gè)返回值的類(lèi)型都寫(xiě)上注解,因此這時(shí) Ellipsis 對(duì)象就派上了用場(chǎng)。根據(jù)官方文檔給出的說(shuō)明,我們完全可以像這樣來(lái)進(jìn)行類(lèi)型注解:

          from?typing?import?Tuple
          def?get_many_value(
          ????a:int,?b:int,?c:int,?
          ????d:int,?e:int,?f:int
          )
          ?->?Tuple[int,?...]:

          ????return?[a+b,?c+d,?e+f]

          這樣的寫(xiě)法本質(zhì)上就是 *args 的作用,表示同類(lèi)型的可變長(zhǎng)度元組。如果你將 Tuple 換成是 List,那么解釋器會(huì)報(bào)錯(cuò),因?yàn)?*args 在方法中的表現(xiàn)就是元組,那么作為注解的 Ellipsis 也應(yīng)如此。這可能也就說(shuō)明為什么在 Tuple 注解中不報(bào)錯(cuò)了。

          FastAPI 中的必選參數(shù)

          目前正流行開(kāi)來(lái)的高性能 Web 框架 FastAPI 中,也應(yīng)用了 Ellipsis。它用以表示參數(shù)是必填項(xiàng),這在 Swagger 頁(yè)面更能直觀(guān)體現(xiàn)。

          #?pip?install?fastapi
          #?pip?install?uvicorn

          from?fastapi?import?FastAPI,?Query

          app?=?FastAPI()

          @app.get('/greetWithOutEllipsis')
          async?def?greet(name:?str?=?None):
          ????if?name:
          ????????return?{"info":?f"Welcome!?{name}"}
          ????return?{"info":?f"Welcome?to?FastAPI!"}
          ????

          @app.get('/greetWithEllipsis')
          async?def?greet(name:?str?=?Query(...,?min_length=2)):
          ????if?name:
          ????????return?{"info":?f"Welcome!?{name}"}
          ????return?{"info":?f"Welcome?to?FastAPI!"}

          if?__name__?==?"__main__":
          ????import?uvicorn
          ????uvicorn.run(app,?port?=?5000)

          啟動(dòng)服務(wù)之后,在瀏覽器中輸入 http://127.0.0.1:5000/docs 便能進(jìn)入到服務(wù)的 Swagger 頁(yè)面中,在上述例子中如果 name 參數(shù)并非是個(gè)必要的參數(shù)時(shí),在 Swagger 頁(yè)面中不會(huì)看到任何標(biāo)識(shí),即便我們不帶上 name 參數(shù)也能進(jìn)行請(qǐng)求:

          非必要參數(shù)

          但當(dāng)我們加上了一個(gè) Query() 方法,并將其 Ellipsis 對(duì)象丟到當(dāng)中時(shí),不僅會(huì)給參數(shù)加上 required 的標(biāo)識(shí),同時(shí)還對(duì)傳入的字符串長(zhǎng)度進(jìn)行了限制。

          必要參數(shù)

          除了參數(shù)之外,在 FastAPI 中你還可以在請(qǐng)求體、路徑、字段等多個(gè)地方使用 Ellipsis 對(duì)象。

          「?jìng)巍?pass 寫(xiě)法

          Ellipsis 有時(shí)候還可以作為 pass 的一種「?jìng)巍箤?xiě)法,比如這樣:

          def?greet():
          ????...?#等價(jià)于?pass

          這其實(shí)就和 # 注釋符號(hào)與六個(gè)引號(hào)的長(zhǎng)字符串注釋類(lèi)似。但實(shí)際上僅僅只是一種取巧的方法,實(shí)際上我們可以將 ... 替換成任何值或?qū)ο螅?None1True 等,因?yàn)樵诜椒ㄖ胁](méi)有顯示聲明返回的對(duì)象,所以無(wú)論我們寫(xiě)什么最后的效果都是一樣的。

          但使用 Ellipsis 對(duì)象來(lái)作為 pass 關(guān)鍵字的替代品從「視覺(jué)」上來(lái)說(shuō)或許還有點(diǎn)「意猶未盡」的意思。

          當(dāng)然如果在你和同事協(xié)作時(shí),隨手寫(xiě)下這樣一個(gè)省略號(hào),沒(méi)準(zhǔn)隱含著你對(duì)同事 Coding 的無(wú)奈,或者是對(duì)禿頭的憂(yōu)愁(逃)

          作者:100gle,練習(xí)時(shí)長(zhǎng)不到兩年的非正經(jīng)文科生一枚,喜歡敲代碼、寫(xiě)寫(xiě)文章、搗鼓搗鼓各種新事物;現(xiàn)從事有關(guān)大數(shù)據(jù)分析與挖掘的相關(guān)工作。


          贊 賞 作 者



          Python中文社區(qū)作為一個(gè)去中心化的全球技術(shù)社區(qū),以成為全球20萬(wàn)Python中文開(kāi)發(fā)者的精神部落為愿景,目前覆蓋各大主流媒體和協(xié)作平臺(tái),與阿里、騰訊、百度、微軟、亞馬遜、開(kāi)源中國(guó)、CSDN等業(yè)界知名公司和技術(shù)社區(qū)建立了廣泛的聯(lián)系,擁有來(lái)自十多個(gè)國(guó)家和地區(qū)數(shù)萬(wàn)名登記會(huì)員,會(huì)員來(lái)自以工信部、清華大學(xué)、北京大學(xué)、北京郵電大學(xué)、中國(guó)人民銀行、中科院、中金、華為、BAT、谷歌、微軟等為代表的政府機(jī)關(guān)、科研單位、金融機(jī)構(gòu)以及海內(nèi)外知名公司,全平臺(tái)近20萬(wàn)開(kāi)發(fā)者關(guān)注。


          推薦閱讀:
          用 Python 進(jìn)行系統(tǒng)聚類(lèi)分析
          用 Python 對(duì)數(shù)據(jù)進(jìn)行相關(guān)性分析
          如何在 matplotlib 中加注釋和內(nèi)嵌圖
          如何用一行代碼讓 gevent 爬蟲(chóng)提速 100%


          ▼點(diǎn)擊成為社區(qū)會(huì)員? ?喜歡就點(diǎn)個(gè)在看吧

          瀏覽 140
          點(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>
                  豆花在线视频观看 | 影音先锋毛片 | 伊伊色综合 | 夜夜躁日日躁狠狠躁av麻豆 | 欧美成人视频 |