7. 簡(jiǎn)單語句?

簡(jiǎn)單語句由一個(gè)單獨(dú)的邏輯行構(gòu)成。 多條簡(jiǎn)單語句可以存在于同一行內(nèi)并以分號(hào)分隔。 簡(jiǎn)單語句的句法為:

simple_stmt ::=  expression_stmt
                 | assert_stmt
                 | assignment_stmt
                 | augmented_assignment_stmt
                 | annotated_assignment_stmt
                 | pass_stmt
                 | del_stmt
                 | return_stmt
                 | yield_stmt
                 | raise_stmt
                 | break_stmt
                 | continue_stmt
                 | import_stmt
                 | future_stmt
                 | global_stmt
                 | nonlocal_stmt

7.1. 表達(dá)式語句?

表達(dá)式語句用于計(jì)算和寫入值(大多是在交互模式下),或者(通常情況)調(diào)用一個(gè)過程 (過程就是不返回有意義結(jié)果的函數(shù);在 Python 中,過程的返回值為 None)。 表達(dá)式語句的其他使用方式也是允許且有特定用處的。 表達(dá)式語句的句法為:

expression_stmt ::=  starred_expression

表達(dá)式語句會(huì)對(duì)指定的表達(dá)式列表(也可能為單一表達(dá)式)進(jìn)行求值。

在交互模式下,如果結(jié)果值不為 None,它會(huì)通過內(nèi)置的 repr() 函數(shù)轉(zhuǎn)換為一個(gè)字符串,該結(jié)果字符串將以單獨(dú)一行的形式寫入標(biāo)準(zhǔn)輸出(例外情況是如果結(jié)果為 None,則該過程調(diào)用不產(chǎn)生任何輸出。)

7.2. 賦值語句?

賦值語句用于將名稱(重)綁定到特定值,以及修改屬性或可變對(duì)象的成員項(xiàng):

assignment_stmt ::=  (target_list "=")+ (starred_expression | yield_expression)
target_list     ::=  target ("," target)* [","]
target          ::=  identifier
                     | "(" [target_list] ")"
                     | "[" [target_list] "]"
                     | attributeref
                     | subscription
                     | slicing
                     | "*" target

(請(qǐng)參閱 原型 一節(jié)了解 屬性引用, 抽取切片 的句法定義。)

賦值語句會(huì)對(duì)指定的表達(dá)式列表進(jìn)行求值(注意這可能為單一表達(dá)式或是由逗號(hào)分隔的列表,后者將產(chǎn)生一個(gè)元組)并將單一結(jié)果對(duì)象從左至右逐個(gè)賦值給目標(biāo)列表。

賦值是根據(jù)目標(biāo)(列表)的格式遞歸地定義的。 當(dāng)目標(biāo)為一個(gè)可變對(duì)象(屬性引用、抽取或切片)的組成部分時(shí),該可變對(duì)象必須最終執(zhí)行賦值并決定其有效性,如果賦值操作不可接受也可能引發(fā)異常。 各種類型可用的規(guī)則和引發(fā)的異常通過對(duì)象類型的定義給出(參見 標(biāo)準(zhǔn)類型層級(jí)結(jié)構(gòu) 一節(jié))。

對(duì)象賦值的目標(biāo)對(duì)象可以包含于圓括號(hào)或方括號(hào)內(nèi),具體操作按以下方式遞歸地定義。

  • 如果目標(biāo)列表為后面不帶逗號(hào)、可以包含于圓括號(hào)內(nèi)的單一目標(biāo),則將對(duì)象賦值給該目標(biāo)。

  • Else:

    • 如果目標(biāo)列表包含一個(gè)帶有星號(hào)前綴的目標(biāo),這稱為“加星”目標(biāo):則該對(duì)象至少必須為與目標(biāo)列表項(xiàng)數(shù)減一相同項(xiàng)數(shù)的可迭代對(duì)象。 該可迭代對(duì)象前面的項(xiàng)將按從左至右的順序被賦值給加星目標(biāo)之前的目標(biāo)。 該可迭代對(duì)象末尾的項(xiàng)將被賦值給加星目標(biāo)之后的目標(biāo)。 然后該可迭代對(duì)象中剩余項(xiàng)的列表將被賦值給加星目標(biāo)(該列表可以為空)。

    • 否則:該對(duì)象必須為具有與目標(biāo)列表相同項(xiàng)數(shù)的可迭代對(duì)象,這些項(xiàng)將按從左至右的順序被賦值給對(duì)應(yīng)的目標(biāo)。

