7. 簡單語句

簡單語句包含於單個邏輯行之內。 多個簡單語句可出現於由分號分隔的單個邏輯行中。 簡單語句的句法是:

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

7.1. 表示式語句

表示式語句被用於(主要是互動式地)計算和寫入一個值,或者(通常地)呼叫一個過程 (一個沒有返回有意義結果的函式;在 Python 中,過程的返回值為 None)。 表示式語句的其他用法也是允許且有用的。 表示式語句的句法是:

expression_stmt: starred_expression

一個表示式語句會對錶達式列表(也可能只是單個表示式)進行求值。

在互動模式下,如果值不是 None,它會透過內建的 repr() 函式被轉換為字串,其結果字串將單獨在一行被寫入到標準輸出(除非結果是 None,這樣就不會有過程呼叫的輸出了)。

7.2. 賦值語句

賦值語句用於將名稱(重)繫結到值,以及修改可變物件的屬性或成員項:

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

attributerefsubscriptionslicing 的句法定義請參閱 原語 一節。)

賦值語句會對錶達式列表(注意這可以為單個表示式或以逗號分隔的列表,後者會生成一個元組)求值,並將單個結果物件從左至右逐個賦給目標列表。

賦值是根據目標(列表)的形式遞迴定義的。 當目標是可變物件(屬性引用、訂閱或切片)的一部分時,該可變物件必須最終執行賦值並決定其有效性,如果賦值操作不可接受則可能引發異常。 各種型別所遵循的規則以及引發的異常在物件型別的定義中給出(參見 標準型別層級結構)。

將一個物件賦值給一個目標列表,任選地以圓括號或方括號括起,其遞迴定義如下。

  • 如果目標列表是單個目標且沒有末尾逗號,任選地在圓括號內,則物件會被賦給該目標。

  • 否則:

    • 如果目標列表包含一個帶星號字首的目標,稱為“加星”目標:則物件必須是一個可迭代物件,其擁有的項數至少要比目標列表中的目標數少一。 該可迭代物件的第一部分項會從左至右被賦給加星目標之前的目標。 該可迭代物件的最後一部分項會被賦給加星目標之後的目標。 然後該可迭代物件中剩餘項的列表會被賦給加星目標(該列表可以為空)。

    • 否則:物件必須是具有與目標列表中的目標數量相同的項的可迭代物件,並且這些項會從左到右分配給相應的目標。

將一個物件賦給單個目標的的遞迴定義如下。

  • 如果目標是識別符號(名稱):

    • 如果名稱未在當前程式碼塊的 globalnonlocal 語句中出現,則名稱會被繫結到當前本地名稱空間中的物件。

    • 否則:該名稱會被繫結到由 nonlocal 確定的全域性名稱空間或外層名稱空間。

    如果名稱已經被繫結,它將被重新繫結。 這可能導致之前被繫結到該名稱的物件的引用計數變為零,導致該物件被釋放,其析構器(如果存在)被呼叫。

  • 如果目標是一個屬性引用:則引用中的主表示式會被求值。 它應該產生一個具有可賦值屬性的物件;如果不是這種情況,則會引發 TypeError。 然後該物件會被要求將賦值物件賦給給定的屬性;如果它無法執行賦值,則會引發一個異常(通常但不一定是 AttributeError)。

    注意:如果物件是類例項並且屬性引用在賦值運算子的兩側都出現,則右側表示式 a.x 可以訪問例項屬性,或者(如果不存在例項屬性)類屬性。 左側目標 a.x 總是被設定為例項屬性,必要時會建立它。 因此,a.x 的兩次出現不一定指向相同的屬性:如果右側表示式指向一個類屬性,則左側會建立一個新的例項屬性作為賦值的目標。

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

    此描述不一定適用於描述器屬性,例如用 property() 建立的特性。

  • 如果目標是一個下標引用:則該引用中的主表示式會被求值。 它應該產生一個可變序列物件(例如列表)或一個對映物件(例如字典)。 接下來,會對下標表達式求值。

    如果主物件是一個可變序列物件(例如列表),下標必須產生一個整數。 如果為負數,則會加上序列的長度。 結果值必須是小於序列長度的非負整數,並且序列會被要求將賦值物件賦給該索引位置的項。 如果索引超出範圍,則會引發 IndexError(對下標序列的賦值不能向列表中新增新項)。

    如果主物件是一個對映物件(例如字典),下標必須是與該對映的鍵型別相容的型別,然後該對映會被要求建立一個鍵/值對,將下標對映到所賦的物件。 這可以替換具有相同鍵值的現有鍵/值對,或插入一個新的鍵/值對(如果沒有具有相同值的鍵存在)。

    對於使用者定義的物件,將使用適當的引數呼叫 __setitem__() 方法。

  • 如果目標是一個切片:則引用中的主表示式會被求值。 它應該產生一個可變序列物件(例如列表)。 被賦值的物件應該是一個相同型別的序列物件。 接下來,如果存在下界和上界表示式,則會對它們求值;預設值為零和序列的長度。 邊界值應為整數。 如果任一邊界值為負數,則會加上序列的長度。 最終的邊界值將被裁剪以位於零和序列長度(含)之間。 最後,序列物件會被要求用被賦值序列的項替換該切片。 切片的長度可能與被賦值序列的長度不同,從而在目標序列允許的情況下改變目標序列的長度。

