在线观看不卡亚洲电影_亚洲妓女99综合网_91青青青亚洲娱乐在线观看_日韩无码高清综合久久

鍍金池/ 教程/ Python/ 表達(dá)式
復(fù)合語(yǔ)句
數(shù)據(jù)模型
完整的語(yǔ)法規(guī)范
執(zhí)行模型
表達(dá)式
導(dǎo)入系統(tǒng)
詞法分析
簡(jiǎn)單語(yǔ)句
頂層組件
介紹

表達(dá)式

本章描述了 Python 中表達(dá)式的組成元素的含義。

句法注意:在本章和之后的章節(jié)中,描述句法時(shí)使用與詞法分析時(shí)不同的擴(kuò)展 BNF 記法。當(dāng)某個(gè)句法規(guī)則(可能是可選的)具有如下形式:

name ::= othername

并且未給出特定語(yǔ)義時(shí),name 的這種形式的意義就與 othername 相同。

數(shù)值間的轉(zhuǎn)換

當(dāng)用以下短語(yǔ)“數(shù)值型參數(shù)轉(zhuǎn)換為通用類(lèi)型”描述數(shù)值型操作數(shù)時(shí),參數(shù)使用第三章結(jié)尾處的強(qiáng)制規(guī)則進(jìn)行強(qiáng)制轉(zhuǎn)換。如果兩個(gè)參數(shù)都屬于標(biāo)準(zhǔn)數(shù)值型,就使用以下的強(qiáng)制規(guī)則:

  • 如果其中一個(gè)參數(shù)是復(fù)數(shù),另一個(gè)也要轉(zhuǎn)換成復(fù)數(shù);
  • 否則,如果其中一個(gè)參數(shù)是浮點(diǎn)數(shù),另一個(gè)也要轉(zhuǎn)換成浮點(diǎn)數(shù);
  • 否則,兩個(gè)都是整數(shù), 不需要轉(zhuǎn)換。

對(duì)于某些運(yùn)算符有特殊的規(guī)則(例如,作為運(yùn)算符‘%’左側(cè)參數(shù)的字符)。擴(kuò)展必須制定轉(zhuǎn)換規(guī)則。

原子

原子是表達(dá)式最基本的組成單位,最簡(jiǎn)單的原子是標(biāo)識(shí)符或者字面值。 以圓括號(hào)、方括號(hào)或大括號(hào)括住的符號(hào)在句法上也看成是原子。原子的句法如下:

atom ::= identifier | literal | enclosure

enclosure ::= parenth_form | list_display | dict_display | set_display | generator_expression | yield_atom

標(biāo)識(shí)符(名字)

作為一個(gè)原子出現(xiàn)的標(biāo)識(shí)符是一個(gè)名字。參看標(biāo)識(shí)符和關(guān)鍵字以及命名空間和結(jié)構(gòu)框架。

當(dāng)某名字捆綁的是一個(gè)對(duì)象時(shí),使用該原子就是使用那個(gè)對(duì)象。當(dāng)某名字沒(méi)有捆綁就直接使用它,則會(huì)拋出一個(gè) NameError 異常。

私有名字變換: 在類(lèi)定義中, 以?xún)蓚€(gè)或多個(gè)下劃線開(kāi)始,并且尾部不是以?xún)蓚€(gè)或多個(gè)下劃線結(jié)束的標(biāo)識(shí)符,它被看作是類(lèi)的私有名字。在產(chǎn)生它的代碼之前, 私有名字被變換成更長(zhǎng)的形式。這種變換是在將去掉前導(dǎo)下劃線的類(lèi)名插入到名字前,再在類(lèi)名前插入一個(gè)下劃線。例如,在類(lèi) Ham 中定義的標(biāo)識(shí)符 _ _spam,會(huì)被變換成 _ _Ham_spam。本變換是不依賴(lài)于使用該標(biāo)識(shí)符處代碼的句法上的上下文的。如果變換后的結(jié)果過(guò)長(zhǎng)(超過(guò) 255 個(gè)字符), 就會(huì)執(zhí)行該P(yáng)ython實(shí)現(xiàn)定義的截短名字的操作。如果某類(lèi)的名字僅僅由下劃線組成,這種變換是不會(huì)發(fā)生的。

字面值

Python 支持字符串、字節(jié)和各種數(shù)值型的字面值:

