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 的語法定義,請參見 Primaries 部分。)

賦值語句計算表示式列表(請記住,這可以是一個表示式或以逗號分隔的列表,後者產生一個元組),並將單個結果物件從左到右分配給每個目標列表。

賦值的定義是根據目標(列表)的形式遞迴定義的。當目標是可變物件(屬性引用、下標或切片)的一部分時,可變物件必須最終執行賦值並決定其有效性,如果賦值不可接受,則可能會引發異常。 各種型別觀察到的規則和引發的異常在物件型別的定義中給出(請參見 標準型別層次結構 部分)。

將物件賦值給目標列表(可以選擇用括號或方括號括起來)的定義是遞迴定義的,如下所示。

  • 如果目標列表是單個目標,沒有尾隨逗號,可以選擇用括號括起來,則將物件分配給該目標。

  • 否則

    • 如果目標列表包含一個以星號為字首的目標,稱為“星號”目標: 該物件必須是可迭代物件,其專案數至少與目標列表中的目標數(減 1)相同。 可迭代物件的第一個專案從左到右分配給星號目標之前的目標。 可迭代物件的最後一個專案被分配給星號目標之後的目標。 然後將可迭代物件中剩餘專案的列表分配給星號目標(該列表可以為空)。

    • 否則:該物件必須是可迭代物件,其專案數與目標列表中的目標數相同,並且專案從左到右分配給相應的目標。

將物件賦值給單個目標的定義是遞迴定義的,如下所示。

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

    • 如果該名稱沒有出現在當前程式碼塊中的 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__ 中,該屬性是一個字典,將變數名(如果私有則會被改寫)對映到已評估的註解。如果靜態地找到註解,則此屬性是可寫的,並且在類或模組主體執行開始時會自動建立。

如果賦值目標不是簡單的(屬性、下標節點或帶括號的名稱),則如果在類或模組作用域中,則會評估註解,但不會儲存。

如果在函式作用域中註解了名稱,則該名稱是該作用域的本地名稱。註解永遠不會在函式作用域中被評估和儲存。

如果右側存在,則帶註解的賦值在評估註解之前執行實際賦值(如果適用)。如果表示式目標的右側不存在,則直譯器將評估目標,除了最後一次 __setitem__()__setattr__() 呼叫。

另請參閱

PEP 526 - 變數註解的語法

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

PEP 484 - 型別提示

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

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

7.3. 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 子句,則會跳過該子句。

如果透過 break 終止了 for 迴圈,則迴圈控制目標將保留其當前值。

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

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

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

  2. import 語句出現的範圍的區域性名稱空間中定義一個或多個名稱。

當語句包含多個子句(以逗號分隔)時,將分別對每個子句執行這兩個步驟,就像將子句分隔為單獨的 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() 來支援動態確定要載入的模組的應用程式。

使用引數 modulefilenamesys.pathsys.meta_pathsys.path_hooks 引發 審計事件 import

7.11.1. 未來語句

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

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

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

未來語句必須出現在模組的頂部附近。在未來語句之前出現的行只能是

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

  • 註釋、

  • 空行和

  • 其他未來語句。

唯一需要使用未來語句的功能是 annotations(請參閱 PEP 563)。

Python 3 仍然可以識別未來語句啟用的所有歷史功能。該列表包括 absolute_importdivisiongeneratorsgenerator_stopunicode_literalsprint_functionnested_scopeswith_statement。它們都是冗餘的,因為它們始終啟用,並且僅為了向後相容而保留。

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

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

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

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

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

import __future__ [as name]

這不是未來語句;它是一個普通的 import 語句,沒有特殊的語義或語法限制。

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

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

另請參閱

PEP 236 - 回到 __future__

__future__ 機制的原始提案。

7.12. global 語句

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

global 語句使列出的識別符號被解釋為全域性變數。如果沒有 global,將無法為全域性變數賦值,儘管自由變數可以引用全域性變數,而無需宣告為全域性變數。

global 語句適用於函式或類主體的整個範圍。如果在作用域中全域性宣告之前使用或賦值變數,則會引發 SyntaxError

程式設計師注意事項: global 是一個給解析器的指令。它僅適用於與 global 語句同時解析的程式碼。特別地,一個包含在字串或傳遞給內建 exec() 函式的程式碼物件中的 global 語句不會影響包含函式呼叫的程式碼塊,並且包含在這樣的字串中的程式碼不受包含函式呼叫的程式碼中的 global 語句的影響。同樣的情況適用於 eval()compile() 函式。

7.13. nonlocal 語句

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

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

nonlocal 語句適用於函式或類體的整個作用域。如果在作用域中在其 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 語句以及泛型類和函式的語法。