CPython 實現細節:在當前實現中,目標的語法與表示式的語法相同,並且無效的語法在程式碼生成階段被拒絕,導致錯誤訊息不夠詳細。

雖然賦值的定義意味著左側和右側之間的重疊是“同時”的(例如,a, b = b, a 交換兩個變數),但在被賦值變數的集合*內部*的重疊是從左到右發生的,有時會導致混淆。 例如,以下程式列印 [0, 2]

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

參見

PEP 3132 - 擴充套件的可迭代物件解包

*target 功能的規範。

7.2.1. 增強賦值語句

增強賦值是將二元運算和賦值語句組合在單個語句中的寫法:

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

(關於最後三個符號的句法定義,請參閱 原語 一節。)

增強賦值會對目標(與普通賦值語句不同,它不能是解包)和表示式列表進行求值,對兩個運算元執行特定於賦值型別的二元運算,並將結果賦給原始目標。 目標只被求值一次。

一個像 x += 1 這樣的增強賦值語句可以重寫為 x = x + 1,以達到類似但不完全相同的效果。在增強版本中,x 只被求值一次。此外,在可能的情況下,實際操作是*就地*執行的,這意味著不是建立一個新物件並將其賦給目標,而是修改舊物件。

與普通賦值不同,增強賦值在求值右側*之前*先求值左側。例如,a[i] += f(x) 首先查詢 a[i],然後求值 f(x) 並執行加法,最後將結果寫回 a[i]

除了賦給元組和在單個語句中賦給多個目標外,增強賦值語句所做的賦值處理方式與普通賦值相同。同樣,除了可能的*就地*行為外,增強賦值執行的二元運算與普通的二元運算相同。

對於作為屬性引用的目標,關於類和例項屬性的注意事項同樣適用於常規賦值。

7.2.2. 帶註解的賦值語句

註解賦值是在單個語句中組合變數或屬性註解和可選賦值語句的寫法:

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

與普通賦值語句的區別在於,只允許單個目標。

如果賦值目標由一個未括在括號中的單個名稱組成,則該目標被視為“簡單”目標。對於簡單賦值目標,如果在類或模組作用域內,註解會被收集到一個延遲求值的註解作用域中。可以使用類或模組的 __annotations__ 屬性,或使用 annotationlib 模組中的工具來對註解進行求值。

如果賦值目標不是簡單的(屬性、下標節點或帶括號的名稱),則註解永遠不會被求值。