literal ::= stringliteral | bytesliteral | integer | floatnumber | imagnumber

使用一個(gè)字面值會(huì)得到一個(gè)具有給定值的相應(yīng)類(lèi)型的對(duì)象(字符串、字節(jié)、整數(shù)、浮點(diǎn)數(shù)、復(fù)數(shù)),如果是浮點(diǎn)數(shù)和復(fù)數(shù),那么這個(gè)值可能是個(gè)近似值,詳見(jiàn) Literals。

所有字面值都屬于不可變的數(shù)據(jù)類(lèi)型,因此對(duì)象的標(biāo)識(shí)比起它們的值來(lái)說(shuō)顯得次要一些。多次使用相同值的字面值(在程序代碼中以相同形式出現(xiàn)或者以不同的形式出現(xiàn))可能獲得的是相同的對(duì)象或具有相同值的不同對(duì)象?!? 

括號(hào)表達(dá)式

一個(gè)括號(hào)表達(dá)式是位于一對(duì)小括號(hào)內(nèi)可選的表達(dá)式表。

parenth_form ::= "(" [expression_list] ")"

表達(dá)式表生成什么類(lèi)型的值括號(hào)表達(dá)式也就生成什么類(lèi)型的值:如果表達(dá)式表中包括了至少一個(gè)逗號(hào),它就生成一個(gè)元組;否則,就生成那個(gè)組成表達(dá)式表的唯一的表達(dá)式。

一個(gè)空的表達(dá)式表會(huì)生成一個(gè)空的元組對(duì)象。因?yàn)樵M是不可變的,因此這里適用字符串所用的規(guī)則(即兩個(gè)具有空表達(dá)式的元組可能是同一個(gè)對(duì)象也可能是不同的對(duì)象)。

請(qǐng)注意元組不是依靠小括號(hào)成定義的,而是使用逗號(hào)。其中空元組是個(gè)例外,此時(shí)要求有小括號(hào)——在表達(dá)式中允許沒(méi)有小括號(hào)的“空”可能會(huì)引起歧義,并容易造成難以查覺(jué)的筆誤。

列表、集合和字典的表示

為了構(gòu)建一個(gè)列表、一個(gè)集合或者一個(gè)字典,Python 提供了一種特殊的語(yǔ)法叫“表示”,每一個(gè)都有兩種方式:

  • 容器中的內(nèi)容被詳細(xì)列出
  • 或者是通過(guò)一套循環(huán)和過(guò)濾指令來(lái)計(jì)算,被稱(chēng)為“推導(dǎo)式”。

推導(dǎo)式的一般語(yǔ)法元素是:

comprehension ::= expression comp_for
comp_for ::= "for" target_list "in" or_test [comp_iter]
comp_iter ::= comp_for | comp_if
comp_if ::= "if" expression_nocond [comp_iter]

推導(dǎo)式是由至少一個(gè) for 子句以及后跟零個(gè)或多個(gè) forif 子句構(gòu)成的一個(gè)表達(dá)式組成,在這種情況下,新列表的元素由每個(gè) forif 子句決定,嵌套是從左至右方向的,而且每執(zhí)行到最內(nèi)部的語(yǔ)句塊就產(chǎn)生一個(gè)列表元素。

請(qǐng)注意,推導(dǎo)式是在一個(gè)單獨(dú)的范圍內(nèi)執(zhí)行的,所以目標(biāo)列表的名字分配不能泄漏到封閉的范圍內(nèi)。

列表的表示

一個(gè)列表用一對(duì)方括號(hào)括住的表達(dá)式序列(可能為空)表示:

list_display ::= "[" [expression_list | comprehension] "]"

使用一個(gè)列表會(huì)生成一個(gè)新的列表對(duì)。它的值由表達(dá)式表或由推導(dǎo)式給出。當(dāng)給出一個(gè)逗號(hào)分隔的表達(dá)式表時(shí),從左到右地對(duì)每個(gè)元素求值然后按順序放進(jìn)列表對(duì)象中。 如果給出的是推導(dǎo)式, 列表是由從推導(dǎo)式得出的元素組合而成。

集合的表示

一個(gè)集合是用花括號(hào)來(lái)表示的,它和字典的區(qū)別是缺少分隔鍵和值的冒號(hào)。

set_display ::= "{" (expression_list | comprehension) "}"