對(duì)象賦值給單個(gè)目標(biāo)的操作按以下方式遞歸地定義。

  • 如果目標(biāo)為標(biāo)識(shí)符(名稱):

    • 如果該名稱未出現(xiàn)于當(dāng)前代碼塊的 globalnonlocal 語句中:該名稱將被綁定到當(dāng)前局部命名空間的對(duì)象。

    • 否則:該名稱將被分別綁定到全局命名空間或由 nonlocal 所確定的外層命名空間的對(duì)象。

    如果該名稱已經(jīng)被綁定則將被重新綁定。 這可能導(dǎo)致之前被綁定到該名稱的對(duì)象的引用計(jì)數(shù)變?yōu)榱?,造成該?duì)象進(jìn)入釋放過程并調(diào)用其析構(gòu)器(如果存在)。

  • 如果該對(duì)象為屬性引用:引用中的原型表達(dá)式會(huì)被求值。 它應(yīng)該產(chǎn)生一個(gè)具有可賦值屬性的對(duì)象;否則將引發(fā) TypeError。 該對(duì)象會(huì)被要求將可賦值對(duì)象賦值給指定的屬性;如果它無法執(zhí)行賦值,則會(huì)引發(fā)異常 (通常應(yīng)為 AttributeError 但并不強(qiáng)制要求)。

    注意:如果該對(duì)象為類實(shí)例并且屬性引用在賦值運(yùn)算符的兩側(cè)都出現(xiàn),則右側(cè)表達(dá)式 a.x 可以訪問實(shí)例屬性或(如果實(shí)例屬性不存在)類屬性。 左側(cè)目標(biāo) a.x 將總是設(shè)定為實(shí)例屬性,并在必要時(shí)創(chuàng)建該實(shí)例屬性。 因此 a.x 的兩次出現(xiàn)不一定指向相同的屬性:如果右側(cè)表達(dá)式指向一個(gè)類屬性,則左側(cè)會(huì)創(chuàng)建一個(gè)新的實(shí)例屬性作為賦值的目標(biāo):

    class Cls:
        x = 3             # class variable
    inst = Cls()
    inst.x = inst.x + 1   # writes inst.x as 4 leaving Cls.x as 3
    

    此描述不一定作用于描述器屬性,例如通過 property() 創(chuàng)建的特征屬性。

  • 如果目標(biāo)為一個(gè)抽取項(xiàng):引用中的原型表達(dá)式會(huì)被求值。 它應(yīng)當(dāng)產(chǎn)生一個(gè)可變序列對(duì)象(例如列表)或一個(gè)映射對(duì)象(例如字典)。 接下來,該抽取表達(dá)式會(huì)被求值。

    如果原型為一個(gè)可變序列對(duì)象(例如列表),抽取應(yīng)產(chǎn)生一個(gè)整數(shù)。 如其為負(fù)值,則再加上序列長(zhǎng)度。 結(jié)果值必須為一個(gè)小于序列長(zhǎng)度的非負(fù)整數(shù),序列將把被賦值對(duì)象賦值給該整數(shù)指定索引號(hào)的項(xiàng)。 如果索引超出范圍,將會(huì)引發(fā) IndexError (給被抽取序列賦值不能向列表添加新項(xiàng))。

    如果原型為一個(gè)映射對(duì)象(例如字典),抽取必須具有與該映射的鍵類型相兼容的類型,然后映射中會(huì)創(chuàng)建一個(gè)將抽取映射到被賦值對(duì)象的鍵/值對(duì)。 這可以是替換一個(gè)現(xiàn)有鍵/值對(duì)并保持相同鍵值,也可以是插入一個(gè)新鍵/值對(duì)(如果具有相同值的鍵不存在)。

    對(duì)于用戶定義對(duì)象,會(huì)調(diào)用 __setitem__() 方法并附帶適當(dāng)?shù)膮?shù)。

  • 如果目標(biāo)為一個(gè)切片:引用中的原型表達(dá)式會(huì)被求值。 它應(yīng)當(dāng)產(chǎn)生一個(gè)可變序列對(duì)象(例如列表)。 被賦值對(duì)象應(yīng)當(dāng)是一個(gè)相同類型的序列對(duì)象。 接下來,下界與上界表達(dá)式如果存在的話將被求值;默認(rèn)值分別為零和序列長(zhǎng)度。 上下邊界值應(yīng)當(dāng)為整數(shù)。 如果某一邊界為負(fù)值,則會(huì)加上序列長(zhǎng)度。 求出的邊界會(huì)被裁剪至介于零和序列長(zhǎng)度的開區(qū)間中。 最后,將要求序列對(duì)象以被賦值序列的項(xiàng)替換該切片。 切片的長(zhǎng)度可能與被賦值序列的長(zhǎng)度不同,這會(huì)在目標(biāo)序列允許的情況下改變目標(biāo)序列的長(zhǎng)度。

