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
(有關 attributeref、subscription 和 slicing 的語法定義,請參見 Primaries 部分。)
賦值語句計算表示式列表(請記住,這可以是一個表示式或以逗號分隔的列表,後者產生一個元組),並將單個結果物件從左到右分配給每個目標列表。
賦值的定義是根據目標(列表)的形式遞迴定義的。當目標是可變物件(屬性引用、下標或切片)的一部分時,可變物件必須最終執行賦值並決定其有效性,如果賦值不可接受,則可能會引發異常。 各種型別觀察到的規則和引發的異常在物件型別的定義中給出(請參見 標準型別層次結構 部分)。
將物件賦值給目標列表(可以選擇用括號或方括號括起來)的定義是遞迴定義的,如下所示。
如果目標列表是單個目標,沒有尾隨逗號,可以選擇用括號括起來,則將物件分配給該目標。
否則
如果目標列表包含一個以星號為字首的目標,稱為“星號”目標: 該物件必須是可迭代物件,其專案數至少與目標列表中的目標數(減 1)相同。 可迭代物件的第一個專案從左到右分配給星號目標之前的目標。 可迭代物件的最後一個專案被分配給星號目標之後的目標。 然後將可迭代物件中剩餘專案的列表分配給星號目標(該列表可以為空)。
否則:該物件必須是可迭代物件,其專案數與目標列表中的目標數相同,並且專案從左到右分配給相應的目標。
將物件賦值給單個目標的定義是遞迴定義的,如下所示。
如果目標是識別符號(名稱)
如果該名稱沒有出現在當前程式碼塊中的
global
或nonlocal
語句中:該名稱繫結到當前區域性名稱空間中的物件。否則:該名稱分別繫結到全域性名稱空間或由
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__()
呼叫。
另請參閱
在 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
足以使該定義建立一個生成器函式,而不是普通函式。
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
如果在處理異常時引發新異常,則類似機制會隱式工作。當使用 except
或 finally
子句,或 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
只能在語法上巢狀在 for
或 while
迴圈中,但不能巢狀在該迴圈內的函式或類定義中。
它會終止最近的封閉迴圈,如果迴圈有可選的 else
子句,則會跳過該子句。
如果透過 break
終止了 for
迴圈,則迴圈控制目標將保留其當前值。
當 break
將控制權傳遞出帶有 finally
子句的 try
語句時,會在真正離開迴圈之前執行該 finally
子句。
7.10. continue
語句¶
continue_stmt ::= "continue"
continue
只能在語法上巢狀在 for
或 while
迴圈中,但不能巢狀在該迴圈內的函式或類定義中。它會繼續最近的封閉迴圈的下一個迴圈。
當 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
子句)分兩步執行
查詢模組,並在必要時載入和初始化它
在
import
語句出現的範圍的區域性名稱空間中定義一個或多個名稱。
當語句包含多個子句(以逗號分隔)時,將分別對每個子句執行這兩個步驟,就像將子句分隔為單獨的 import 語句一樣。
第一步,即查詢和載入模組的詳細資訊,在關於匯入系統的章節中有更詳細的描述。該章節還描述了可以匯入的各種型別的包和模組,以及可用於自定義匯入系統的所有鉤子。請注意,此步驟中的失敗可能表示模組無法找到,或在初始化模組(包括執行模組的程式碼)時發生錯誤。
如果成功檢索到請求的模組,則將以三種方式之一使其在本地名稱空間中可用。
如果模組名稱後跟
as
,則as
後面的名稱將直接繫結到匯入的模組。如果未指定其他名稱,並且要匯入的模組是頂級模組,則模組的名稱將在本地名稱空間中繫結為對匯入模組的引用。
如果要匯入的模組不是頂級模組,則包含該模組的頂級包的名稱將在本地名稱空間中繫結為對頂級包的引用。必須使用其完整的限定名稱而不是直接訪問匯入的模組。
from
形式使用稍微複雜的過程。
查詢
from
子句中指定的模組,並在必要時載入和初始化它;對於
import
子句中指定的每個識別符號:檢查匯入的模組是否具有該名稱的屬性。
如果否,則嘗試匯入具有該名稱的子模組,然後再次檢查匯入的模組是否具有該屬性。
如果找不到該屬性,則引發
ImportError
。否則,將使用
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()
來支援動態確定要載入的模組的應用程式。
使用引數 module
、filename
、sys.path
、sys.meta_path
、sys.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_import
、division
、generators
、generator_stop
、unicode_literals
、print_function
、nested_scopes
和 with_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
異常。
程式設計師注意事項: 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
語句以及泛型類和函式的語法。