集合的表示將產(chǎn)生一個(gè)新的集合對(duì)象,內(nèi)容是由一個(gè)表達(dá)式序列或者一個(gè)推導(dǎo)式來(lái)制定。當(dāng)提供一個(gè)由逗號(hào)分隔的表達(dá)式列表時(shí),將從左到由計(jì)算它的元素并把它們加入到集合對(duì)象中。當(dāng)提供一個(gè)推導(dǎo)式時(shí),集合將由從推導(dǎo)式中得出的元素組成。

一個(gè)空的集合不能由{ }構(gòu)建,這種形式將構(gòu)建一個(gè)空的字典。

字典的表示

一個(gè)字典用一對(duì)大括號(hào)括住的鍵/數(shù)據(jù)對(duì)的序列(可能為空)表示:

dict_display ::= "{" [key_datum_list | dict_comprehension] "}"
key_datum_list ::= key_datum ("," key_datum)* [","]
key_datum ::= expression ":" expression
dict_comprehension ::= expression ":" expression comp_for

使用一個(gè)字典會(huì)生成一個(gè)新的字典對(duì)象。

鍵/數(shù)據(jù)對(duì)按在字典中定義的從左到右的順序求值:每個(gè)鍵對(duì)象作為鍵嵌入到字典中存儲(chǔ)相應(yīng)的數(shù)據(jù)。這意味著你可以在鍵/數(shù)據(jù)列表中多次指定相同的鍵,鍵值是最后一次指定的值。

字典推導(dǎo)式,與列表和集合推導(dǎo)式相反,需要兩個(gè)由冒號(hào)分開(kāi)的表達(dá)式,并且其后跟一般的 “for” 和 “if” 子句。當(dāng)推導(dǎo)式在運(yùn)行時(shí),產(chǎn)生的鍵和值元素將按照它們生成的順序插入到新的字典中去。

關(guān)于鍵值類(lèi)型的限制已在前述章節(jié) 標(biāo)準(zhǔn)類(lèi)型層次 提及(總而言之,鍵的類(lèi)型應(yīng)該是可散列的,這就排除了所有的可變對(duì)象)。重復(fù)鍵之間的沖突不會(huì)被檢測(cè)到;對(duì)給定的(有重復(fù)的)鍵來(lái)說(shuō),最后出現(xiàn)的數(shù)據(jù)(就是文字顯示中出現(xiàn)在最右邊的)成為(最終的)勝利者。

生成器表達(dá)式

生成器表達(dá)式是由圓括號(hào)括起來(lái)的緊湊的生成器符號(hào)。

generator_expression ::= "(" expression comp_for ")"

一個(gè)生成器表達(dá)式產(chǎn)生一個(gè)新的生成器對(duì)象。它是被括在圓括號(hào)中而不是方括號(hào)或者花括號(hào)中,除此之外,它的語(yǔ)法和推導(dǎo)式一樣。

當(dāng) __next__() 方法被生成器對(duì)象調(diào)用時(shí),在生成器表達(dá)式中用到的變量將被計(jì)算(和普通生成器相同)。然而,最左邊的 for 子句將被立即計(jì)算,這樣由它產(chǎn)生的錯(cuò)誤將在處理生成器代碼中其它可能出現(xiàn)的錯(cuò)誤之前被發(fā)現(xiàn)。隨后的 for 子句將不會(huì)被立即計(jì)算,因?yàn)樗鼈儗⑷Q于之前的 for 循環(huán)。例如 (x*y for x in range(10) for y in bar(x))。

當(dāng)調(diào)用生成器表達(dá)式時(shí),圓括號(hào)可以被忽略,只保留一個(gè)參數(shù)。詳情請(qǐng)參見(jiàn)調(diào)用章節(jié)。

Yield 表達(dá)式

yield_atom ::= "("yield_expression ")"
yield_expression ::= "yield" [expression_list | "from" expression]

yield 表達(dá)式只有在定義一個(gè)生成器功能時(shí)才會(huì)被使用,所以只能被用在函數(shù)定義的過(guò)程中。在函數(shù)體內(nèi)使用 yield 表達(dá)式將會(huì)使該函數(shù)變成一個(gè)生成器。