如果在函式作用域內對名稱進行註解,則該名稱對於該作用域是區域性的。註解永遠不會在函式作用域內被求值和儲存。

如果右側存在,帶註解的賦值會執行實際的賦值,就好像沒有註解存在一樣。如果對於表示式目標右側不存在,則直譯器會求值目標,除了最後的 __setitem__()__setattr__() 呼叫。

參見

PEP 526 - 變數註解的語法

該提案增加了用於註解變數型別(包括類變數和例項變數)的語法,而不是透過註釋來表達它們。

PEP 484 - 型別提示

該提案增加了 typing 模組,為型別註解提供了標準語法,可用於靜態分析工具和 IDE。

在 3.8 版更改: 現在,帶註解的賦值允許在右側使用與常規賦值相同的表示式。以前,一些表示式(如未加括號的元組表示式)會導致語法錯誤。

在 3.14 版更改: 註解現在在一個單獨的 註解作用域 中延遲求值。如果賦值目標不是簡單的,註解將永遠不會被求值。

7.3. assert 語句

Assert 語句是一種向程式中插入除錯斷言的簡便方法:

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

簡單形式 assert expression 等價於

if __debug__:
    if not expression: raise AssertionError

擴充套件形式 assert expression1, expression2 等價於

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

這些等價性假設 __debug__AssertionError 指的是具有這些名稱的內建變數。在當前實現中,內建變數 __debug__ 在正常情況下為 True,當請求最佳化時(命令列選項 -O)為 False。當前程式碼生成器在編譯時請求最佳化時不會為 assert 語句生成任何程式碼。請注意,不必在錯誤訊息中包含失敗表示式的原始碼;它將作為堆疊跟蹤的一部分顯示。

__debug__ 的賦值是非法的。內建變數的值在直譯器啟動時確定。

7.4. pass 語句

pass_stmt: "pass"

pass 是一個空操作——當它被執行時,什麼也不會發生。當語法上需要一個語句但不需要執行任何程式碼時,它可用作佔位符,例如:

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

刪除的遞迴定義與賦值的定義非常相似。這裡不詳述,只提供一些提示。

刪除目標列表會從左到右遞迴地刪除每個目標。

刪除名稱會從本地或全域性名稱空間中移除該名稱的繫結,具體取決於該名稱是否出現在同一程式碼塊的 global 語句中。嘗試刪除未繫結的名稱會引發 NameError 異常。

刪除屬性引用、訂閱和切片會被傳遞給相關的主物件;刪除切片通常等同於賦一個正確型別的空切片(但即使這也由被切片的物件決定)。

在 3.2 版更改: 以前,如果一個名稱在巢狀塊中作為自由變量出現,那麼從本地名稱空間中刪除該名稱是非法的。

7.6. return 語句

return_stmt: "return" [expression_list]

return 只能在語法上巢狀在函式定義中,不能巢狀在類定義中。

如果存在表示式列表,則對其求值,否則用 None 替代。

return 會帶著表示式列表(或 None)作為返回值離開當前的函式呼叫。

return 將控制權傳出帶有 finally 子句的 try 語句時,該 finally 子句會在真正離開函式之前執行。

在生成器函式中,return 語句表示生成器已完成,並將導致引發 StopIteration。返回值(如果有)用作構造 StopIteration 的引數,併成為 StopIteration.value 屬性。

在非同步生成器函式中,空的 return 語句表示非同步生成器已完成,並將導致引發 StopAsyncIteration。在非同步生成器函式中,非空的 return 語句是語法錯誤。

7.7. yield 語句

yield_stmt: yield_expression

yield 語句在語義上等同於 yield 表示式yield 語句可用於省略在等效的 yield 表示式語句中所需的括號。例如,yield 語句

yield <expr>
yield from <expr>

等價於 yield 表示式語句

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

Yield 表示式和語句僅在定義生成器函式時使用,並且僅在生成器函式的主體中使用。在函式定義中使用 yield 足以使該定義建立生成器函式而不是普通函式。