CPython implementation detail: 在當(dāng)前實(shí)現(xiàn)中,目標(biāo)的句法被當(dāng)作與表達(dá)式的句法相同,無效的句法會(huì)在代碼生成階段被拒絕,導(dǎo)致不太詳細(xì)的錯(cuò)誤信息。

雖然賦值的定義意味著左手邊與右手邊的重疊是“同時(shí)”進(jìn)行的(例如 a, b = b, a 會(huì)交換兩個(gè)變量的值),但在賦值給變量的多項(xiàng)集 之內(nèi) 的重疊是從左至右進(jìn)行的,這有時(shí)會(huì)令人混淆。 例如,以下程序?qū)?huì)打印出 [0, 2]:

x = [0, 1]
i = 0
i, x[i] = 1, 2         # i is updated, then x[i] is updated
print(x)

參見

PEP 3132 - 擴(kuò)展的可迭代對(duì)象拆包

對(duì) *target 特性的規(guī)范說明。

7.2.1. 增強(qiáng)賦值語句?

增強(qiáng)賦值語句就是在單個(gè)語句中將二元運(yùn)算和賦值語句合為一體:

augmented_assignment_stmt ::=  augtarget augop (expression_list | yield_expression)
augtarget                 ::=  identifier | attributeref | subscription | slicing
augop                     ::=  "+=" | "-=" | "*=" | "@=" | "/=" | "http://=" | "%=" | "**="
                               | ">>=" | "<<=" | "&=" | "^=" | "|="

(請(qǐng)參閱 原型 一節(jié)了解最后三種符號(hào)的句法定義。)

增強(qiáng)賦值語句將對(duì)目標(biāo)和表達(dá)式列表求值(與普通賦值語句不同的是,前者不能為可迭代對(duì)象拆包),對(duì)兩個(gè)操作數(shù)相應(yīng)類型的賦值執(zhí)行指定的二元運(yùn)算,并將結(jié)果賦值給原始目標(biāo)。 目標(biāo)僅會(huì)被求值一次。

增強(qiáng)賦值語句例如 x += 1 可以改寫為 x = x + 1 獲得類似但并非完全等價(jià)的效果。 在增強(qiáng)賦值的版本中,x 僅會(huì)被求值一次。 而且,在可能的情況下,實(shí)際的運(yùn)算是 原地 執(zhí)行的,也就是說并不是創(chuàng)建一個(gè)新對(duì)象并將其賦值給目標(biāo),而是直接修改原對(duì)象。

不同于普通賦值,增強(qiáng)賦值會(huì)在對(duì)右手邊求值 之前 對(duì)左手邊求值。 例如,a[i] += f(x) 首先查找 a[i],然后對(duì) f(x) 求值并執(zhí)行加法操作,最后將結(jié)果寫回到 a[i]

除了在單個(gè)語句中賦值給元組和多個(gè)目標(biāo)的例外情況,增強(qiáng)賦值語句的賦值操作處理方式與普通賦值相同。 類似地,除了可能存在 原地 操作行為的例外情況,增強(qiáng)賦值語句執(zhí)行的二元運(yùn)算也與普通二元運(yùn)算相同。

對(duì)于屬性引用類目標(biāo),針對(duì)常規(guī)賦值的 關(guān)于類和實(shí)例屬性的警告 也同樣適用。

7.2.2. 帶標(biāo)注的賦值語句?

標(biāo)注 賦值就是在單個(gè)語句中將變量或?qū)傩詷?biāo)注和可選的賦值語句合為一體:

annotated_assignment_stmt ::=  augtarget ":" expression
                               ["=" (starred_expression | yield_expression)]

與普通 賦值語句 的差別在于僅允許單個(gè)目標(biāo)。

對(duì)于將簡(jiǎn)單名稱作為賦值目標(biāo)的情況,如果是在類或模塊作用域中,標(biāo)注會(huì)被求值并存入一個(gè)特殊的類或模塊屬性 __annotations__ 中,這是一個(gè)將變量名稱(如為私有會(huì)被移除)映射到被求值標(biāo)注的字典。 此屬性為可寫并且在類或模塊體開始執(zhí)行時(shí)如果靜態(tài)地發(fā)現(xiàn)標(biāo)注就會(huì)自動(dòng)創(chuàng)建。

對(duì)于將表達(dá)式作為賦值目標(biāo)的情況,如果是在類或模塊作用域中,標(biāo)注會(huì)被求值,但不會(huì)保存。