當(dāng)一個(gè)生成器函數(shù)被調(diào)用時(shí),它將返回一個(gè)被稱(chēng)為生成器的迭代器。該生成器將控制生成器函數(shù)的執(zhí)行。當(dāng)生成器的某個(gè)方法被調(diào)用時(shí),生成器函數(shù)將開(kāi)始執(zhí)行。同時(shí),在執(zhí)行第一個(gè) yield 表達(dá)式的過(guò)程中,即上次被掛起的地方,將返回表達(dá)式列表的值給生成器調(diào)用程序。所謂掛起,即所有的本地狀態(tài)都將被保留,包括局部變量的綁定情況、指令指針、內(nèi)部計(jì)算堆棧以及一些異常處理的狀態(tài)。當(dāng)調(diào)用生成器的某種方法,該執(zhí)行過(guò)程恢復(fù)時(shí),該函數(shù)可以像 yield 表達(dá)式是另外一個(gè)外部表達(dá)式調(diào)用一樣運(yùn)行?;謴?fù)執(zhí)行后 yeild 表達(dá)式的值將取決于使該執(zhí)行過(guò)程恢復(fù)的方法。如果使用 __next__() 函數(shù)(通常是通過(guò) for 語(yǔ)句或者內(nèi)部 next() 函數(shù)),則結(jié)果為 None。如果使用 send() 函數(shù),結(jié)果為傳遞到該方法中的值。

所有這些特性讓生成器函數(shù)和協(xié)同程序非常像,它們可以多次輸出,有多于一個(gè)的程序執(zhí)行入口點(diǎn),而且它們的執(zhí)行過(guò)程可以被掛起。唯一的區(qū)別是當(dāng)輸出一次執(zhí)行結(jié)果后,需要繼續(xù)執(zhí)行時(shí),生成器函數(shù)無(wú)法控制,只有當(dāng)生成器被調(diào)用時(shí)才可以被控制。

try 塊中的任何地方都可以使用 yield 表達(dá)式。如果一個(gè)生成器在它結(jié)束(引用計(jì)數(shù)達(dá)到0或者被垃圾收集)之前沒(méi)有被恢復(fù),迭代器的 close() 方法將會(huì)被調(diào)用,允許各種 finally 語(yǔ)句執(zhí)行。

當(dāng)使用 yield from <expr> 時(shí),認(rèn)為表達(dá)式為從迭代器。所有由該從迭代器提供的值將直接返回給當(dāng)前生成器方法的調(diào)用程序。如果有合適的方法,所有由 send() 函數(shù)傳遞的值和所有由 throw() 函數(shù)傳遞的異常都將傳送給底層的迭代器。如果找不到合適的方法,send() 函數(shù)將拋出AttributeError或者 TypeError異常,但是 throw() 函數(shù)只拋出傳遞異常。

當(dāng)?shù)讓盈B加器完成計(jì)算時(shí),拋出的 StopIteration 異常實(shí)例的值屬性將變成 yield 表達(dá)式的值。它可以在拋出異常 StopIteration 異常時(shí)明確的設(shè)置,或者當(dāng)子迭代器是一個(gè)生成器時(shí)(通過(guò)子生成器返回值)自動(dòng)生成。

3.3版本修改的地方:添加 yield from <expr> 語(yǔ)句使子生成器具備控制功能。

當(dāng) yield 表達(dá)式是賦值表達(dá)式右邊唯一的表達(dá)式時(shí),圓括號(hào)可以被忽略。

可參見(jiàn): PEP 0255 – 簡(jiǎn)單生成器
提議在 Python 中 添加生成器和 yield 的說(shuō)明.
PEP 0342 – 通過(guò)高級(jí)生成器實(shí)現(xiàn)的協(xié)同程序
提議增強(qiáng)生成器的 API 和語(yǔ)法,讓它們和簡(jiǎn)單生成器一樣便于使用。
PEP 0380 – 子生成器的授權(quán)語(yǔ)法
提議介紹 yield-from 語(yǔ)法,讓授權(quán)子生成器變得容易。

生成器-迭代器方法

這一部分將描述生成器迭代器的方法,該方法可以控制生成器程序的執(zhí)行。

請(qǐng)注意:當(dāng)生成器已經(jīng)開(kāi)始運(yùn)行的時(shí)候,調(diào)用以下任何一個(gè)方法將拋出 ValueError 異常。

generator.__next__()