有關 yield 語義的完整詳細資訊,請參閱Yield 表示式部分。

7.8. raise 語句

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

如果不存在表示式,raise 會重新引發當前正在處理的異常,也稱為*活動異常*。如果當前沒有活動異常,則會引發 RuntimeError 異常,表示這是一個錯誤。

否則,raise 會將第一個表示式求值為異常物件。它必須是 BaseException 的子類或例項。如果它是一個類,則在需要時透過無引數例項化該類來獲取異常例項。

異常的型別是異常例項的類,是例項本身。

通常在引發異常時會自動建立一個回溯物件,並將其作為 __traceback__ 屬性附加到異常上。你可以使用 with_traceback() 異常方法一步建立異常並設定自己的回溯(該方法返回同一個異常例項,其回溯設定為其引數),如下所示:

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

from 子句用於異常鏈:如果給定,第二個*表示式*必須是另一個異常類或例項。如果第二個表示式是異常例項,它將作為 __cause__ 屬性(可寫)附加到引發的異常上。如果表示式是異常類,該類將被例項化,生成的異常例項將作為 __cause__ 屬性附加到引發的異常上。如果引發的異常未被處理,兩個異常都將被打印出來:

>>> 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>
    print(1 / 0)
          ~~^~~
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>
    raise RuntimeError("Something bad happened") from exc
RuntimeError: Something bad happened

當已經處理一個異常時引發新異常,類似的機制會隱式工作。當使用 exceptfinally 子句,或者 with 語句時,可以處理異常。前一個異常然後作為新異常的 __context__ 屬性附加:

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

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 4, in <module>
    raise RuntimeError("Something bad happened")
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

有關異常的更多資訊可以在異常部分找到,有關處理異常的資訊在try 語句部分。

在 3.3 版更改: None 現在被允許作為 raise X from Y 中的 Y

增加了 __suppress_context__ 屬性以抑制異常上下文的自動顯示。

在 3.11 版更改: 如果在 except 子句中修改了活動異常的回溯,後續的 raise 語句會用修改後的回溯重新引發該異常。以前,異常會用捕獲時的回溯重新引發。

7.9. break 語句

break_stmt: "break"

break 只能在語法上巢狀在 forwhile 迴圈中,但不能巢狀在該迴圈內的函式或類定義中。

它會終止最近的封閉迴圈,如果迴圈有可選的 else 子句,則跳過該子句。

如果 for 迴圈被 break 終止,迴圈控制目標會保持其當前值。

break 將控制權傳出帶有 finally 子句的 try 語句時,該 finally 子句在真正離開迴圈之前執行。

7.10. continue 語句

continue_stmt: "continue"

continue 只能在語法上巢狀在 forwhile 迴圈中,但不能巢狀在該迴圈內的函式或類定義中。它會繼續執行最近的封閉迴圈的下一次迭代。

continue 將控制權傳出帶有 finally 子句的 try 語句時,該 finally 子句在真正開始下一次迴圈迭代之前執行。

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

基本的匯入語句(沒有 from 子句)分兩步執行:

  1. 查詢模組,必要時載入並初始化它

  2. import 語句發生的範圍的本地名稱空間中定義一個或多個名稱。

當語句包含多個子句(用逗號分隔)時,這兩個步驟會為每個子句分別執行,就像子句被分成單獨的匯入語句一樣。

第一步,查詢和載入模組的詳細資訊在匯入系統一節中有更詳細的描述,該節還描述了可以匯入的各種包和模組型別,以及所有可用於自定義匯入系統的鉤子。請注意,此步驟中的失敗可能表示模組無法找到,*或者*在初始化模組時發生錯誤,其中包括執行模組的程式碼。