如果一個(gè)名稱在函數(shù)作用域內(nèi)被標(biāo)注,則該名稱為該作用域的局部變量。 標(biāo)注絕不會(huì)在函數(shù)作用域內(nèi)被求值和保存。

如果存在右手邊,帶標(biāo)注的賦值會(huì)在對(duì)標(biāo)注求值之前(如果適用)執(zhí)行實(shí)際的賦值。 如果用作表達(dá)式目標(biāo)的右手邊不存在,則解釋器會(huì)對(duì)目標(biāo)求值,但最后的 __setitem__()__setattr__() 調(diào)用除外。

參見

PEP 526 - 變量標(biāo)注的語法

該提議增加了標(biāo)注變量(也包括類變量和實(shí)例變量)類型的語法,而不再是通過注釋來進(jìn)行表達(dá)。

PEP 484 - 類型提示

該提議增加了 typing 模塊以便為類型標(biāo)注提供標(biāo)準(zhǔn)句法,可被靜態(tài)分析工具和 IDE 所使用。

在 3.8 版更改: 現(xiàn)在帶有標(biāo)注的賦值允許在右邊以同樣的表達(dá)式作為常規(guī)賦值。 之前,某些表達(dá)式(例如未加圓括號(hào)的元組表達(dá)式)會(huì)導(dǎo)致語法錯(cuò)誤。

7.3. assert 語句?

assert 語句是在程序中插入調(diào)試性斷言的簡(jiǎn)便方式:

assert_stmt ::=  "assert" expression ["," expression]

簡(jiǎn)單形式 assert expression 等價(jià)于

if __debug__:
    if not expression: raise AssertionError

擴(kuò)展形式 assert expression1, expression2 等價(jià)于

if __debug__:
    if not expression1: raise AssertionError(expression2)

以上等價(jià)形式假定 __debug__AssertionError 指向具有指定名稱的內(nèi)置變量。 在當(dāng)前實(shí)現(xiàn)中,內(nèi)置變量 __debug__ 在正常情況下為 True,在請(qǐng)求優(yōu)化時(shí)為 False (對(duì)應(yīng)命令行選項(xiàng)為 -O)。 如果在編譯時(shí)請(qǐng)求優(yōu)化,當(dāng)前代碼生成器不會(huì)為 assert 語句發(fā)出任何代碼。 請(qǐng)注意不必在錯(cuò)誤信息中包含失敗表達(dá)式的源代碼;它會(huì)被作為棧追蹤的一部分被顯示。

賦值給 __debug__ 是非法的。 該內(nèi)置變量的值會(huì)在解釋器啟動(dòng)時(shí)確定。

7.4. pass 語句?

pass_stmt ::=  "pass"

pass 是一個(gè)空操作 --- 當(dāng)它被執(zhí)行時(shí),什么都不發(fā)生。 它適合當(dāng)語法上需要一條語句但并不需要執(zhí)行任何代碼時(shí)用來臨時(shí)占位,例如:

def f(arg): pass    # a function that does nothing (yet)

class C: pass       # a class with no methods (yet)

7.5. del 語句?

del_stmt ::=  "del" target_list

刪除是遞歸定義的,與賦值的定義方式非常類似。 此處不再詳細(xì)說明,只給出一些提示。

目標(biāo)列表的刪除將從左至右遞歸地刪除每一個(gè)目標(biāo)。

名稱的刪除將從局部或全局命名空間中移除該名稱的綁定,具體作用域的確定是看該名稱是否有在同一代碼塊的 global 語句中出現(xiàn)。 如果該名稱未被綁定,將會(huì)引發(fā) NameError

屬性引用、抽取和切片的刪除會(huì)被傳遞給相應(yīng)的原型對(duì)象;刪除一個(gè)切片基本等價(jià)于賦值為一個(gè)右側(cè)類型的空切片(但即便這一點(diǎn)也是由切片對(duì)象決定的)。

在 3.2 版更改: 在之前版本中,如果一個(gè)名稱作為被嵌套代碼塊中的自由變量出現(xiàn),則將其從局部命名空間中刪除是非法的。

7.6. return 語句?

return_stmt ::=  "return" [expression_list]

return 在語法上只會(huì)出現(xiàn)于函數(shù)定義所嵌套的代碼,不會(huì)出現(xiàn)于類定義所嵌套的代碼。

如果提供了表達(dá)式列表,它將被求值,否則以 None 替代。

return 會(huì)離開當(dāng)前函數(shù)調(diào)用,并以表達(dá)式列表 (或 None) 作為返回值。