開(kāi)啟生成器函數(shù)的執(zhí)行或者在上次執(zhí)行 yield 表達(dá)式的地方恢復(fù)執(zhí)行。當(dāng)一個(gè)生成器函數(shù)被 next() 方法恢復(fù)執(zhí)行,最近的 yield 表達(dá)式通常計(jì)算為 None。當(dāng)生成器再次被掛起,表達(dá)式列表的值被返回給 next() 函數(shù)的調(diào)用者,執(zhí)行過(guò)程將繼續(xù)到下一個(gè) yield 表達(dá)式。如果生成器沒(méi)有生成另外一個(gè)值就直接退出執(zhí)行,將引發(fā)一個(gè) StopIteration 異常。

該方法通常被間接調(diào)用,如通過(guò)一個(gè) for 循環(huán)或者通過(guò)內(nèi)建 next() 函數(shù)。

generator.send(value)

恢復(fù)執(zhí)行過(guò)程并且傳遞給生成器函數(shù)一個(gè)值。value 參數(shù)的值將被賦予當(dāng)前 yield 表達(dá)式。send() 方法返回生成器生成的下一個(gè)值。如果生成器沒(méi)有產(chǎn)生其它值并退出執(zhí)行后,將引發(fā) StopIteration 異常。當(dāng)調(diào)用 send() 函數(shù)啟動(dòng)生成器時(shí),必須以 None 作為參數(shù),因?yàn)闆](méi)有接收該值得 yield 表達(dá)式。

generator.throw(type[, value[, traceback]])

當(dāng)生成器被暫停將拋出一個(gè) type 類(lèi)型的異常,并返回由生成器函數(shù)生成的 next 值。如果生成器沒(méi)有返回其它值并退出執(zhí)行,將拋出一個(gè) StopIteration 異常。如果生成器函數(shù)沒(méi)有對(duì)傳入的異常進(jìn)行捕獲處理時(shí),異常將返回給調(diào)用者。

generator.close()

當(dāng)生成器函數(shù)被暫停執(zhí)行時(shí)將拋出 GeneratorExit 異常(正常退出或者已被關(guān)閉)。如果生成器函數(shù)拋出一個(gè) StopIteration (正常退出或者已被關(guān)閉)或者 GeneratorExit 異常時(shí)(不捕獲處理異常),生成器將正常結(jié)束。如果生成器返回其它值,將拋出 RuntimeError 異常。如果生成器拋出其它類(lèi)型的異常,則異常將直接被返回給調(diào)用者。如果生成器因?yàn)楫惓;蛘哒M顺龆Y(jié)束運(yùn)行,則 close() 函數(shù)不起任何作用。

舉例

此處用一個(gè)簡(jiǎn)單的例子來(lái)說(shuō)明生成器和生成器函數(shù)的執(zhí)行。

    >>> 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.  

使用 yield from 語(yǔ)句的例子,請(qǐng)參見(jiàn)PEP380:委托至子生成器的語(yǔ)法。

基元

基元指和語(yǔ)言本身中接合最緊密的若干操作。它們的語(yǔ)法如下:

primary ::= atom | attributeref | subscription | slicing | call

屬性引用

一個(gè)屬性引用是由一個(gè)主元(primary)后跟一個(gè)句號(hào)和一個(gè)名字構(gòu)成:

attributeref ::= primary "." identifier

主元必須是一個(gè)支持屬性引用的類(lèi)型的對(duì)象。引用對(duì)象屬性時(shí),即要求該被對(duì)象生成指定名字的屬性?!≡撨^(guò)程可以通過(guò)重寫(xiě) _ getattr _() 方法具體化?!?如果該屬性無(wú)效,將會(huì)拋出異常 AttribError。否則,對(duì)象決定生成的屬性的類(lèi)型和值。對(duì)同一屬性的引用多次求值是有可能生成不同對(duì)象的。

下標(biāo)

一個(gè)下標(biāo)選擇一個(gè)有序類(lèi)型對(duì)象(字符串,元祖或列表)或映射(字典)對(duì)象的一項(xiàng):

subscription ::= primary "[" expression_list "]"

主元(primary)必須是一個(gè)支持下標(biāo)計(jì)算的對(duì)象(例如列表或字典)。用戶自定義的對(duì)象通過(guò)定義 __getitem__() 方法來(lái)支持下標(biāo)。

如果主元是一個(gè)映射,則對(duì)表達(dá)式表求值的結(jié)果必須是映射中的一個(gè)鍵,然后此下標(biāo)操作在主元映射中選擇與該鍵所對(duì)應(yīng)的值。(如果表達(dá)式表只有一項(xiàng),那么它就是一個(gè)元組)。

