新聞中心
6. 表達(dá)式
本章將解釋 python 中組成表達(dá)式的各種元素的的含義。

邵東網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)建站!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站開(kāi)發(fā)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)建站自2013年創(chuàng)立以來(lái)到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專(zhuān)注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)建站。
語(yǔ)法注釋: 在本章和后續(xù)章節(jié)中,會(huì)使用擴(kuò)展 BNF 標(biāo)注來(lái)描述語(yǔ)法而不是詞法分析。 當(dāng)(某種替代的)語(yǔ)法規(guī)則具有如下形式
- name ::=
othername
并且沒(méi)有給出語(yǔ)義,則這種形式的 name 在語(yǔ)法上與 othername 相同。
6.1. 算術(shù)轉(zhuǎn)換
當(dāng)對(duì)下述某個(gè)算術(shù)運(yùn)算符的描述中使用了“數(shù)值參數(shù)被轉(zhuǎn)換為普通類(lèi)型”這樣的說(shuō)法,這意味著內(nèi)置類(lèi)型的運(yùn)算符實(shí)現(xiàn)采用了如下運(yùn)作方式:
如果任一參數(shù)為復(fù)數(shù),另一參數(shù)會(huì)被轉(zhuǎn)換為復(fù)數(shù);
否則,如果任一參數(shù)為浮點(diǎn)數(shù),另一參數(shù)會(huì)被轉(zhuǎn)換為浮點(diǎn)數(shù);
否則,兩者應(yīng)該都為整數(shù),不需要進(jìn)行轉(zhuǎn)換。
某些附加規(guī)則會(huì)作用于特定運(yùn)算符(例如,字符串作為 ‘%’ 運(yùn)算符的左運(yùn)算參數(shù))。 擴(kuò)展必須定義它們自己的轉(zhuǎn)換行為。
6.2. 原子
“原子”指表達(dá)式的最基本構(gòu)成元素。 最簡(jiǎn)單的原子是標(biāo)識(shí)符和字面值。 以圓括號(hào)、方括號(hào)或花括號(hào)包括的形式在語(yǔ)法上也被歸類(lèi)為原子。 原子的句法為:
- atom ::= identifier | literal | enclosure
- enclosure ::= parenth_form | list_display | dict_display | set_display
- | generator_expression | yield_atom
6.2.1. 標(biāo)識(shí)符(名稱(chēng))
作為原子出現(xiàn)的標(biāo)識(shí)符叫做名稱(chēng)。 請(qǐng)參看 標(biāo)識(shí)符和關(guān)鍵字 一節(jié)了解其詞法定義,以及 命名與綁定 獲取有關(guān)命名與綁定的文檔。
當(dāng)名稱(chēng)被綁定到一個(gè)對(duì)象時(shí),對(duì)該原子求值將返回相應(yīng)對(duì)象。 當(dāng)名稱(chēng)未被綁定時(shí),嘗試對(duì)其求值將引發(fā) NameError 異常。
私有名稱(chēng)轉(zhuǎn)換: 當(dāng)以文本形式出現(xiàn)在類(lèi)定義中的一個(gè)標(biāo)識(shí)符以?xún)蓚€(gè)或更多下劃線開(kāi)頭并且不以?xún)蓚€(gè)或更多下劃線結(jié)尾,它會(huì)被視為該類(lèi)的 私有名稱(chēng)。 私有名稱(chēng)會(huì)在為其生成代碼之前被轉(zhuǎn)換為一種更長(zhǎng)的形式。 轉(zhuǎn)換時(shí)會(huì)插入類(lèi)名,移除打頭的下劃線再在名稱(chēng)前增加一個(gè)下劃線。 例如,出現(xiàn)在一個(gè)名為 Ham 的類(lèi)中的標(biāo)識(shí)符 __spam 會(huì)被轉(zhuǎn)換為 _Ham__spam。 這種轉(zhuǎn)換獨(dú)立于標(biāo)識(shí)符所使用的相關(guān)句法。 如果轉(zhuǎn)換后的名稱(chēng)太長(zhǎng)(超過(guò) 255 個(gè)字符),可能發(fā)生由具體實(shí)現(xiàn)定義的截?cái)唷?如果類(lèi)名僅由下劃線組成,則不會(huì)進(jìn)行轉(zhuǎn)換。
6.2.2. 字面值
Python 支持字符串和字節(jié)串字面值,以及幾種數(shù)字字面值:
- literal ::= stringliteral | bytesliteral
- | integer | floatnumber | imagnumber
對(duì)字面值求值將返回一個(gè)該值所對(duì)應(yīng)類(lèi)型的對(duì)象(字符串、字節(jié)串、整數(shù)、浮點(diǎn)數(shù)、復(fù)數(shù))。 對(duì)于浮點(diǎn)數(shù)和虛數(shù)(復(fù)數(shù))的情況,該值可能為近似值。 詳情參見(jiàn) 字面值。
所有字面值都對(duì)應(yīng)于不可變數(shù)據(jù)類(lèi)型,因此對(duì)象標(biāo)識(shí)的重要性不如其實(shí)際值。 多次對(duì)具有相同值的字面值求值(不論是發(fā)生在程序文本的相同位置還是不同位置)可能得到相同對(duì)象或是具有相同值的不同對(duì)象。
6.2.3. 帶圓括號(hào)的形式
帶圓括號(hào)的形式是包含在圓括號(hào)中的可選表達(dá)式列表。
- parenth_form ::= "(" [starred_expression] ")"
帶圓括號(hào)的表達(dá)式列表將返回該表達(dá)式列表所產(chǎn)生的任何東西:如果該列表包含至少一個(gè)逗號(hào),它會(huì)產(chǎn)生一個(gè)元組;否則,它會(huì)產(chǎn)生該表達(dá)式列表所對(duì)應(yīng)的單一表達(dá)式。
一對(duì)內(nèi)容為空的圓括號(hào)將產(chǎn)生一個(gè)空的元組對(duì)象。 由于元組是不可變對(duì)象,因此適用與字面值相同的規(guī)則(即兩次出現(xiàn)的空元組產(chǎn)生的對(duì)象可能相同也可能不同)。
Note that tuples are not formed by the parentheses, but rather by use of the comma. The exception is the empty tuple, for which parentheses are required —- allowing unparenthesized “nothing” in expressions would cause ambiguities and allow common typos to pass uncaught.
6.2.4. 列表、集合與字典的顯示
為了構(gòu)建列表、集合或字典,Python 提供了名為“顯示”的特殊句法,每個(gè)類(lèi)型各有兩種形式:
第一種是顯式地列出容器內(nèi)容
第二種是通過(guò)一組循環(huán)和篩選指令計(jì)算出來(lái),稱(chēng)為 推導(dǎo)式。
推導(dǎo)式的常用句法元素為:
- comprehension ::= assignment_expression comp_for
- comp_for ::= ["async"] "for" target_list "in" or_test [comp_iter]
- comp_iter ::= comp_for | comp_if
- comp_if ::= "if" or_test [comp_iter]
推導(dǎo)式的結(jié)構(gòu)是一個(gè)單獨(dú)表達(dá)式后面加至少一個(gè) for 子句以及零個(gè)或更多個(gè) for 或 if 子句。 在這種情況下,新容器的元素產(chǎn)生方式是將每個(gè) for 或 if 子句視為一個(gè)代碼塊,按從左至右的順序嵌套,然后每次到達(dá)最內(nèi)層代碼塊時(shí)就對(duì)表達(dá)式進(jìn)行求值以產(chǎn)生一個(gè)元素。
不過(guò),除了最左邊 for 子句中的可迭代表達(dá)式,推導(dǎo)式是在另一個(gè)隱式嵌套的作用域內(nèi)執(zhí)行的。 這能確保賦給目標(biāo)列表的名稱(chēng)不會(huì)“泄露”到外層的作用域。
最左邊的 for 子句中的可迭代對(duì)象表達(dá)式會(huì)直接在外層作用域中被求值,然后作為一個(gè)參數(shù)被傳給隱式嵌套的作用域。 后續(xù)的 for 子句以及最左側(cè) for 子句中的任何篩選條件不能在外層作用域中被求值,因?yàn)樗鼈兛赡芤蕾?lài)于從最左側(cè)可迭代對(duì)象中獲得的值。 例如: [x*y for x in range(10) for y in range(x, x+10)]。
為了確保推導(dǎo)式得出的結(jié)果總是一個(gè)類(lèi)型正確的容器,在隱式嵌套作用域內(nèi)禁止使用 yield 和 yield from 表達(dá)式。
Since Python 3.6, in an async def function, an async for clause may be used to iterate over a asynchronous iterator. A comprehension in an async def function may consist of either a for or async for clause following the leading expression, may contain additional for or async for clauses, and may also use await expressions. If a comprehension contains either async for clauses or await expressions or other asynchronous comprehensions it is called an asynchronous comprehension. An asynchronous comprehension may suspend the execution of the coroutine function in which it appears. See also PEP 530.
3.6 新版功能: 引入了異步推導(dǎo)式。
在 3.8 版更改: yield 和 yield from 在隱式嵌套的作用域中已被禁用。
在 3.11 版更改: Asynchronous comprehensions are now allowed inside comprehensions in asynchronous functions. Outer comprehensions implicitly become asynchronous.
6.2.5. 列表顯示
列表顯示是一個(gè)用方括號(hào)括起來(lái)的可能為空的表達(dá)式系列:
- list_display ::= "[" [starred_list | comprehension] "]"
列表顯示會(huì)產(chǎn)生一個(gè)新的列表對(duì)象,其內(nèi)容通過(guò)一系列表達(dá)式或一個(gè)推導(dǎo)式來(lái)指定。 當(dāng)提供由逗號(hào)分隔的一系列表達(dá)式時(shí),其元素會(huì)從左至右被求值并按此順序放入列表對(duì)象。 當(dāng)提供一個(gè)推導(dǎo)式時(shí),列表會(huì)根據(jù)推導(dǎo)式所產(chǎn)生的結(jié)果元素進(jìn)行構(gòu)建。
6.2.6. 集合顯示
集合顯示是用花括號(hào)標(biāo)明的,與字典顯示的區(qū)別在于沒(méi)有冒號(hào)分隔的鍵和值:
- set_display ::= "{" (starred_list | comprehension) "}"
集合顯示會(huì)產(chǎn)生一個(gè)新的可變集合對(duì)象,其內(nèi)容通過(guò)一系列表達(dá)式或一個(gè)推導(dǎo)式來(lái)指定。 當(dāng)提供由逗號(hào)分隔的一系列表達(dá)式時(shí),其元素會(huì)從左至右被求值并加入到集合對(duì)象。 當(dāng)提供一個(gè)推導(dǎo)式時(shí),集合會(huì)根據(jù)推導(dǎo)式所產(chǎn)生的結(jié)果元素進(jìn)行構(gòu)建。
空集合不能用 {} 來(lái)構(gòu)建;該字面值所構(gòu)建的是一個(gè)空字典。
6.2.7. 字典顯示
字典顯示是一個(gè)用花括號(hào)括起來(lái)的可能為空的鍵/數(shù)據(jù)對(duì)系列:
- dict_display ::= "{" [key_datum_list | dict_comprehension] "}"
- key_datum_list ::= key_datum ("," key_datum)* [","]
- key_datum ::= expression ":" expression | "**" or_expr
- dict_comprehension ::= expression ":" expression comp_for
字典顯示會(huì)產(chǎn)生一個(gè)新的字典對(duì)象。
如果給出一個(gè)由逗號(hào)分隔的鍵/數(shù)據(jù)對(duì)序列,它們會(huì)從左至右被求值以定義字典的條目:每個(gè)鍵對(duì)象會(huì)被用作在字典中存放相應(yīng)數(shù)據(jù)的鍵。 這意味著你可以在鍵/數(shù)據(jù)對(duì)序列中多次指定相同的鍵,最終字典的值將由最后一次給出的鍵決定。
雙星號(hào) ** 表示 字典拆包。 它的操作數(shù)必須是一個(gè) mapping。 每個(gè)映射項(xiàng)被會(huì)加入新的字典。 后續(xù)的值會(huì)替代先前的鍵/數(shù)據(jù)對(duì)和先前的字典拆包所設(shè)置的值。
3.5 新版功能: 拆包到字典顯示,最初由 PEP 448 提出。
字典推導(dǎo)式與列表和集合推導(dǎo)式有所不同,它需要以冒號(hào)分隔的兩個(gè)表達(dá)式,后面帶上標(biāo)準(zhǔn)的 “for” 和 “if” 子句。 當(dāng)推導(dǎo)式被執(zhí)行時(shí),作為結(jié)果的鍵和值元素會(huì)按它們的產(chǎn)生順序被加入新的字典。
對(duì)鍵取值類(lèi)型的限制已列在之前的 標(biāo)準(zhǔn)類(lèi)型層級(jí)結(jié)構(gòu) 一節(jié)中。 (總的說(shuō)來(lái),鍵的類(lèi)型應(yīng)該為 hashable,這就把所有可變對(duì)象都排除在外。) 重復(fù)鍵之間的沖突不會(huì)被檢測(cè);指定鍵所保存的最后一個(gè)數(shù)據(jù) (即在顯示中排最右邊的文本) 為最終有效數(shù)據(jù)。
在 3.8 版更改: 在 Python 3.8 之前的字典推導(dǎo)式中,并沒(méi)有定義好鍵和值的求值順序。 在 CPython 中,值會(huì)先于鍵被求值。 根據(jù) PEP 572 的提議,從 3.8 開(kāi)始,鍵會(huì)先于值被求值。
6.2.8. 生成器表達(dá)式
生成器表達(dá)式是用圓括號(hào)括起來(lái)的緊湊形式生成器標(biāo)注。
- generator_expression ::= "(" expression comp_for ")"
生成器表達(dá)式會(huì)產(chǎn)生一個(gè)新的生成器對(duì)象。 其句法與推導(dǎo)式相同,區(qū)別在于它是用圓括號(hào)而不是用方括號(hào)或花括號(hào)括起來(lái)的。
在生成器表達(dá)式中使用的變量會(huì)在為生成器對(duì)象調(diào)用 __next__() 方法的時(shí)候以惰性方式被求值(即與普通生成器相同的方式)。 但是,最左側(cè) for 子句內(nèi)的可迭代對(duì)象是會(huì)被立即求值的,因此它所造成的錯(cuò)誤會(huì)在生成器表達(dá)式被定義時(shí)被檢測(cè)到,而不是在獲取第一個(gè)值時(shí)才出錯(cuò)。 后續(xù)的 for 子句以及最左側(cè) for 子句內(nèi)的任何篩選條件無(wú)法在外層作用域內(nèi)被求值,因?yàn)樗鼈兛赡軙?huì)依賴(lài)于從最左側(cè)可迭代對(duì)象獲取的值。 例如: (x*y for x in range(10) for y in range(x, x+10)).
圓括號(hào)在只附帶一個(gè)參數(shù)的調(diào)用中可以被省略。 詳情參見(jiàn) 調(diào)用 一節(jié)。
為了避免干擾到生成器表達(dá)式本身的預(yù)期操作,禁止在隱式定義的生成器中使用 yield 和 yield from 表達(dá)式。
如果生成器表達(dá)式包含 async for 子句或 await 表達(dá)式,則稱(chēng)為 異步生成器表達(dá)式。 異步生成器表達(dá)式會(huì)返回一個(gè)新的異步生成器對(duì)象,此對(duì)象屬于異步迭代器 (參見(jiàn) 異步迭代器)。
3.6 新版功能: 引入了異步生成器表達(dá)式。
在 3.7 版更改: 在 Python 3.7 之前,異步生成器表達(dá)式只能在 async def 協(xié)和中出現(xiàn)。 從 3.7 開(kāi)始,任何函數(shù)都可以使用異步生成器表達(dá)式。
在 3.8 版更改: yield 和 yield from 在隱式嵌套的作用域中已被禁用。
6.2.9. yield 表達(dá)式
- yield_atom ::= "(" yield_expression ")"
- yield_expression ::= "yield" [expression_list | "from" expression]
yield 表達(dá)式在定義 generator 函數(shù)或 asynchronous generator 函數(shù)時(shí)才會(huì)用到因此只能在函數(shù)定義的內(nèi)部使用。 在一個(gè)函數(shù)體內(nèi)使用 yield 表達(dá)式會(huì)使這個(gè)函數(shù)變成一個(gè)生成器函數(shù),而在一個(gè) async def 函數(shù)的內(nèi)部使用它則會(huì)讓這個(gè)協(xié)程函數(shù)變成一個(gè)異步生成器函數(shù)。 例如:
def gen(): # defines a generator functionyield 123async def agen(): # defines an asynchronous generator functionyield 123
由于它們會(huì)對(duì)外層作用域造成附帶影響,yield 表達(dá)式不被允許作為用于實(shí)現(xiàn)推導(dǎo)式和生成器表達(dá)式的隱式定義作用域的一部分。
在 3.8 版更改: 禁止在實(shí)現(xiàn)推導(dǎo)式和生成器表達(dá)式的隱式嵌套作用域中使用 yield 表達(dá)式。
下面是對(duì)生成器函數(shù)的描述,異步生成器函數(shù)會(huì)在 異步生成器函數(shù) 一節(jié)中單獨(dú)介紹。
當(dāng)一個(gè)生成器函數(shù)被調(diào)用時(shí),它返回一個(gè)名為生成器的迭代器。 然后這個(gè)生成器將控制生成器函數(shù)的執(zhí)行。 執(zhí)行過(guò)程會(huì)在這個(gè)生成器的某個(gè)方法被調(diào)用時(shí)開(kāi)始。 這時(shí),函數(shù)會(huì)執(zhí)行到第一個(gè) yield 表達(dá)式,在這里它將再次被掛起,向生成器的調(diào)用方返回 expression_list 的值。 我們所謂的掛起,就是說(shuō)所有局部狀態(tài)都會(huì)被保留下來(lái),包括局部變量的當(dāng)前綁定、指令指針、內(nèi)部求值棧和任何異常處理等等。 當(dāng)通過(guò)調(diào)用生成器的某個(gè)方法恢復(fù)執(zhí)行時(shí),這個(gè)函數(shù)的運(yùn)行就與 yield 表達(dá)式只是一個(gè)外部調(diào)用的情況完全一樣。 恢復(fù)之后 yield 表達(dá)式的值取決于恢復(fù)執(zhí)行所調(diào)用的方法。 如果是用 __next__() (通常是通過(guò) for 或 next() 內(nèi)置函數(shù)) 則結(jié)果為 None。 否則,如果是用 send(),則結(jié)果將為傳給該方法的值。
所有這些使生成器函數(shù)與協(xié)程非常相似;它們 yield 多次,它們具有多個(gè)入口點(diǎn),并且它們的執(zhí)行可以被掛起。唯一的區(qū)別是生成器函數(shù)不能控制在它在 yield 后交給哪里繼續(xù)執(zhí)行;控制權(quán)總是轉(zhuǎn)移到生成器的調(diào)用者。
在 try 結(jié)構(gòu)中的任何位置都允許yield表達(dá)式。如果生成器在(因?yàn)橐糜?jì)數(shù)到零或是因?yàn)楸焕厥?銷(xiāo)毀之前沒(méi)有恢復(fù)執(zhí)行,將調(diào)用生成器-迭代器的 close() 方法. close 方法允許任何掛起的 finally 子句執(zhí)行。
當(dāng)使用 yield from 時(shí),所提供的表達(dá)式必須是一個(gè)可迭代對(duì)象。 迭代該可迭代對(duì)象所產(chǎn)生的值會(huì)被直接傳遞給當(dāng)前生成器方法的調(diào)用者。 任何通過(guò) send() 傳入的值以及任何通過(guò) throw() 傳入的異常如果有適當(dāng)?shù)姆椒▌t會(huì)被傳給下層迭代器。 如果不是這種情況,那么 send() 將引發(fā) AttributeError 或 TypeError,而 throw() 將立即引發(fā)所轉(zhuǎn)入的異常。
當(dāng)下層迭代器完成時(shí),被引發(fā)的 StopIteration 實(shí)例的 value 屬性會(huì)成為 yield 表達(dá)式的值。 它可以在引發(fā) StopIteration 時(shí)被顯式地設(shè)置,也可以在子迭代器是一個(gè)生成器時(shí)自動(dòng)地設(shè)置(通過(guò)從子生成器返回一個(gè)值)。
在 3.3 版更改: 添加
yield from以委托控制流給一個(gè)子迭代器。
當(dāng)yield表達(dá)式是賦值語(yǔ)句右側(cè)的唯一表達(dá)式時(shí),括號(hào)可以省略。
參見(jiàn)
PEP 255 - 簡(jiǎn)單生成器
在 Python 中加入生成器和 yield 語(yǔ)句的提議。
PEP 342 - 通過(guò)增強(qiáng)型生成器實(shí)現(xiàn)協(xié)程
增強(qiáng)生成器 API 和語(yǔ)法的提議,使其可以被用作簡(jiǎn)單的協(xié)程。
PEP 380 - 委托給子生成器的語(yǔ)法
引入 yield_from 語(yǔ)法的提議,以方便地委托給子生成器。
PEP 525 - 異步生成器
通過(guò)給協(xié)程函數(shù)加入生成器功能對(duì) PEP 492 進(jìn)行擴(kuò)展的提議。
6.2.9.1. 生成器-迭代器的方法
這個(gè)子小節(jié)描述了生成器迭代器的方法。 它們可被用于控制生成器函數(shù)的執(zhí)行。
請(qǐng)注意在生成器已經(jīng)在執(zhí)行時(shí)調(diào)用以下任何方法都會(huì)引發(fā) ValueError 異常。
generator.__next__()
開(kāi)始一個(gè)生成器函數(shù)的執(zhí)行或是從上次執(zhí)行 yield 表達(dá)式的位置恢復(fù)執(zhí)行。 當(dāng)一個(gè)生成器函數(shù)通過(guò) __next__() 方法恢復(fù)執(zhí)行時(shí),當(dāng)前的 yield 表達(dá)式總是取值為 None。 隨后會(huì)繼續(xù)執(zhí)行到下一個(gè) yield 表達(dá)式,這時(shí)生成器將再次掛起,而 expression_list 的值會(huì)被返回給 __next__() 的調(diào)用方。 如果生成器沒(méi)有產(chǎn)生下一個(gè)值就退出,則將引發(fā) StopIteration 異常。
此方法通常是隱式地調(diào)用,例如通過(guò) for 循環(huán)或是內(nèi)置的 next() 函數(shù)。
generator.send(value)
恢復(fù)執(zhí)行并向生成器函數(shù)“發(fā)送”一個(gè)值。 value 參數(shù)將成為當(dāng)前 yield 表達(dá)式的結(jié)果。 send() 方法會(huì)返回生成器所產(chǎn)生的下一個(gè)值,或者如果生成器沒(méi)有產(chǎn)生下一個(gè)值就退出則會(huì)引發(fā) StopIteration。 當(dāng)調(diào)用 send() 來(lái)啟動(dòng)生成器時(shí),它必須以 None 作為調(diào)用參數(shù),因?yàn)檫@時(shí)沒(méi)有可以接收值的 yield 表達(dá)式。
generator.throw(value)
generator.throw(type[, value[, traceback]])
在生成器暫停的位置引發(fā)一個(gè)異常,并返回該生成器函數(shù)所產(chǎn)生的下一個(gè)值。 如果生成器沒(méi)有產(chǎn)生下一個(gè)值就退出,則將引發(fā) StopIteration 異常。 如果生成器函數(shù)沒(méi)有捕獲傳入的異常,或是引發(fā)了另一個(gè)異常,則該異常會(huì)被傳播給調(diào)用方。
在典型的使用場(chǎng)景下,其調(diào)用將附帶單個(gè)異常實(shí)例,類(lèi)似于使用 raise 關(guān)鍵字的方式。
For backwards compatibility, however, the second signature is supported, following a convention from older versions of Python. The type argument should be an exception class, and value should be an exception instance. If the value is not provided, the type constructor is called to get an instance. If traceback is provided, it is set on the exception, otherwise any existing __traceback__ attribute stored in value may be cleared.
generator.close()
在生成器函數(shù)暫停的位置引發(fā) GeneratorExit。 如果之后生成器函數(shù)正常退出、關(guān)閉或引發(fā) GeneratorExit (由于未捕獲該異常) 則關(guān)閉并返回其調(diào)用者。 如果生成器產(chǎn)生了一個(gè)值,關(guān)閉會(huì)引發(fā) RuntimeError。 如果生成器引發(fā)任何其他異常,它會(huì)被傳播給調(diào)用者。 如果生成器已經(jīng)由于異?;蛘M顺鰟t close() 不會(huì)做任何事。
6.2.9.2. 例子
這里是一個(gè)簡(jiǎn)單的例子,演示了生成器和生成器函數(shù)的行為:
>>> def echo(value=None):... print("Execution starts when 'next()' is called for the first time.")... try:... while True:... try:... value = (yield value)... except Exception as e:... value = e... finally:... print("Don't forget to clean up when 'close()' is called.")...>>> generator = echo(1)>>> print(next(generator))Execution starts when 'next()' is called for the first time.1>>> print(next(generator))None>>> print(generator.send(2))2>>> generator.throw(TypeError, "spam")TypeError('spam',)>>> generator.close()Don't forget to clean up when 'close()' is called.
對(duì)于 yield from 的例子, 參見(jiàn)“Python 有什么新變化”中的 PEP 380: 委托給子生成器的語(yǔ)法。
6.2.9.3. 異步生成器函數(shù)
在一個(gè)使用 async def 定義的函數(shù)或方法中出現(xiàn)的 yield 表達(dá)式會(huì)進(jìn)一步將該函數(shù)定義為一個(gè) asynchronous generator 函數(shù)。
當(dāng)一個(gè)異步生成器函數(shù)被調(diào)用時(shí),它會(huì)返回一個(gè)名為異步生成器對(duì)象的異步迭代器。 此對(duì)象將在之后控制該生成器函數(shù)的執(zhí)行。 異步生成器對(duì)象通常被用在協(xié)程函數(shù)的 async for 語(yǔ)句中,類(lèi)似于在 for 語(yǔ)句中使用生成器對(duì)象。
調(diào)用某個(gè)異步生成器的方法將返回 awaitable 對(duì)象,執(zhí)行會(huì)在此對(duì)象被等待時(shí)啟動(dòng)。 到那時(shí),執(zhí)行過(guò)程將前往第一個(gè) yield 表達(dá)式,在那里它會(huì)再次掛起,將 expression_list 的值返回給等待中的協(xié)程。 與生成器一樣,掛起意味著所有局部狀態(tài)會(huì)被保留,包括局部變量的當(dāng)前綁定、指令指針、內(nèi)部求值棧以及任何異常處理的狀態(tài)。 當(dāng)執(zhí)行在等待異步生成器的方法返回下一個(gè)對(duì)象后恢復(fù)時(shí),該函數(shù)可以從原狀態(tài)繼續(xù)執(zhí)行,就仿佛 yield 表達(dá)式只是另一個(gè)外部調(diào)用。 恢復(fù)執(zhí)行之后 yield 表達(dá)式的值取決于恢復(fù)執(zhí)行所用的方法。 如果使用 __anext__() 則結(jié)果為 None。 否則的話(huà),如果使用 asend(),則結(jié)果將是傳遞給該方法的值。
如果一個(gè)異步生成器恰好因 break、調(diào)用方任務(wù)被取消,或是其他異常而提前退出,生成器的異步清理代碼將會(huì)運(yùn)行并可能引發(fā)異?;蛟L問(wèn)意外上下文中的上下文變量 — 也許是在它所依賴(lài)的任務(wù)的生命周期之后,或是在異步生成器垃圾回收鉤子被調(diào)用時(shí)的事件循環(huán)關(guān)閉期間。 為了防止這種情況,調(diào)用方必須通過(guò)調(diào)用 aclose() 方法來(lái)顯式地關(guān)閉異步生成器以終結(jié)生成器并最終從事件循環(huán)中將其分離。
在異步生成器函數(shù)中,yield 表達(dá)式允許出現(xiàn)在 try 結(jié)構(gòu)的任何位置。 但是,如果一個(gè)異步生成器在其被終結(jié)(由于引用計(jì)數(shù)達(dá)到零或被作為垃圾回收)之前未被恢復(fù),則then a yield expression within a try 結(jié)構(gòu)中的 yield 表達(dá)式可能導(dǎo)致掛起的 finally 子句執(zhí)行失敗。 在此情況下,應(yīng)由運(yùn)行該異步生成器的事件循環(huán)或任務(wù)調(diào)度器來(lái)負(fù)責(zé)調(diào)用異步生成器-迭代器的 aclose() 方法并運(yùn)行所返回的協(xié)程對(duì)象,從而允許任何掛起的 finally 子句得以執(zhí)行。
為了能在事件循環(huán)終結(jié)時(shí)執(zhí)行最終化處理,事件循環(huán)應(yīng)當(dāng)定義一個(gè) 終結(jié)器 函數(shù),它接受一個(gè)異步生成器迭代器并將調(diào)用 aclose() 且執(zhí)行該協(xié)程。 這個(gè) 終結(jié)器 可以通過(guò)調(diào)用 sys.set_asyncgen_hooks() 來(lái)注冊(cè)。 當(dāng)首次迭代時(shí),異步生成器迭代器將保存已注冊(cè)的 終結(jié)器 以便在最終化時(shí)調(diào)用。 有關(guān) 終結(jié)器 方法的參考示例請(qǐng)查看在 Lib/asyncio/base_events.py 的中的 asyncio.Loop.shutdown_asyncgens 實(shí)現(xiàn)。
yield from 表達(dá)式如果在異步生成器函數(shù)中使用會(huì)引發(fā)語(yǔ)法錯(cuò)誤。
6.2.9.4. 異步生成器-迭代器方法
這個(gè)子小節(jié)描述了異步生成器迭代器的方法,它們可被用于控制生成器函數(shù)的執(zhí)行。
coroutine agen.__anext__()
返回一個(gè)可等待對(duì)象,它在運(yùn)行時(shí)會(huì)開(kāi)始執(zhí)行該異步生成器或是從上次執(zhí)行的 yield 表達(dá)式位置恢復(fù)執(zhí)行。 當(dāng)一個(gè)異步生成器函數(shù)通過(guò) __anext__() 方法恢復(fù)執(zhí)行時(shí),當(dāng)前的 yield 表達(dá)式所返回的可等待對(duì)象總是取值為 None,它在運(yùn)行時(shí)將繼續(xù)執(zhí)行到下一個(gè) yield 表達(dá)式。 該 yield 表達(dá)式的 expression_list 的值會(huì)是完成的協(xié)程所引發(fā)的 StopIteration 異常的值。 如果異步生成器沒(méi)有產(chǎn)生下一個(gè)值就退出,則該可等待對(duì)象將引發(fā) StopAsyncIteration 異常,提示該異步迭代操作已完成。
此方法通常是通過(guò) async for 循環(huán)隱式地調(diào)用。
coroutine agen.asend(value)
返回一個(gè)可等待對(duì)象,它在運(yùn)行時(shí)會(huì)恢復(fù)該異步生成器的執(zhí)行。 與生成器的 send() 方法一樣,此方法會(huì)“發(fā)送”一個(gè)值給異步生成器函數(shù),其 value 參數(shù)會(huì)成為當(dāng)前 yield 表達(dá)式的結(jié)果值。 asend() 方法所返回的可等待對(duì)象將返回生成器產(chǎn)生的下一個(gè)值,其值為所引發(fā)的 StopIteration,或者如果異步生成器沒(méi)有產(chǎn)生下一個(gè)值就退出則引發(fā) StopAsyncIteration。 當(dāng)調(diào)用 asend() 來(lái)啟動(dòng)異步生成器時(shí),它必須以 None 作為調(diào)用參數(shù),因?yàn)檫@時(shí)沒(méi)有可以接收值的 yield 表達(dá)式。
coroutine agen.athrow(type[, value[, traceback]])
返回一個(gè)可等待對(duì)象,它會(huì)在異步生成器暫停的位置引發(fā) type 類(lèi)型的異常,并返回該生成器函數(shù)所產(chǎn)生的下一個(gè)值,其值為所引發(fā)的 StopIteration 異常。 如果異步生成器沒(méi)有產(chǎn)生下一個(gè)值就退出,則將由該可等待對(duì)象引發(fā) StopAsyncIteration 異步。 如果生成器函數(shù)沒(méi)有捕獲傳入的異常,或引發(fā)了另一個(gè)異常,則當(dāng)可等待對(duì)象運(yùn)行時(shí)該異常會(huì)被傳播給可等待對(duì)象的調(diào)用者。
coroutine agen.aclose()
返回一個(gè)可等待對(duì)象,它會(huì)在運(yùn)行時(shí)向異步生成器函數(shù)暫停的位置拋入一個(gè) GeneratorExit。 如果該異步生成器函數(shù)正常退出、關(guān)閉或引發(fā) GeneratorExit (由于未捕獲該異常) 則返回的可等待對(duì)象將引發(fā) StopIteration 異常。 后續(xù)調(diào)用異步生成器所返回的任何其他可等待對(duì)象將引發(fā) StopAsyncIteration 異常。 如果異步生成器產(chǎn)生了一個(gè)值,該可等待對(duì)象會(huì)引發(fā) RuntimeError。 如果異步生成器引發(fā)任何其他異常,它會(huì)被傳播給可等待對(duì)象的調(diào)用者。 如果異步生成器已經(jīng)由于異?;蛘M顺鰟t后續(xù)調(diào)用 aclose() 將返回一個(gè)不會(huì)做任何事的可等待對(duì)象。
6.3. 原型
原型代表編程語(yǔ)言中最緊密綁定的操作。 它們的句法如下:
- primary ::= atom | attributeref | subscription | slicing | call
6.3.1. 屬性引用
屬性引用是后面帶有一個(gè)句點(diǎn)加一個(gè)名稱(chēng)的原型:
- attributeref ::= primary "." identifier
此原型必須求值為一個(gè)支持屬性引用的類(lèi)型的對(duì)象,多數(shù)對(duì)象都支持屬性引用。 隨后該對(duì)象會(huì)被要求產(chǎn)生以指定標(biāo)識(shí)符為名稱(chēng)的屬性。 這個(gè)產(chǎn)生過(guò)程可通過(guò)重載 __getattr__() 方法來(lái)自定義。 如果這個(gè)屬性不可用,則將引發(fā) AttributeError 異常。 否則的話(huà),所產(chǎn)生對(duì)象的類(lèi)型和值會(huì)根據(jù)該對(duì)象來(lái)確定。 對(duì)同一屬性引用的多次求值可能產(chǎn)生不同的對(duì)象。
6.3.2. 抽取
對(duì)一個(gè) 容器類(lèi) 的實(shí)例執(zhí)行抽取操作通常將會(huì)從該容器中選取一個(gè)元素。 而對(duì)一個(gè) 泛型類(lèi) 執(zhí)行抽取操作通常將會(huì)返回一個(gè) GenericAlias 對(duì)象。
- subscription ::= primary "[" expression_list "]"
當(dāng)一個(gè)對(duì)象被抽取時(shí),解釋器將對(duì)原型和表達(dá)式列表進(jìn)行求值。
原型必須可被求值為一個(gè)支持抽取操作的對(duì)象。 一個(gè)對(duì)象可通過(guò)同時(shí)定義 __getitem__() 和 __class_getitem__() 或其中之一來(lái)支持抽取操作。 當(dāng)原型被抽取時(shí),表達(dá)式列表的求值結(jié)果將被傳給以上方法中的一個(gè)。 對(duì)于在何時(shí)會(huì)調(diào)用 __class_getitem__ 而不是 __getitem__ 的更多細(xì)節(jié),請(qǐng)參閱 __class_getitem__ 與 __getitem__。
如果表達(dá)式列表包含至少一個(gè)逗號(hào),它將被求值為包含該表達(dá)式列表中所有條目的 tuple。 在其他情況下,表達(dá)式列表將被求值為列表中唯一成員的值。
對(duì)于內(nèi)置對(duì)象,有兩種類(lèi)型的對(duì)象支持通過(guò) __getitem__() 執(zhí)行抽取操作:
映射。 如果原型是一個(gè) mapping,則表達(dá)式列表必須求值為一個(gè)以該映射的某個(gè)鍵為值的對(duì)象,而抽取操作會(huì)在映射中選取該鍵所對(duì)應(yīng)的值。 內(nèi)置映射類(lèi)的一個(gè)例子是 dict 類(lèi)。
序列。 如果原型是一個(gè) sequence,則表達(dá)式列表必須求值為一個(gè) int 或一個(gè) slice (如下面的小節(jié)所討論的)。 內(nèi)置序列類(lèi)的例子包括 str, list 和 tuple 等類(lèi)。
正式語(yǔ)法規(guī)則并未在 序列 中設(shè)置負(fù)索引號(hào)的特殊保留條款。 不過(guò),內(nèi)置序列都提供了通過(guò)給索引號(hào)加上序列長(zhǎng)度來(lái)解讀負(fù)索引號(hào)的 __getitem__() 方法,因此舉例來(lái)說(shuō),x[-1] 將選取 x 的最后一項(xiàng)。 結(jié)果值必須為一個(gè)小于序列中條目數(shù)的非負(fù)整數(shù),抽取操作會(huì)選取索引號(hào)為該值的條目(從零開(kāi)始計(jì)數(shù))。 由于對(duì)負(fù)索引號(hào)和切片的支持位于對(duì)象的 __getitem__() 方法中,因而重載此方法的子類(lèi)將需要顯式地添加這種支持。
字符串 是一種特殊的序列,其中的項(xiàng)是 字符。 字符并不是一種單獨(dú)的數(shù)據(jù)類(lèi)型而是長(zhǎng)度恰好為一個(gè)字符的字符串。
6.3.3. 切片
切片就是在序列對(duì)象(字符串、元組或列表)中選擇某個(gè)范圍內(nèi)的項(xiàng)。 切片可被用作表達(dá)式以及賦值或 del 語(yǔ)句的目標(biāo)。 切片的句法如下:
- slicing ::= primary "[" slice_list "]"
- slice_list ::= slice_item ("," slice_item)* [","]
- slice_item ::= expression | proper_slice
- proper_slice ::= [lower_bound] ":" [upper_bound] [ ":" [stride] ]
- lower_bound ::= expression
- upper_bound ::= expression
- stride ::= expression
此處的正式句法中存在一點(diǎn)歧義:任何形似表達(dá)式列表的東西同樣也會(huì)形似切片列表,因此任何抽取操作也可以被解析為切片。 為了不使句法更加復(fù)雜,于是通過(guò)定義將此情況解析為抽取優(yōu)先于解析為切片來(lái)消除這種歧義(切片列表未包含正確的切片就屬于此情況)。
切片的語(yǔ)義如下所述。 元型通過(guò)一個(gè)根據(jù)下面的切片列表來(lái)構(gòu)造的鍵進(jìn)行索引(與普通抽取一樣使用 __getitem__() 方法)。 如果切片列表包含至少一個(gè)逗號(hào),則鍵將是一個(gè)包含切片項(xiàng)轉(zhuǎn)換的元組;否則的話(huà),鍵將是單個(gè)切片項(xiàng)的轉(zhuǎn)換。 切片項(xiàng)如為一個(gè)表達(dá)式,則其轉(zhuǎn)換就是該表達(dá)式。 一個(gè)正確切片的轉(zhuǎn)換就是一個(gè)切片對(duì)象(參見(jiàn) 標(biāo)準(zhǔn)類(lèi)型層級(jí)結(jié)構(gòu) 一節(jié)),該對(duì)象的 start, stop 和 step 屬性將分別為表達(dá)式所給出的下界、上界和步長(zhǎng)值,省略的表達(dá)式將用 None 來(lái)替換。
6.3.4. 調(diào)用
所謂調(diào)用就是附帶可能為空的一系列 參數(shù) 來(lái)執(zhí)行一個(gè)可調(diào)用對(duì)象 (例如 function):
- call ::= primary "(" [argument_list [","] | comprehension] ")"
- argument_list ::= positional_arguments ["," starred_and_keywords]
- ["," keywords_arguments]
- | starred_and_keywords ["," keywords_arguments]
- | keywords_arguments
- positional_arguments ::= positional_item ("," positional_item)*
- positional_item ::= assignment_expression | "*" expression
- starred_and_keywords ::= ("*" expression | keyword_item)
- ("," "*" expression | "," keyword_item)*
- keywords_arguments ::= (keyword_item | "**" expression)
- ("," keyword_item | "," "**" expression)*
- keyword_item ::= identifier "=" expression
一個(gè)可選項(xiàng)為在位置和關(guān)鍵字參數(shù)后加上逗號(hào)而不影響語(yǔ)義。
此原型必須求值為一個(gè)可調(diào)用對(duì)象(用戶(hù)定義的函數(shù),內(nèi)置函數(shù),內(nèi)置對(duì)象的方法,類(lèi)對(duì)象,類(lèi)實(shí)例的方法以及任何具有 __call__() 方法的對(duì)象都是可調(diào)用對(duì)象)。 所有參數(shù)表達(dá)式將在嘗試調(diào)用前被求值。 請(qǐng)參閱 函數(shù)定義 一節(jié)了解正式的 parameter 列表句法。
If keyword arguments are present, they are first converted to positional arguments, as follows. First, a list of unfilled slots is created for the formal parameters. If there are N positional arguments, they are placed in the first N slots. Next, for each keyword argument, the identifier is used to determine the corresponding slot (if the identifier is the same as the first formal parameter name, the first slot is used, and so on). If the slot is already filled, a TypeError exception is raised. Otherwise, the argument is placed in the slot, filling it (even if the expression is None, it fills the slot). When all arguments have been processed, the slots that are still unfilled are filled with the corresponding default value from the function definition. (Default values are calculated, once, when the function is defined; thus, a mutable object such as a list or dictionary used as default value will be shared by all calls that don’t specify an argument value for the corresponding slot; this should usually be avoided.) If there are any unfilled slots for which no default value is specified, a TypeError exception is raised. Otherwise, the list of filled slots is used as the argument list for the call.
CPython 實(shí)現(xiàn)細(xì)節(jié): 某些實(shí)現(xiàn)可能提供位置參數(shù)沒(méi)有名稱(chēng)的內(nèi)置函數(shù),即使它們?cè)谖臋n說(shuō)明的場(chǎng)合下有“命名”,因此不能以關(guān)鍵字形式提供參數(shù)。 在 CPython 中,以 C 編寫(xiě)并使用 PyArg_ParseTuple() 來(lái)解析其參數(shù)的函數(shù)實(shí)現(xiàn)就屬于這種情況。
如果存在比正式參數(shù)空位多的位置參數(shù),將會(huì)引發(fā) TypeError 異常,除非有一個(gè)正式參數(shù)使用了 *identifier 句法;在此情況下,該正式參數(shù)將接受一個(gè)包含了多余位置參數(shù)的元組(如果沒(méi)有多余位置參數(shù)則為一個(gè)空元組)。
如果任何關(guān)鍵字參數(shù)沒(méi)有與之對(duì)應(yīng)的正式參數(shù)名稱(chēng),將會(huì)引發(fā) TypeError 異常,除非有一個(gè)正式參數(shù)使用了 **identifier 句法,該正式參數(shù)將接受一個(gè)包含了多余關(guān)鍵字參數(shù)的字典(使用關(guān)鍵字作為鍵而參數(shù)值作為與鍵對(duì)應(yīng)的值),如果沒(méi)有多余關(guān)鍵字參數(shù)則為一個(gè)(新的)空字典。
如果函數(shù)調(diào)用中出現(xiàn)了 *expression 句法,expression 必須求值為一個(gè) iterable。 來(lái)自該可迭代對(duì)象的元素會(huì)被當(dāng)作是額外的位置參數(shù)。 對(duì)于 f(x1, x2, *y, x3, x4) 調(diào)用,如果 y 求值為一個(gè)序列 y1, …, yM,則它就等價(jià)于一個(gè)帶有 M+4 個(gè)位置參數(shù) x1, x2, y1, …, yM, x3, x4 的調(diào)用。
這樣做的一個(gè)后果是雖然 *expression 句法可能出現(xiàn)于顯式的關(guān)鍵字參數(shù) 之后,但它會(huì)在關(guān)鍵字參數(shù)(以及任何 **expression 參數(shù) — 見(jiàn)下文) 之前 被處理。 因此:
>>> def f(a, b):... print(a, b)...>>> f(b=1, *(2,))2 1>>> f(a=1, *(2,))Traceback (most recent call last):File "", line 1, in TypeError: f() got multiple values for keyword argument 'a'>>> f(1, *(2,))1 2
It is unusual for both keyword arguments and the *expression syntax to be used in the same call, so in practice this confusion does not often arise.
If the syntax **expression appears in the function call, expression must evaluate to a mapping, the contents of which are treated as additional keyword arguments. If a parameter matching a key has already been given a value (by an explicit keyword argument, or from another unpacking), a TypeError exception is raised.
When **expression is used, each key in this mapping must be a string. Each value from the mapping is assigned to the first formal parameter eligible for keyword assignment whose name is equal to the key. A key need not be a Python identifier (e.g. "max-temp °F" is acceptable, although it will not match any formal parameter that could be declared). If there is no match to a formal parameter the key-value pair is collected by the ** parameter, if there is one, or if there is not, a TypeError exception is raised.
使用 *identifier 或 **identifier 句法的正式參數(shù)不能被用作位置參數(shù)空位或關(guān)鍵字參數(shù)名稱(chēng)。
在 3.5 版更改: 函數(shù)調(diào)用接受任意數(shù)量的 * 和 ** 拆包,位置參數(shù)可能跟在可迭代對(duì)象拆包 (*) 之后,而關(guān)鍵字參數(shù)可能跟在字典拆包 (**) 之后。 由 PEP 448 發(fā)起最初提議。
除非引發(fā)了異常,調(diào)用總是會(huì)有返回值,返回值也可能為 None。 返回值的計(jì)算方式取決于可調(diào)用對(duì)象的類(lèi)型。
如果類(lèi)型為—-
用戶(hù)自定義函數(shù):
函數(shù)的代碼塊會(huì)被執(zhí)行,并向其傳入?yún)?shù)列表。 代碼塊所做的第一件事是將正式形參綁定到對(duì)應(yīng)參數(shù);相關(guān)描述參見(jiàn) 函數(shù)定義 一節(jié)。 當(dāng)代碼塊執(zhí)行 return 語(yǔ)句時(shí),由其指定函數(shù)調(diào)用的返回值。
內(nèi)置函數(shù)或方法:
具體結(jié)果依賴(lài)于解釋器;有關(guān)內(nèi)置函數(shù)和方法的描述參見(jiàn) 內(nèi)置函數(shù)。
類(lèi)對(duì)象:
返回該類(lèi)的一個(gè)新實(shí)例。
類(lèi)實(shí)例方法:
調(diào)用相應(yīng)的用戶(hù)自定義函數(shù),向其傳入的參數(shù)列表會(huì)比調(diào)用的參數(shù)列表多一項(xiàng):該實(shí)例將成為第一個(gè)參數(shù)。
類(lèi)實(shí)例:
該類(lèi)必須定義有 __call__() 方法;作用效果將等價(jià)于調(diào)用該方法。
6.4. await 表達(dá)式
掛起 coroutine 的執(zhí)行以等待一個(gè) awaitable 對(duì)象。 只能在 coroutine function 內(nèi)部使用。
- await_expr ::= "await" primary
3.5 新版功能.
6.5. 冪運(yùn)算符
冪運(yùn)算符的綁定比在其左側(cè)的一元運(yùn)算符更緊密;但綁定緊密程度不及在其右側(cè)的一元運(yùn)算符。 句法如下:
- power ::= (await_expr | primary) ["**" u_expr]
因此,在一個(gè)未加圓括號(hào)的冪運(yùn)算符和單目運(yùn)算符序列中,運(yùn)算符將從右向左求值(這不會(huì)限制操作數(shù)的求值順序): -1**2 結(jié)果將為 -1。
冪運(yùn)算符與附帶兩個(gè)參數(shù)調(diào)用內(nèi)置 pow() 函數(shù)具有相同的語(yǔ)義:結(jié)果為對(duì)其左參數(shù)進(jìn)行其右參數(shù)所指定冪次的乘方運(yùn)算。 數(shù)值參數(shù)會(huì)先轉(zhuǎn)換為相同類(lèi)型,結(jié)果也為轉(zhuǎn)換后的類(lèi)型。
對(duì)于 int 類(lèi)型的操作數(shù),結(jié)果將具有與操作數(shù)相同的類(lèi)型,除非第二個(gè)參數(shù)為負(fù)數(shù);在那種情況下,所有參數(shù)會(huì)被轉(zhuǎn)換為 float 類(lèi)型并輸出 float 類(lèi)型的結(jié)果。 例如,10**2 返回 100,而 10**-2 返回 0.01。
對(duì) 0.0 進(jìn)行負(fù)數(shù)冪次運(yùn)算將導(dǎo)致 ZeroDivisionError。 對(duì)負(fù)數(shù)進(jìn)行分?jǐn)?shù)冪次運(yùn)算將返回 complex 數(shù)值。 (在早期版本中這將引發(fā) ValueError。)
此運(yùn)算符可使用特殊的 __pow__() 方法來(lái)自定義。
6.6. 一元算術(shù)和位運(yùn)算
所有算術(shù)和位運(yùn)算具有相同的優(yōu)先級(jí):
- u_expr ::= power | "-" u_expr | "+" u_expr | "~" u_expr
一元的 - (負(fù)值) 運(yùn)算符會(huì)產(chǎn)生其數(shù)字參數(shù)的負(fù)值;該運(yùn)算可通過(guò) __neg__() 特殊方法來(lái)重載。
一元的 + (正值) 運(yùn)算符會(huì)原樣輸出其數(shù)字參數(shù);該運(yùn)算可通過(guò) __pos__() 特殊方法來(lái)重載。
一元的 ~ (取反) 運(yùn)算符會(huì)對(duì)其整數(shù)參數(shù)按位取反。 x 的按位取反被定義為 -(x+1)。 它只作用于整數(shù)或是重載了 __invert__() 特殊方法的自定義對(duì)象。
在所有三種情況下,如果參數(shù)的類(lèi)型不正確,將引發(fā) TypeError 異常。
6.7. 二元算術(shù)運(yùn)算符
二元算術(shù)運(yùn)算符遵循傳統(tǒng)的優(yōu)先級(jí)。 請(qǐng)注意某些此類(lèi)運(yùn)算符也作用于特定的非數(shù)字類(lèi)型。 除冪運(yùn)算符以外只有兩個(gè)優(yōu)先級(jí)別,一個(gè)作用于乘法型運(yùn)算符,另一個(gè)作用于加法型運(yùn)算符:
- m_expr ::= u_expr | m_expr "*" u_expr | m_expr "@" m_expr |
- m_expr "http://" u_expr | m_expr "/" u_expr |
- m_expr "%" u_expr
- a_expr ::= m_expr | a_expr "+" m_expr | a_expr "-" m_expr
運(yùn)算符 * (乘) 將輸出其參數(shù)的乘積。 兩個(gè)參數(shù)或者必須都為數(shù)字,或者一個(gè)參數(shù)必須為整數(shù)而另一個(gè)參數(shù)必須為序列。 在前一種情況下,兩個(gè)數(shù)字將被轉(zhuǎn)換為相同類(lèi)型然后相乘。 在后一種情況下,將執(zhí)行序列的重復(fù);重復(fù)因子為負(fù)數(shù)將輸出空序列。
此運(yùn)算可使用特殊的 __mul__() 和 __rmul__() 方法來(lái)自定義。
運(yùn)算符 @ (at) 的目標(biāo)是用于矩陣乘法。 沒(méi)有內(nèi)置 Python 類(lèi)型實(shí)現(xiàn)此運(yùn)算符。
3.5 新版功能.
運(yùn)算符 / (除) 和 // (整除) 將輸出其參數(shù)的商。 兩個(gè)數(shù)字參數(shù)將先被轉(zhuǎn)換為相同類(lèi)型。 整數(shù)相除會(huì)輸出一個(gè) float 值,整數(shù)相整除的結(jié)果仍是整數(shù);整除的結(jié)果就是使用 ‘floor’ 函數(shù)進(jìn)行算術(shù)除法的結(jié)果。 除以零的運(yùn)算將引發(fā) ZeroDivisionError 異常。
此運(yùn)行可使用特殊的 __truediv__() 和 __floordiv__() 方法來(lái)自定義。
運(yùn)算符 % (模) 將輸出第一個(gè)參數(shù)除以第二個(gè)參數(shù)的余數(shù)。 兩個(gè)數(shù)字參數(shù)將先被轉(zhuǎn)換為相同類(lèi)型。 右參數(shù)為零將引發(fā) ZeroDivisionError 異常。 參數(shù)可以為浮點(diǎn)數(shù),例如 3.14%0.7 等于 0.34 (因?yàn)?3.14 等于 4*0.7 + 0.34)。 模運(yùn)算符的結(jié)果的正負(fù)總是與第二個(gè)操作數(shù)一致(或是為零);結(jié)果的絕對(duì)值一定小于第二個(gè)操作數(shù)的絕對(duì)值 1。
整除與模運(yùn)算符的聯(lián)系可通過(guò)以下等式說(shuō)明: x == (x//y)*y + (x%y)。 此外整除與模也可通過(guò)內(nèi)置函數(shù) divmod() 來(lái)同時(shí)進(jìn)行: divmod(x, y) == (x//y, x%y)。 2。
除了對(duì)數(shù)字執(zhí)行模運(yùn)算,運(yùn)算符 % 還被字符串對(duì)象重載用于執(zhí)行舊式的字符串格式化(又稱(chēng)插值)。 字符串格式化句法的描述參見(jiàn) Python 庫(kù)參考的 printf 風(fēng)格的字符串格式化 一節(jié)。
取余 運(yùn)算可使用特殊的 __mod__() 方法來(lái)自定義。
整除運(yùn)算符,模運(yùn)算符和 divmod() 函數(shù)未被定義用于復(fù)數(shù)。 如果有必要可以使用 abs() 函數(shù)將其轉(zhuǎn)換為浮點(diǎn)數(shù)。
運(yùn)算符 + (addition) 將輸出其參數(shù)的和。 兩個(gè)參數(shù)或者必須都為數(shù)字,或者都為相同類(lèi)型的序列。 在前一種情況下,兩個(gè)數(shù)字將被轉(zhuǎn)換為相同類(lèi)型然后相加。 在后一種情況下,將執(zhí)行序列拼接操作。
此運(yùn)算可使用特殊的 __add__() 和 __radd__() 方法來(lái)自定義。
運(yùn)算符 - (減) 將輸出其參數(shù)的差。 兩個(gè)數(shù)字參數(shù)將先被轉(zhuǎn)換為相同類(lèi)型。
此運(yùn)算可使用特殊的 __sub__() 方法來(lái)自定義。
6.8. 移位運(yùn)算
移位運(yùn)算的優(yōu)先級(jí)低于算術(shù)運(yùn)算:
- shift_expr ::= a_expr | shift_expr ("<<" | ">>") a_expr
這些運(yùn)算符接受整數(shù)參數(shù)。 它們會(huì)將第一個(gè)參數(shù)左移或右移第二個(gè)參數(shù)所指定的比特位數(shù)。
此運(yùn)算可使用特殊的 __lshift__() 和 __rshift__() 方法來(lái)自定義。
右移 n 位被定義為被 pow(2,n) 整除。 左移 n 位被定義為乘以 pow(2,n)。
6.9. 二元位運(yùn)算
三種位運(yùn)算具有各不相同的優(yōu)先級(jí):
- and_expr ::= shift_expr | and_expr "&" shift_expr
- xor_expr ::= and_expr | xor_expr "^" and_expr
- or_expr ::= xor_expr | or_expr "|" xor_expr
& 運(yùn)算符會(huì)對(duì)其參數(shù)執(zhí)行按位 AND,參數(shù)必須都為整數(shù)或者其中之一必須為重載了 __and__() 或 __rand__() 特殊方法的自定義對(duì)象。
^ 運(yùn)算符會(huì)對(duì)其參數(shù)執(zhí)行按位 XOR (異 OR),參數(shù)必須都為整數(shù)或者其中之一必須為重載了 __xor__() 或 __rxor__() 特殊方法的自定義對(duì)象。
| 運(yùn)算符會(huì)對(duì)其參數(shù)執(zhí)行按位 (合并) OR,參數(shù)必須都為整數(shù)或者其中之一必須為重載了 __or__() 或 __ror__() 特殊方法的自定義對(duì)象。
6.10. 比較運(yùn)算
與 C 不同,Python 中所有比較運(yùn)算的優(yōu)先級(jí)相同,低于任何算術(shù)、移位或位運(yùn)算。 另一個(gè)與 C 不同之處在于 a < b < c 這樣的表達(dá)式會(huì)按傳統(tǒng)算術(shù)法則來(lái)解讀:
- comparison ::= or_expr (comp_operator or_expr)*
- comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!="
- | "is" ["not"] | ["not"] "in"
比較運(yùn)算會(huì)產(chǎn)生布爾值: True 或 False。 自定義的 富比較方法 可能返回非布爾值。 在此情況下 Python 將在布爾運(yùn)算上下文中對(duì)該值調(diào)用 bool()。
比較運(yùn)算可以任意串連,例如 x < y <= z 等價(jià)于 x < y and y <= z,除了 y 只被求值一次(但在兩種寫(xiě)法下當(dāng) x < y 值為假時(shí) z 都不會(huì)被求值)。
正式的說(shuō)法是這樣:如果 a, b, c, …, y, z 為表達(dá)式而 op1, op2, …, opN 為比較運(yùn)算符,則 a op1 b op2 c ... y opN z 就等價(jià)于 a op1 b and b op2 c and ... y opN z,不同點(diǎn)在于每個(gè)表達(dá)式最多只被求值一次。
請(qǐng)注意 a op1 b op2 c 不意味著在 a 和 c 之間進(jìn)行任何比較,因此,如 x < y > z 這樣的寫(xiě)法是完全合法的(雖然也許不太好看)。
6.10.1. 值比較
運(yùn)算符 <, >, ==, >=, <= 和 != 將比較兩個(gè)對(duì)象的值。 兩個(gè)對(duì)象不要求為相同類(lèi)型。
對(duì)象、值與類(lèi)型 一章已說(shuō)明對(duì)象都有相應(yīng)的值(還有類(lèi)型和標(biāo)識(shí)號(hào))。 對(duì)象值在 Python 中是一個(gè)相當(dāng)抽象的概念:例如,對(duì)象值并沒(méi)有一個(gè)規(guī)范的訪問(wèn)方法。 而且,對(duì)象值并不要求具有特定的構(gòu)建方式,例如由其全部數(shù)據(jù)屬性組成等。 比較運(yùn)算符實(shí)現(xiàn)了一個(gè)特定的對(duì)象值概念。 人們可以認(rèn)為這是通過(guò)實(shí)現(xiàn)對(duì)象比較間接地定義了對(duì)象值。
由于所有類(lèi)型都是 object 的(直接或間接)子類(lèi)型,它們都從 object 繼承了默認(rèn)的比較行為。 類(lèi)型可以通過(guò)實(shí)現(xiàn) 豐富比較方法 例如 __lt__() 來(lái)定義自己的比較行為,詳情參見(jiàn) 基本定制。
默認(rèn)的一致性比較 (== 和 !=) 是基于對(duì)象的標(biāo)識(shí)號(hào)。 因此,具有相同標(biāo)識(shí)號(hào)的實(shí)例一致性比較結(jié)果為相等,具有不同標(biāo)識(shí)號(hào)的實(shí)例一致性比較結(jié)果為不等。 規(guī)定這種默認(rèn)行為的動(dòng)機(jī)是希望所有對(duì)象都應(yīng)該是自反射的 (即 x is y 就意味著 x == y)。
次序比較 (<, >, <= 和 >=) 默認(rèn)沒(méi)有提供;如果嘗試比較會(huì)引發(fā) TypeError。 規(guī)定這種默認(rèn)行為的原因是缺少與一致性比較類(lèi)似的固定值。
按照默認(rèn)的一致性比較行為,具有不同標(biāo)識(shí)號(hào)的實(shí)例總是不相等,這可能不適合某些對(duì)象值需要有合理定義并有基于值的一致性的類(lèi)型。 這樣的類(lèi)型需要定制自己的比較行為,實(shí)際上,許多內(nèi)置類(lèi)型都是這樣做的。
以下列表描述了最主要內(nèi)置類(lèi)型的比較行為。
內(nèi)置數(shù)值類(lèi)型 (數(shù)字類(lèi)型 —- int, float, complex) 以及標(biāo)準(zhǔn)庫(kù)類(lèi)型 fractions.Fraction 和 decimal.Decimal 可進(jìn)行類(lèi)型內(nèi)部和跨類(lèi)型的比較,例外限制是復(fù)數(shù)不支持次序比較。 在類(lèi)型相關(guān)的限制以?xún)?nèi),它們會(huì)按數(shù)學(xué)(算法)規(guī)則正確進(jìn)行比較且不會(huì)有精度損失。
非數(shù)字值
float('NaN')和decimal.Decimal('NaN')屬于特例。 任何數(shù)字與非數(shù)字值的排序比較均返回假值。 還有一個(gè)反直覺(jué)的結(jié)果是非數(shù)字值不等于其自身。 舉例來(lái)說(shuō),如果x = float('NaN')則3 < x,x < 3和x == x均為假值,而x != x則為真值。 此行為是遵循 IEEE 754 標(biāo)準(zhǔn)的。None和NotImplemented都是單例對(duì)象。 PEP 8 建議單例對(duì)象的比較應(yīng)當(dāng)總是通過(guò)is或is not而不是等于運(yùn)算符來(lái)進(jìn)行。二進(jìn)制碼序列 (bytes 或 byte
網(wǎng)頁(yè)題目:創(chuàng)新互聯(lián)Python教程:6. 表達(dá)式
標(biāo)題來(lái)源:http://fisionsoft.com.cn/article/djdocoi.html


咨詢(xún)
建站咨詢(xún)