當(dāng) return 將控制流傳出一個(gè)帶有 finally 子句的 try 語句時(shí),該 finally 子句會(huì)先被執(zhí)行然后再真正離開該函數(shù)。

在一個(gè)生成器函數(shù)中,return 語句表示生成器已完成并將導(dǎo)致 StopIteration 被引發(fā)。 返回值(如果有的話)會(huì)被當(dāng)作一個(gè)參數(shù)用來構(gòu)建 StopIteration 并成為 StopIteration.value 屬性。

在一個(gè)異步生成器函數(shù)中,一個(gè)空的 return 語句表示異步生成器已完成并將導(dǎo)致 StopAsyncIteration 被引發(fā)。 一個(gè)非空的 return 語句在異步生成器函數(shù)中會(huì)導(dǎo)致語法錯(cuò)誤。

7.7. yield 語句?

yield_stmt ::=  yield_expression

yield 語句在語義上等同于 yield 表達(dá)式。 yield 語句可用來省略在使用等效的 yield 表達(dá)式語句時(shí)所必須的圓括號(hào)。 例如,以下 yield 語句

yield <expr>
yield from <expr>

等同于以下 yield 表達(dá)式語句

(yield <expr>)
(yield from <expr>)

yield 表達(dá)式和語句僅在定義 generator 函數(shù)時(shí)使用,并且僅被用于生成器函數(shù)的函數(shù)體內(nèi)部。 在函數(shù)定義中使用 yield 就足以使得該定義創(chuàng)建的是生成器函數(shù)而非普通函數(shù)。

有關(guān) yield 語義的完整細(xì)節(jié)請(qǐng)參看 yield 表達(dá)式 一節(jié)。

7.8. raise 語句?

raise_stmt ::=  "raise" [expression ["from" expression]]

If no expressions are present, raise re-raises the exception that is currently being handled, which is also known as the active exception. If there isn't currently an active exception, a RuntimeError exception is raised indicating that this is an error.

否則的話,raise 會(huì)將第一個(gè)表達(dá)式求值為異常對(duì)象。 它必須為 BaseException 的子類或?qū)嵗?如果它是一個(gè)類,當(dāng)需要時(shí)會(huì)通過不帶參數(shù)地實(shí)例化該類來獲得異常的實(shí)例。

異常的 類型 為異常實(shí)例的類, 為實(shí)例本身。

A traceback object is normally created automatically when an exception is raised and attached to it as the __traceback__ attribute, which is writable. You can create an exception and set your own traceback in one step using the with_traceback() exception method (which returns the same exception instance, with its traceback set to its argument), like so:

raise Exception("foo occurred").with_traceback(tracebackobj)

from 子句用于異常串連:如果有該子句,則第二個(gè) 表達(dá)式 必須為另一個(gè)異常類或?qū)嵗?如果第二個(gè)表達(dá)式是一個(gè)異常實(shí)例,它將作為可寫的 __cause__ 屬性被關(guān)聯(lián)到所引發(fā)的異常。 如果該表達(dá)式是一個(gè)異常類,這個(gè)類將被實(shí)例化且所生成的異常實(shí)例將作為 __cause__ 屬性被關(guān)聯(lián)到所引發(fā)的異常。 如果所引發(fā)的異常未被處理,則兩個(gè)異常都將被打印出來:

>>>
>>> try:
...     print(1 / 0)
... except Exception as exc:
...     raise RuntimeError("Something bad happened") from exc
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

A similar mechanism works implicitly if a new exception is raised when an exception is already being handled. An exception may be handled when an except or finally clause, or a with statement, is used. The previous exception is then attached as the new exception's __context__ attribute:

>>>
>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened")
...
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

異常串連可通過在 from 子句中指定 None 來顯式地加以抑制:

>>>
>>> try:
...     print(1 / 0)
... except:
...     raise RuntimeError("Something bad happened") from None
...
Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
RuntimeError: Something bad happened

有關(guān)異常的更多信息可在 異常 一節(jié)查看,有關(guān)處理異常的信息可在 try 語句 一節(jié)查看。

在 3.3 版更改: None 現(xiàn)在允許被用作 raise X from Y 中的 Y。

3.3 新版功能: 使用 __suppress_context__ 屬性來抑制異常上下文的自動(dòng)顯示。

在 3.11 版更改: If the traceback of the active exception is modified in an except clause, a subsequent raise statement re-raises the exception with the modified traceback. Previously, the exception was re-raised with the traceback it had when it was caught.

7.9. break 語句?

break_stmt ::=  "break"

break 在語法上只會(huì)出現(xiàn)于 forwhile 循環(huán)所嵌套的代碼,但不會(huì)出現(xiàn)于該循環(huán)內(nèi)部的函數(shù)或類定義所嵌套的代碼。