如果主元是一個(gè)有序類(lèi)型,表達(dá)式(列表)的計(jì)算結(jié)果應(yīng)該是一個(gè)整數(shù)或片段(見(jiàn)下方討論部分)。

正式的語(yǔ)法對(duì)序列中的負(fù)索引沒(méi)有特別的規(guī)定;但是,所有內(nèi)建序列都提供了一個(gè) __getitem__() 方法來(lái)解決負(fù)索引,即如果索引值是負(fù)數(shù), 就加上該序列的長(zhǎng)度(例如, x[-1] 選擇 x 的最后一項(xiàng))。

字符串的元素是字符,字符不是單獨(dú)的數(shù)據(jù)類(lèi)型而僅僅是只有一個(gè)字符長(zhǎng)的字符串。

片段

一個(gè)片斷選擇某個(gè)有序類(lèi)型對(duì)象(如字符串、元組、列表)一段范圍之內(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

在這里形式句法的說(shuō)明中有點(diǎn)含糊: 任何看起來(lái)像表達(dá)式表的語(yǔ)法構(gòu)件也能看作是片斷表,所以任何下標(biāo)都可以解釋為片斷。但這樣要比更復(fù)雜的句法要合適,該定義是沒(méi)有歧義的,在這種情況下(在片斷表中沒(méi)有包括適當(dāng)?shù)钠瑪嗷蛘呤÷詫?xiě)法)優(yōu)先將其解釋為下標(biāo),而不是片斷。

一個(gè)片斷的語(yǔ)義如下:主要是由該片斷表構(gòu)成的鍵作索引(使用相同的 __getitem__() 方法作為正常下標(biāo))。如果一個(gè)片斷表包括至少一個(gè)逗號(hào),那么鍵就是一個(gè)包括由片斷中的所有項(xiàng)轉(zhuǎn)換而來(lái)的元組; 否則, 就用獨(dú)立的片斷項(xiàng)作轉(zhuǎn)換成為鍵。為表達(dá)式的片斷項(xiàng)轉(zhuǎn)換后仍是該表達(dá)式。正常的片斷轉(zhuǎn)換后是一個(gè) start,stop 和step 屬性為給定的下限,上限和步長(zhǎng)的片斷對(duì)象(見(jiàn)3.2節(jié)),對(duì)于缺少的表達(dá)式用 None 替代。

調(diào)用

一個(gè)調(diào)用就是以一系列參數(shù)(可能為空)調(diào)用一個(gè)可調(diào)用對(duì)象(例如,函數(shù)):