如果成功檢索到請求的模組,它將透過以下三種方式之一在本地名稱空間中可用:

  • 如果模組名稱後跟 as,則 as 後面的名稱將直接繫結到匯入的模組。

  • 如果沒有指定其他名稱,並且要匯入的模組是頂級模組,則模組的名稱將作為對匯入模組的引用繫結在本地名稱空間中。

  • 如果要匯入的模組*不是*頂級模組,則包含該模組的頂級包的名稱將作為對頂級包的引用繫結在本地名稱空間中。必須使用其完全限定名稱訪問匯入的模組,而不是直接訪問。

from 形式使用一個稍微複雜的過程:

  1. 查詢 from 子句中指定的模組,必要時載入並初始化它;

  2. 對於 import 子句中指定的每個識別符號:

    1. 檢查匯入的模組是否具有該名稱的屬性

    2. 如果沒有,嘗試匯入一個具有該名稱的子模組,然後再次檢查匯入的模組是否具有該屬性

    3. 如果未找到該屬性,則引發 ImportError

    4. 否則,對該值的引用將儲存在本地名稱空間中,如果存在 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

如果識別符號列表被星號('*')替換,則模組中定義的所有公共名稱都將繫結在 import 語句發生的範圍的本地名稱空間中。

模組定義的*公共名稱*透過檢查模組的名稱空間中名為 __all__ 的變數來確定;如果定義了,它必須是一個字串序列,這些字串是該模組定義或匯入的名稱。__all__ 中給出的名稱都被視為公共的,並且必須存在。如果未定義 __all__,則公共名稱集合包括在模組名稱空間中找到的所有不以下劃線字元('_')開頭的名稱。__all__ 應該包含整個公共 API。它旨在避免意外匯出不屬於 API 的項(例如在模組內匯入和使用的庫模組)。

萬用字元形式的匯入 — from module import * — 僅在模組級別允許。嘗試在類或函式定義中使用它將引發 SyntaxError

在指定要匯入哪個模組時,您不必指定模組的絕對名稱。當模組或包包含在另一個包中時,可以在同一個頂級包內進行相對匯入,而無需提及包名。透過在 from 後面的指定模組或包中使用前導點,您可以指定在不指定確切名稱的情況下向上遍歷當前包層次結構的層級。一個前導點表示執行匯入的模組所在的當前包。兩個點表示向上一級包。三個點是向上兩級,依此類推。因此,如果您從 pkg 包中的一個模組執行 from . import mod,那麼您最終將匯入 pkg.mod。如果您從 pkg.subpkg1 內執行 from ..subpkg2 import mod,您將匯入 pkg.subpkg2.mod。相對匯入的規範包含在包相對匯入部分。

importlib.import_module() 用於支援動態確定要載入的模組的應用程式。

引發一個審計事件 import,引數為 modulefilenamesys.pathsys.meta_pathsys.path_hooks

7.11.1. future 語句

future 語句是給編譯器的指令,指示特定模組應使用在未來指定 Python 版本中將可用的語法或語義進行編譯,屆時該功能將成為標準。

future 語句旨在簡化向引入不相容語言更改的未來 Python 版本的遷移。它允許在功能成為標準之前,在每個模組的基礎上使用新功能。

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

future 語句必須出現在模組的頂部附近。在 future 語句之前只能出現以下內容:

  • 模組文件字串(如果有),

  • 註釋,

  • 空行,和

  • 其他 future 語句。

唯一需要使用 future 語句的功能是 annotations(參見 PEP 563)。

Python 3 仍然識別所有由 future 語句啟用的歷史功能。該列表包括 absolute_importdivisiongeneratorsgenerator_stopunicode_literalsprint_functionnested_scopeswith_statement。它們都是多餘的,因為它們總是被啟用,僅為了向後相容而保留。

future 語句在編譯時被識別並特殊處理:核心構造語義的更改通常透過生成不同的程式碼來實現。甚至可能出現新功能引入新的不相容語法(例如新的保留字),在這種情況下,編譯器可能需要以不同的方式解析模組。這些決定不能推遲到執行時。

對於任何給定的版本,編譯器都知道定義了哪些功能名稱,如果 future 語句包含它不知道的功能,則會引發編譯時錯誤。