它會(huì)終結(jié)最近的外層循環(huán),如果循環(huán)有可選的 else 子句,也會(huì)跳過該子句。

如果一個(gè) for 循環(huán)被 break 所終結(jié),該循環(huán)的控制目標(biāo)會(huì)保持其當(dāng)前值。

當(dāng) break 將控制流傳出一個(gè)帶有 finally 子句的 try 語句時(shí),該 finally 子句會(huì)先被執(zhí)行然后再真正離開該循環(huán)。

7.10. continue 語句?

continue_stmt ::=  "continue"

continue 在語法上只會(huì)出現(xiàn)于 forwhile 循環(huán)所嵌套的代碼中,但不會(huì)出現(xiàn)于該循環(huán)內(nèi)部的函數(shù)或類定義中。 它會(huì)繼續(xù)執(zhí)行最近的外層循環(huán)的下一個(gè)輪次。

當(dāng) continue 將控制流傳出一個(gè)帶有 finally 子句的 try 語句時(shí),該 finally 子句會(huì)先被執(zhí)行然后再真正開始循環(huán)的下一個(gè)輪次。

7.11. import 語句?

import_stmt     ::=  "import" module ["as" identifier] ("," module ["as" identifier])*
                     | "from" relative_module "import" identifier ["as" identifier]
                     ("," identifier ["as" identifier])*
                     | "from" relative_module "import" "(" identifier ["as" identifier]
                     ("," identifier ["as" identifier])* [","] ")"
                     | "from" relative_module "import" "*"
module          ::=  (identifier ".")* identifier
relative_module ::=  "."* module | "."+

基本的 import 語句(不帶 from 子句)會(huì)分兩步執(zhí)行:

  1. 查找一個(gè)模塊,如果有必要還會(huì)加載并初始化模塊。

  2. 在局部命名空間中為 import 語句發(fā)生位置所處的作用域定義一個(gè)或多個(gè)名稱。

當(dāng)語句包含多個(gè)子句(由逗號(hào)分隔)時(shí)這兩個(gè)步驟將對(duì)每個(gè)子句分別執(zhí)行,如同這些子句被分成獨(dú)立的 import 語句一樣。

第一個(gè)步驟即查找和加載模塊的詳情 導(dǎo)入系統(tǒng) 一節(jié)中有更詳細(xì)的描述,其中也描述了可被導(dǎo)入的多種類型的包和模塊,以及可用于定制導(dǎo)入系統(tǒng)的所有鉤子對(duì)象。 請(qǐng)注意這一步如果失敗,則可能說明模塊無法找到,或者 是在初始化模塊,包括執(zhí)行模塊代碼期間發(fā)生了錯(cuò)誤。

如果成功獲取到請(qǐng)求的模塊,則可以通過以下三種方式一之在局部命名空間中使用它:

  • 模塊名后使用 as 時(shí),直接把 as 后的名稱與導(dǎo)入模塊綁定。

  • 如果沒有指定其他名稱,且被導(dǎo)入的模塊為最高層級(jí)模塊,則模塊的名稱將被綁定到局部命名空間作為對(duì)所導(dǎo)入模塊的引用。

  • 如果被導(dǎo)入的模塊 不是 最高層級(jí)模塊,則包含該模塊的最高層級(jí)包的名稱將被綁定到局部命名空間作為對(duì)該最高層級(jí)包的引用。 所導(dǎo)入的模塊必須使用其完整限定名稱來訪問而不能直接訪問。

from 形式使用的過程略微繁復(fù)一些:

  1. 查找 from 子句中指定的模塊,如有必要還會(huì)加載并初始化模塊;

  2. 對(duì)于 import 子句中指定的每個(gè)標(biāo)識(shí)符:

    1. 檢查被導(dǎo)入模塊是否有該名稱的屬性

    2. 如果沒有,嘗試導(dǎo)入具有該名稱的子模塊,然后再次檢查被導(dǎo)入模塊是否有該屬性

    3. 如果未找到該屬性,則引發(fā) ImportError。

    4. 否則的話,將對(duì)該值的引用存入局部命名空間,如果有 as 子句則使用其指定的名稱,否則使用該屬性的名稱

示例:

import foo                 # foo imported and bound locally
import foo.bar.baz         # foo, foo.bar, and foo.bar.baz imported, foo bound locally
import foo.bar.baz as fbb  # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as fbb
from foo.bar import baz    # foo, foo.bar, and foo.bar.baz imported, foo.bar.baz bound as baz
from foo import attr       # foo imported and foo.attr bound as attr