call ::= primary "(" [argument_list [","] | comprehension] ")"
argument_list ::= positional_arguments ["," keyword_arguments]
[","*" expression] ["," keyword_arguments]
["," "**" expression]
| [keyword_arguments]() ["," "*" expression]
["," keyword_arguments] ["," "**" expression]
| "*" expression ["," keyword_arguments] ["," "**" expression]
| "**" expression
positional_arguments ::= expression ("," expression)
keyword_arguments ::= keyword_item ("," keyword_item)

keyword_item ::= identifier "=" expression

在關(guān)鍵字參數(shù)表后面可以出現(xiàn)一個(gè)逗號(hào),但它在語(yǔ)義上是沒(méi)有任何作用的。

首先的工作是導(dǎo)出一個(gè)可調(diào)用對(duì)象(用戶自定義函數(shù),內(nèi)建函數(shù),內(nèi)建方法對(duì)象,類(lèi)定義,類(lèi)實(shí)例方法,包含方法 __call__() 的對(duì)象都是可調(diào)用的)。所有的參數(shù)表達(dá)都在試圖調(diào)用之前被計(jì)算。關(guān)于形參列表的句法請(qǐng)參考章節(jié)函數(shù)定義。

如果給出了關(guān)鍵字參數(shù),它們首先被轉(zhuǎn)換為位置參數(shù)。具體如下:第一步,根據(jù)形參表創(chuàng)建一串空閑槽,如果有N個(gè)位置參數(shù),它們就被放在前N個(gè)槽中。然后,對(duì)于每個(gè)關(guān)鍵字參數(shù),它的標(biāo)識(shí)符用于檢測(cè)其對(duì)應(yīng)的槽(如果其標(biāo)識(shí)符與第一個(gè)形參數(shù)名相同,它就占用第一個(gè)槽,以此類(lèi)推)如果發(fā)現(xiàn)某個(gè)槽已經(jīng)被占用,則引發(fā) TypeError異常。否則將參數(shù)的值(即使為 None )放進(jìn)槽中。當(dāng)所有關(guān)鍵字參數(shù)處理完成后, 所有未填充的槽用在函數(shù)定義中的相應(yīng)的默認(rèn)值填充。(默認(rèn)值是由函數(shù)定義時(shí)計(jì)算出來(lái)的,所以,像列表和字典這樣的可變類(lèi)型對(duì)象作默認(rèn)值時(shí),它們會(huì)被那些沒(méi)有相應(yīng)槽指定參數(shù)值的調(diào)用所共享,通常要避免這樣做)。如果仍有未填充默認(rèn)的槽位,就會(huì)引發(fā)一個(gè) TypeError 異常。否則,所有被填充的槽當(dāng)作調(diào)用的參數(shù)表。

CPython實(shí)現(xiàn)細(xì)節(jié):CPython實(shí)現(xiàn)了一種位置參數(shù)沒(méi)有名字的內(nèi)建函數(shù),即使位置參數(shù)被命名也是為了閱讀方便,因此無(wú)法提供關(guān)鍵詞。在實(shí)現(xiàn),這是實(shí)現(xiàn)在 C 使用 PyArg_ParseTuple() 解析他們的論點(diǎn)的情況下。

如果位置參數(shù)的個(gè)數(shù)比形參槽數(shù)多,并且在未使用 *identifier 句法的情況下,會(huì)引發(fā) TypeError 異常。使用該種句法時(shí),形參接受一個(gè)包括有額外位置參數(shù)的元組(如果沒(méi)有額外和位置參數(shù),它就為空)。

如果任何一個(gè)關(guān)鍵字參數(shù)與形參名不匹配,并且在未使用 **identifier句法的情況下,會(huì)引發(fā) TypeError 異常。使用該種句法時(shí),形參接受一個(gè)包括有額外關(guān)鍵字參數(shù)的字典(關(guān)鍵字作為鍵,參數(shù)值作為該鍵對(duì)應(yīng)的值),字典如果沒(méi)有額外和關(guān)鍵字參數(shù),它就為空。

如果在函數(shù)調(diào)用中使用了 *exprsiones 句法, 那么 exprsiones的結(jié)果必須是有序類(lèi)型的。這個(gè)有序類(lèi)型對(duì)象的元素被當(dāng)作附加的位置參數(shù)處理; 如果存在有位置參數(shù) x1,...,xN,并且 *exprsiones 的計(jì)算結(jié)果為 y1,...,yM,那么它與具有 M+N 個(gè)參數(shù) x1,...xN,y1,...,yM 的調(diào)用等效。

由此可以得到一個(gè)推論: 盡管 *exprsiones 句法出現(xiàn)在任何關(guān)鍵字參數(shù)之后,但它在處理關(guān)鍵字參數(shù)之前計(jì)算。(如果有的話,**exprsiones 也是如此,參見(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 "<stdin>", line 1, in ?  
    TypeError: f() got multiple values for keyword argument 'a'  
    >>> f(1, *(2,))  
    1 2  

一同使用關(guān)鍵字語(yǔ)法和 *expression 的情況十分罕見(jiàn),所以實(shí)際上這種混亂是不會(huì)發(fā)生的。

如果在函數(shù)調(diào)用中使用 **expression 句法,expression 計(jì)算結(jié)果必須是一個(gè)字典(的子類(lèi))。其內(nèi)容作為附加的關(guān)鍵字參數(shù)。如果一個(gè)關(guān)鍵字出現(xiàn)在 expression 中并且是一個(gè)顯式關(guān)鍵字參數(shù),就會(huì)引發(fā) TypeError 異常。

使用 *identifier”**identifier 句法的形參不能作為位置參數(shù)或關(guān)鍵字參數(shù)名使用。

一個(gè)元組如果沒(méi)有引發(fā)異常,通常會(huì)返回一些值,可能為 None。怎樣計(jì)算這個(gè)值依賴(lài)于可調(diào)用對(duì)象的類(lèi)型。

如果它是—

用戶自定義函數(shù):
執(zhí)行此函數(shù)的代碼塊,并把參數(shù)傳給它。它要做的第一件事就是將形參與實(shí)參對(duì)應(yīng)起來(lái)。關(guān)于這點(diǎn)參見(jiàn)函數(shù)定義 當(dāng)代碼塊執(zhí)行到 return 語(yǔ)句時(shí),會(huì)指定這次函數(shù)調(diào)用的返回值。

內(nèi)建函數(shù)或內(nèi)建方法:
結(jié)果依賴(lài)于解釋器,詳見(jiàn) Built-in Functions。

類(lèi)對(duì)象:
返回該類(lèi)的一個(gè)新實(shí)例。

類(lèi)實(shí)例的方法:
調(diào)用對(duì)應(yīng)的用戶自定義函數(shù),其參數(shù)個(gè)數(shù)比普通的函數(shù)調(diào)用多一:該實(shí)例成為方法的第一個(gè)參數(shù)。

類(lèi)實(shí)例:
類(lèi)實(shí)例必須定義方法 call ();效果與調(diào)用該方法相同。

冪運(yùn)算符

冪運(yùn)算符比在操作數(shù)左邊的一元運(yùn)算符有更高的優(yōu)先級(jí);但比右面的一元運(yùn)算符要低。句法為:

power ::=primary ["**" u_expr]

因此,在一串沒(méi)有括號(hào)的由冪運(yùn)算符和一元運(yùn)算符組成的序列,會(huì)從左到右面求值(沒(méi)有強(qiáng)制改變求值順 序):-1**2 結(jié)果為 -1。

當(dāng)以?xún)蓚€(gè)參數(shù)調(diào)用 pow() 時(shí),冪運(yùn)算符與內(nèi)建函數(shù) pow() 有相同的語(yǔ)義: 生成左邊參數(shù)的右邊參數(shù)次方。數(shù)值型參數(shù)首先轉(zhuǎn)換成通用類(lèi)型。結(jié)果類(lèi)型是參數(shù)經(jīng)強(qiáng)制規(guī)則轉(zhuǎn)換后的結(jié)果。

對(duì)于整數(shù)操作數(shù),其結(jié)果的類(lèi)型與操作數(shù)相同除非第二個(gè)參數(shù)為負(fù)數(shù);在這種情況下,所有的參數(shù)被轉(zhuǎn)換為 float 進(jìn)而結(jié)果也是 float。例如,10\*\*2 返回 100,但 10\*\*-2 返回 0.01。

0.0的任意負(fù)數(shù)指冪會(huì)引發(fā) ZeroDivisionError 異常。一個(gè)負(fù)數(shù)的分?jǐn)?shù)指冪結(jié)果是一個(gè) complex。(早期的版本中會(huì)引發(fā) ValueError 異常。)