直接的執行時語義與任何匯入語句相同:有一個標準模組 __future__,稍後描述,它將在 future 語句執行時以通常的方式匯入。

有趣的執行時語義取決於 future 語句啟用的特定功能。

請注意,以下語句沒有什麼特別之處:

import __future__ [as name]

這不是 future 語句;這是一個普通的匯入語句,沒有特殊的語義或語法限制。

在包含 future 語句的模組 M 中,透過呼叫內建函式 exec()compile() 編譯的程式碼,預設將使用與 future 語句相關的新語法或語義。這可以透過 compile() 的可選引數來控制——有關詳細資訊,請參閱該函式的文件。

在互動式直譯器提示符下鍵入的 future 語句將在直譯器會話的其餘部分生效。如果直譯器以 -i 選項啟動,並傳遞一個要執行的指令碼名稱,並且該指令碼包含 future 語句,則該語句將在指令碼執行後啟動的互動式會話中生效。

參見

PEP 236 - 回到 __future__

__future__ 機制的原始提案。

7.12. global 語句

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

global 語句使列出的識別符號被解釋為全域性變數。沒有 global 就不可能給全域性變數賦值,儘管自由變數可以在未宣告為全域性的情況下引用全域性變數。

global 語句適用於整個當前作用域(模組、函式體或類定義)。如果在作用域中,變數在其全域性宣告之前被使用或賦值,則會引發 SyntaxError

在模組級別,所有變數都是全域性的,因此 global 語句沒有效果。但是,變數仍必須在其 global 宣告之前不被使用或賦值。此要求在互動式提示符(REPL)中被放寬。

程式設計師注意:global 是對解析器的指令。它僅適用於與 global 語句同時解析的程式碼。特別是,包含在提供給內建 exec() 函式的字串或程式碼物件中的 global 語句不會影響*包含*該函式呼叫的程式碼塊,並且此類字串中包含的程式碼不受包含該函式呼叫的程式碼中的 global 語句的影響。同樣適用於 eval()compile() 函式。

7.13. nonlocal 語句

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

當函式或類的定義巢狀(封閉)在其他函式的定義中時,其非區域性作用域是封閉函式的區域性作用域。nonlocal 語句使列出的識別符號引用先前在非區域性作用域中繫結的名稱。它允許封裝的程式碼重新繫結此類非區域性識別符號。如果一個名稱在多個非區域性作用域中被繫結,則使用最近的繫結。如果一個名稱在任何非區域性作用域中都未被繫結,或者沒有非區域性作用域,則會引發 SyntaxError

nonlocal 語句適用於函式或類體的整個作用域。如果在作用域中,變數在其非區域性宣告之前被使用或賦值,則會引發 SyntaxError

參見

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

nonlocal 語句的規範。

程式設計師注意:nonlocal 是對解析器的指令,僅適用於與其一起解析的程式碼。請參閱 global 語句的註釋。

7.14. type 語句

type_stmt: 'type' identifier [type_params] "=" expression

type 語句宣告一個類型別名,它是 typing.TypeAliasType 的例項。

例如,以下語句建立一個類型別名:

type Point = tuple[float, float]

這段程式碼大致等同於:

annotation-def VALUE_OF_Point():
    return tuple[float, float]
Point = typing.TypeAliasType("Point", VALUE_OF_Point())

annotation-def 表示一個 註解作用域,其行為大多像一個函式,但有一些細微的差異。

類型別名的值在註解作用域中求值。它在建立類型別名時不會被求值,而只有在透過類型別名的 __value__ 屬性訪問值時才會被求值(參見 延遲求值)。這允許類型別名引用尚未定義的名稱。

透過在名稱後新增型別形參列表,可以使類型別名成為泛型。更多資訊請參見泛型類型別名

type 是一個軟關鍵字

3.12 新版功能.

參見

PEP 695 - 型別形參語法

引入了 type 語句以及泛型類和函式的語法。