如果標(biāo)識(shí)符列表改為一個(gè)星號(hào) ('*'),則在模塊中定義的全部公有名稱都將按 import 語句所在的作用域被綁定到局部命名空間。

一個(gè)模塊所定義的 公有名稱 是由在模塊的命名空間中檢測(cè)一個(gè)名為 __all__ 的變量來確定的;如果有定義,它必須是一個(gè)字符串列表,其中的項(xiàng)為該模塊所定義或?qū)氲拿Q。 在 __all__ 中所給出的名稱都會(huì)被視為公有并且應(yīng)當(dāng)存在。 如果 __all__ 沒有被定義,則公有名稱的集合將包含在模塊的命名空間中找到的所有不以下劃線字符 ('_') 打頭的名稱。 __all__ 應(yīng)當(dāng)包括整個(gè)公有 API。 它的目標(biāo)是避免意外地導(dǎo)出不屬于 API 的一部分的項(xiàng)(例如在模塊內(nèi)部被導(dǎo)入和使用的庫(kù)模塊)。

通配符形式的導(dǎo)入 --- from module import * --- 僅在模塊層級(jí)上被允許。 嘗試在類或函數(shù)定義中使用它將引發(fā) SyntaxError

當(dāng)指定要導(dǎo)入哪個(gè)模塊時(shí),你不必指定模塊的絕對(duì)名稱。 當(dāng)一個(gè)模塊或包被包含在另一個(gè)包之中時(shí),可以在同一個(gè)最高層級(jí)包中進(jìn)行相對(duì)導(dǎo)入,而不必提及包名稱。 通過在 from 之后指定的模塊或包中使用前綴點(diǎn)號(hào),你可以在不指定確切名稱的情況下指明在當(dāng)前包層級(jí)結(jié)構(gòu)中要上溯多少級(jí)。 一個(gè)前綴點(diǎn)號(hào)表示是執(zhí)行導(dǎo)入的模塊所在的當(dāng)前包,兩個(gè)點(diǎn)號(hào)表示上溯一個(gè)包層級(jí)。 三個(gè)點(diǎn)號(hào)表示上溯兩級(jí),依此類推。 因此如果你執(zhí)行 from . import mod 時(shí)所處位置為 pkg 包內(nèi)的一個(gè)模塊,則最終你將導(dǎo)入 pkg.mod。 如果你執(zhí)行 from ..subpkg2 import mod 時(shí)所處位置為 pkg.subpkg1 則你將導(dǎo)入 pkg.subpkg2.mod。 有關(guān)相對(duì)導(dǎo)入的規(guī)范說明包含在 包相對(duì)導(dǎo)入 一節(jié)中。

importlib.import_module() 被提供用來為動(dòng)態(tài)地確定要導(dǎo)入模塊的應(yīng)用提供支持。

引發(fā)一個(gè) 審計(jì)事件 import 附帶參數(shù) module, filename, sys.path, sys.meta_path, sys.path_hooks。

7.11.1. future 語句?

future 語句 是一種針對(duì)編譯器的指令,指明某個(gè)特定模塊應(yīng)當(dāng)使用在特定的未來某個(gè) Python 發(fā)行版中成為標(biāo)準(zhǔn)特性的語法或語義。

future 語句的目的是使得向在語言中引入了不兼容改變的 Python 未來版本的遷移更為容易。 它允許基于每個(gè)模塊在某種新特性成為標(biāo)準(zhǔn)之前的發(fā)行版中使用該特性。

future_stmt ::=  "from" "__future__" "import" feature ["as" identifier]
                 ("," feature ["as" identifier])*
                 | "from" "__future__" "import" "(" feature ["as" identifier]
                 ("," feature ["as" identifier])* [","] ")"
feature     ::=  identifier

future 語句必須在靠近模塊開頭的位置出現(xiàn)。 可以出現(xiàn)在 future 語句之前行只有:

  • 模塊的文檔字符串(如果存在),

  • 注釋,

  • 空行,以及

  • 其他 future 語句。

唯一需要使用 future 語句的特性是 標(biāo)注 (參見 PEP 563)。

future 語句所啟用的所有歷史特性仍然為 Python 3 所認(rèn)可。 其中包括 absolute_import, division, generators, generator_stop, unicode_literals, print_function, nested_scopeswith_statement。 它們都已成為冗余項(xiàng),因?yàn)樗鼈兛偸菫橐褑⒂脿顟B(tài),保留它們只是為了向后兼容。