一元算術(shù)運(yùn)算符和位運(yùn)算符

所有一元算術(shù)運(yùn)算符(和位運(yùn)算符)有相同的優(yōu)先級(jí):

u_expr ::=power | "-" u_expr | "+" u_expr | "~" u_expr

一元運(yùn)算符-(減)對(duì)其數(shù)值型操作數(shù)取負(fù)。

一元運(yùn)算符+(加)不改變其數(shù)值型操作數(shù)。

一元運(yùn)算符 (取反)對(duì)其普通整數(shù)或長(zhǎng)整數(shù)參數(shù)求逆(比特級(jí))。x的比特級(jí)求逆運(yùn)算定義為 -(x+1)。它僅僅用于整數(shù)型的操作數(shù)。

在以上所有的三種情況下,如果參數(shù)的類(lèi)型不合法,就會(huì)引發(fā)一個(gè) TypeError 異常。

二元算術(shù)運(yùn)算符

二元算術(shù)運(yùn)算符的優(yōu)先級(jí)符合我們的正常習(xí)慣。注意其中有些運(yùn)算符也可以應(yīng)用于非數(shù)值型操作數(shù)。除了冪運(yùn)算符,它們只分兩個(gè)優(yōu)先級(jí):一個(gè)是乘法類(lèi)運(yùn)算,一個(gè)是加法類(lèi)運(yùn)算。

m_expr ::= u_expr | m_expr "*" u_expr | m_expr "//" [u_expr]() | m_expr "/" u_expr | m_expr "%" 上一篇:介紹下一篇:執(zhí)行模型