future 語句在編譯時(shí)會(huì)被識(shí)別并做特殊對(duì)待:對(duì)核心構(gòu)造語義的改變常常是通過生成不同的代碼來實(shí)現(xiàn)。 新的特性甚至可能會(huì)引入新的不兼容語法(例如新的保留字),在這種情況下編譯器可能需要以不同的方式來解析模塊。 這樣的決定不能推遲到運(yùn)行時(shí)方才作出。

對(duì)于任何給定的發(fā)布版本,編譯器要知道哪些特性名稱已被定義,如果某個(gè) future 語句包含未知的特性則會(huì)引發(fā)編譯時(shí)錯(cuò)誤。

直接運(yùn)行時(shí)的語義與任何 import 語句相同:存在一個(gè)后文將詳細(xì)說明的標(biāo)準(zhǔn)模塊 __future__,它會(huì)在執(zhí)行 future 語句時(shí)以通常的方式被導(dǎo)入。

相應(yīng)的運(yùn)行時(shí)語義取決于 future 語句所啟用的指定特性。

請(qǐng)注意以下語句沒有任何特別之處:

import __future__ [as name]

這并非 future 語句;它只是一條沒有特殊語義或語法限制的普通 import 語句。

在默認(rèn)情況下,通過對(duì)Code compiled by calls to the 內(nèi)置函數(shù) exec()compile() 的調(diào)用所編譯的代碼如果出現(xiàn)于一個(gè)包含有 future 語句的模塊 M 之中,就會(huì)使用 future 語句所關(guān)聯(lián)的語法和語義。 此行為可以通過 compile() 的可選參數(shù)加以控制 --- 請(qǐng)參閱該函數(shù)的文檔以了解詳情。

在交互式解釋器提示符中鍵入的 future 語句將在解釋器會(huì)話此后的交互中有效。 如果一個(gè)解釋器的啟動(dòng)使用了 -i 選項(xiàng)啟動(dòng),并傳入了一個(gè)腳本名稱來執(zhí)行,且該腳本包含 future 語句,它將在交互式會(huì)話開始執(zhí)行腳本之后保持有效。

參見

PEP 236 - 回到 __future__

有關(guān) __future__ 機(jī)制的最初提議。

7.12. global 語句?

global_stmt ::=  "global" identifier ("," identifier)*

global 語句是作用于整個(gè)當(dāng)前代碼塊的聲明。 它意味著所列出的標(biāo)識(shí)符將被解讀為全局變量。 要給全局變量賦值不可能不用到 global 關(guān)鍵字,不過自由變量也可以指向全局變量而不必聲明為全局變量。

global 語句中列出的名稱不得在同一代碼塊內(nèi)該 global 語句之前的位置中使用。

global 語句中列出的名稱不能被定義為形式參數(shù),也不能被作為 with 語句或 except 子句的目標(biāo),以及 for 循環(huán)的目標(biāo)列表、class 定義、函數(shù)定義、import 語句或變量標(biāo)注等等。

CPython implementation detail: 當(dāng)前的實(shí)現(xiàn)并未強(qiáng)制要求所有的上述限制,但程序不應(yīng)當(dāng)濫用這樣的自由,因?yàn)槲磥淼膶?shí)現(xiàn)可能會(huì)改為強(qiáng)制要求,并靜默地改變程序的含義。

程序員注意事項(xiàng): global 是對(duì)解析器的指令。 它僅對(duì)與 global 語句同時(shí)被解析的代碼起作用。 特別地,包含在提供給內(nèi)置 exec() 函數(shù)字符串或代碼對(duì)象中的 global 語句并不會(huì)影響 包含 該函數(shù)調(diào)用的代碼塊,而包含在這種字符串中的代碼也不會(huì)受到包含該函數(shù)調(diào)用的代碼中的 global 語句影響。 這同樣適用于 eval()compile() 函數(shù)。

7.13. nonlocal 語句?

nonlocal_stmt ::=  "nonlocal" identifier ("," identifier)*

nonlocal 語句會(huì)使得所列出的名稱指向之前在最近的包含作用域中綁定的除全局變量以外的變量。 這種功能很重要,因?yàn)榻壎ǖ哪J(rèn)行為是先搜索局部命名空間。 這個(gè)語句允許被封裝的代碼重新綁定局部作用域以外且非全局(模塊)作用域當(dāng)中的變量。

global 語句中列出的名稱不同,nonlocal 語句中列出的名稱必須指向之前存在于包含作用域之中的綁定(在這個(gè)應(yīng)當(dāng)用來創(chuàng)建新綁定的作用域不能被無歧義地確定)。

nonlocal 語句中列出的名稱不得與之前存在于局部作用域中的綁定相沖突。

參見

PEP 3104 - 訪問外層作用域中的名稱

有關(guān) nonlocal 語句的規(guī)范說明。