新聞中心
8. 復(fù)合語(yǔ)句
復(fù)合語(yǔ)句是包含其它語(yǔ)句(語(yǔ)句組)的語(yǔ)句;它們會(huì)以某種方式影響或控制所包含其它語(yǔ)句的執(zhí)行。 通常,復(fù)合語(yǔ)句會(huì)跨越多行,雖然在某些簡(jiǎn)單形式下整個(gè)復(fù)合語(yǔ)句也可能包含于一行之內(nèi)。

在浪卡子等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站建設(shè)、網(wǎng)站制作 網(wǎng)站設(shè)計(jì)制作定制網(wǎng)站制作,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),全網(wǎng)整合營(yíng)銷推廣,外貿(mào)網(wǎng)站建設(shè),浪卡子網(wǎng)站建設(shè)費(fèi)用合理。
if, while 和 for 語(yǔ)句用來(lái)實(shí)現(xiàn)傳統(tǒng)的控制流程構(gòu)造。 try 語(yǔ)句為一組語(yǔ)句指定異常處理和/和清理代碼,而 with 語(yǔ)句允許在一個(gè)代碼塊周圍執(zhí)行初始化和終結(jié)化代碼。 函數(shù)和類定義在語(yǔ)法上也屬于復(fù)合語(yǔ)句。
一條復(fù)合語(yǔ)句由一個(gè)或多個(gè)‘子句’組成。 一個(gè)子句則包含一個(gè)句頭和一個(gè)‘句體’。 特定復(fù)合語(yǔ)句的子句頭都處于相同的縮進(jìn)層級(jí)。 每個(gè)子句頭以一個(gè)作為唯一標(biāo)識(shí)的關(guān)鍵字開(kāi)始并以一個(gè)冒號(hào)結(jié)束。 子句體是由一個(gè)子句控制的一組語(yǔ)句。 子句體可以是在子句頭的冒號(hào)之后與其同處一行的一條或由分號(hào)分隔的多條簡(jiǎn)單語(yǔ)句,或者也可以是在其之后縮進(jìn)的一行或多行語(yǔ)句。 只有后一種形式的子句體才能包含嵌套的復(fù)合語(yǔ)句;以下形式是不合法的,這主要是因?yàn)闊o(wú)法分清某個(gè)后續(xù)的 else 子句應(yīng)該屬于哪個(gè) if 子句:
if test1: if test2: print(x)
還要注意的是在這種情形下分號(hào)的綁定比冒號(hào)更緊密,因此在以下示例中,所有 print() 調(diào)用或者都不執(zhí)行,或者都執(zhí)行:
if x < y < z: print(x); print(y); print(z)
總結(jié):
- compound_stmt ::= if_stmt
- | while_stmt
- | for_stmt
- | try_stmt
- | with_stmt
- | match_stmt
- | funcdef
- | classdef
- | async_with_stmt
- | async_for_stmt
- | async_funcdef
- suite ::= stmt_list NEWLINE | NEWLINE INDENT statement+ DEDENT
- statement ::= stmt_list NEWLINE | compound_stmt
- stmt_list ::= simple_stmt (";" simple_stmt)* [";"]
請(qǐng)注意語(yǔ)句總是以 NEWLINE 結(jié)束,之后可能跟隨一個(gè) DEDENT。 還要注意可選的后續(xù)子句總是以一個(gè)不能作為語(yǔ)句開(kāi)頭的關(guān)鍵字作為開(kāi)頭,因此不會(huì)產(chǎn)生歧義(‘懸空的 else’問(wèn)題在 python 中是通過(guò)要求嵌套的 if 語(yǔ)句必須縮進(jìn)來(lái)解決的)。
為了保證清晰,以下各節(jié)中語(yǔ)法規(guī)則采用將每個(gè)子句都放在單獨(dú)行中的格式。
8.1. if 語(yǔ)句
if 語(yǔ)句用于有條件的執(zhí)行:
- if_stmt ::= "if" assignment_expression ":" suite
- ("elif" assignment_expression ":" suite)*
- ["else" ":" suite]
它通過(guò)對(duì)表達(dá)式逐個(gè)求值直至找到一個(gè)真值(請(qǐng)參閱 布爾運(yùn)算 了解真值與假值的定義)在子句體中選擇唯一匹配的一個(gè);然后執(zhí)行該子句體(而且 if 語(yǔ)句的其他部分不會(huì)被執(zhí)行或求值)。 如果所有表達(dá)式均為假值,則如果 else 子句體如果存在就會(huì)被執(zhí)行。
8.2. while 語(yǔ)句
while 語(yǔ)句用于在表達(dá)式保持為真的情況下重復(fù)地執(zhí)行:
- while_stmt ::= "while" assignment_expression ":" suite
- ["else" ":" suite]
這將重復(fù)地檢驗(yàn)表達(dá)式,并且如果其值為真就執(zhí)行第一個(gè)子句體;如果表達(dá)式值為假(這可能在第一次檢驗(yàn)時(shí)就發(fā)生)則如果 else 子句體存在就會(huì)被執(zhí)行并終止循環(huán)。
第一個(gè)子句體中的 break 語(yǔ)句在執(zhí)行時(shí)將終止循環(huán)且不執(zhí)行 else 子句體。 第一個(gè)子句體中的 continue 語(yǔ)句在執(zhí)行時(shí)將跳過(guò)子句體中的剩余部分并返回檢驗(yàn)表達(dá)式。
8.3. for 語(yǔ)句
for 語(yǔ)句用于對(duì)序列(例如字符串、元組或列表)或其他可迭代對(duì)象中的元素進(jìn)行迭代:
- for_stmt ::= "for" target_list "in" starred_list ":" suite
- ["else" ":" suite]
The starred_list expression is evaluated once; it should yield an iterable object. An iterator is created for that iterable. The first item provided by the iterator is then assigned to the target list using the standard rules for assignments (see 賦值語(yǔ)句), and the suite is executed. This repeats for each item provided by the iterator. When the iterator is exhausted, the suite in the else clause, if present, is executed, and the loop terminates.
第一個(gè)子句體中的 break 語(yǔ)句在執(zhí)行時(shí)將終止循環(huán)且不執(zhí)行 else 子句體。 第一個(gè)子句體中的 continue 語(yǔ)句在執(zhí)行時(shí)將跳過(guò)子句體中的剩余部分并轉(zhuǎn)往下一項(xiàng)繼續(xù)執(zhí)行,或者在沒(méi)有下一項(xiàng)時(shí)轉(zhuǎn)往 else 子句執(zhí)行。
for 循環(huán)會(huì)對(duì)目標(biāo)列表中的變量進(jìn)行賦值。 這將覆蓋之前對(duì)這些變量的所有賦值,包括在 for 循環(huán)體中的賦值:
for i in range(10):print(i)i = 5 # this will not affect the for-loop# because i will be overwritten with the next# index in the range
目標(biāo)列表中的名稱在循環(huán)結(jié)束時(shí)不會(huì)被刪除,但如果序列為空,則它們根本不會(huì)被循環(huán)所賦值。 提示:內(nèi)置函數(shù) range() 會(huì)返回一個(gè)可迭代的整數(shù)序列,適用于模擬 Pascal 中的 for i := a to b do 這種效果;例如 list(range(3)) 會(huì)返回列表 [0, 1, 2]。
在 3.11 版更改: Starred elements are now allowed in the expression list.
8.4. try 語(yǔ)句
The try statement specifies exception handlers and/or cleanup code for a group of statements:
- try_stmt ::= try1_stmt | try2_stmt | try3_stmt
- try1_stmt ::= "try" ":" suite
- ("except" [expression ["as" identifier]] ":" suite)+
- ["else" ":" suite]
- ["finally" ":" suite]
- try2_stmt ::= "try" ":" suite
- ("except" "*" expression ["as" identifier] ":" suite)+
- ["else" ":" suite]
- ["finally" ":" suite]
- try3_stmt ::= "try" ":" suite
- "finally" ":" suite
有關(guān)異常的更多信息可以在 異常 一節(jié)找到,有關(guān)使用 raise 語(yǔ)句生成異常的信息可以在 raise 語(yǔ)句 一節(jié)找到。
8.4.1. except clause
The except clause(s) specify one or more exception handlers. When no exception occurs in the try clause, no exception handler is executed. When an exception occurs in the try suite, a search for an exception handler is started. This search inspects the except clauses in turn until one is found that matches the exception. An expression-less except clause, if present, must be last; it matches any exception. For an except clause with an expression, that expression is evaluated, and the clause matches the exception if the resulting object is “compatible” with the exception. An object is compatible with an exception if the object is the class or a non-virtual base class of the exception object, or a tuple containing an item that is the class or a non-virtual base class of the exception object.
If no except clause matches the exception, the search for an exception handler continues in the surrounding code and on the invocation stack. 1
If the evaluation of an expression in the header of an except clause raises an exception, the original search for a handler is canceled and a search starts for the new exception in the surrounding code and on the call stack (it is treated as if the entire try statement raised the exception).
When a matching except clause is found, the exception is assigned to the target specified after the as keyword in that except clause, if present, and the except clause’s suite is executed. All except clauses must have an executable block. When the end of this block is reached, execution continues normally after the entire try statement. (This means that if two nested handlers exist for the same exception, and the exception occurs in the try clause of the inner handler, the outer handler will not handle the exception.)
When an exception has been assigned using as target, it is cleared at the end of the except clause. This is as if
except E as N:foo
被轉(zhuǎn)寫為
except E as N:try:foofinally:del N
This means the exception must be assigned to a different name to be able to refer to it after the except clause. Exceptions are cleared because with the traceback attached to them, they form a reference cycle with the stack frame, keeping all locals in that frame alive until the next garbage collection occurs.
Before an except clause’s suite is executed, details about the exception are stored in the sys module and can be accessed via sys.exc_info(). sys.exc_info() returns a 3-tuple consisting of the exception class, the exception instance and a traceback object (see section 標(biāo)準(zhǔn)類型層級(jí)結(jié)構(gòu)) identifying the point in the program where the exception occurred. The details about the exception accessed via sys.exc_info() are restored to their previous values when leaving an exception handler:
>>> print(sys.exc_info())(None, None, None)>>> try:... raise TypeError... except:... print(sys.exc_info())... try:... raise ValueError... except:... print(sys.exc_info())... print(sys.exc_info())...(, TypeError(), ) (, ValueError(), ) (, TypeError(), ) >>> print(sys.exc_info())(None, None, None)
8.4.2. except* clause
The except* clause(s) are used for handling ExceptionGroups. The exception type for matching is interpreted as in the case of except, but in the case of exception groups we can have partial matches when the type matches some of the exceptions in the group. This means that multiple except* clauses can execute, each handling part of the exception group. Each clause executes at most once and handles an exception group of all matching exceptions. Each exception in the group is handled by at most one except* clause, the first that matches it.
>>> try:... raise ExceptionGroup("eg",... [ValueError(1), TypeError(2), OSError(3), OSError(4)])... except* TypeError as e:... print(f'caught {type(e)} with nested {e.exceptions}')... except* OSError as e:... print(f'caught {type(e)} with nested {e.exceptions}')...caughtwith nested (TypeError(2),) caughtwith nested (OSError(3), OSError(4)) + Exception Group Traceback (most recent call last):| File "", line 2, in | ExceptionGroup: eg+-+---------------- 1 ----------------| ValueError: 1+------------------------------------
Any remaining exceptions that were not handled by any except* clause are re-raised at the end, combined into an exception group along with all exceptions that were raised from within except* clauses.
If the raised exception is not an exception group and its type matches one of the except* clauses, it is caught and wrapped by an exception group with an empty message string.
>>> try:... raise BlockingIOError... except* BlockingIOError as e:... print(repr(e))...ExceptionGroup('', (BlockingIOError()))
An except* clause must have a matching type, and this type cannot be a subclass of BaseExceptionGroup. It is not possible to mix except and except* in the same try. break, continue and return cannot appear in an except* clause.
8.4.3. else clause
如果控制流離開(kāi) try 子句體時(shí)沒(méi)有引發(fā)異常,并且沒(méi)有執(zhí)行 return, continue 或 break 語(yǔ)句,可選的 else 子句將被執(zhí)行。 else 語(yǔ)句中的異常不會(huì)由之前的 except 子句處理。
8.4.4. finally clause
If finally is present, it specifies a ‘cleanup’ handler. The try clause is executed, including any except and else clauses. If an exception occurs in any of the clauses and is not handled, the exception is temporarily saved. The finally clause is executed. If there is a saved exception it is re-raised at the end of the finally clause. If the finally clause raises another exception, the saved exception is set as the context of the new exception. If the finally clause executes a return, break or continue statement, the saved exception is discarded:
>>> def f():... try:... 1/0... finally:... return 42...>>> f()42
The exception information is not available to the program during execution of the finally clause.
When a return, break or continue statement is executed in the try suite of a try…finally statement, the finally clause is also executed ‘on the way out.’
The return value of a function is determined by the last return statement executed. Since the finally clause always executes, a return statement executed in the finally clause will always be the last one executed:
>>> def foo():... try:... return 'try'... finally:... return 'finally'...>>> foo()'finally'
在 3.8 版更改: Prior to Python 3.8, a continue statement was illegal in the finally clause due to a problem with the implementation.
8.5. with 語(yǔ)句
with 語(yǔ)句用于包裝帶有使用上下文管理器 (參見(jiàn) with 語(yǔ)句上下文管理器 一節(jié)) 定義的方法的代碼塊的執(zhí)行。 這允許對(duì)普通的 try…except…finally 使用模式進(jìn)行封裝以方便地重用。
- with_stmt ::= "with" ( "(" with_stmt_contents ","? ")" | with_stmt_contents ) ":" suite
- with_stmt_contents ::= with_item ("," with_item)*
- with_item ::= expression ["as" target]
帶有一個(gè)“項(xiàng)目”的 with 語(yǔ)句的執(zhí)行過(guò)程如下:
-
對(duì)上下文表達(dá)式(在 with_item 中給出的表達(dá)式)進(jìn)行求值來(lái)獲得上下文管理器。
-
載入上下文管理器的
__enter__()以便后續(xù)使用。 -
載入上下文管理器的
__exit__()以便后續(xù)使用。 -
發(fā)起調(diào)用上下文管理器的
__enter__()方法。 -
如果 with 語(yǔ)句中包含一個(gè)目標(biāo),來(lái)自
__enter__()的返回值將被賦值給它。備注
with 語(yǔ)句會(huì)保證如果
__enter__()方法返回時(shí)未發(fā)生錯(cuò)誤,則__exit__()將總是被調(diào)用。 因此,如果在對(duì)目標(biāo)列表賦值期間發(fā)生錯(cuò)誤,則會(huì)將其視為在語(yǔ)句體內(nèi)部發(fā)生的錯(cuò)誤。 參見(jiàn)下面的第 6 步。 -
執(zhí)行語(yǔ)句體。
-
發(fā)起調(diào)用上下文管理器的
__exit__()方法。 如果語(yǔ)句體的退出是由異常導(dǎo)致的,則其類型、值和回溯信息將被作為參數(shù)傳遞給__exit__()。 否則的話,將提供三個(gè) None 參數(shù)。如果語(yǔ)句體的退出是由異常導(dǎo)致的,并且來(lái)自
__exit__()方法的返回值為假,則該異常會(huì)被重新引發(fā)。 如果返回值為真,則該異常會(huì)被抑制,并會(huì)繼續(xù)執(zhí)行 with 語(yǔ)句之后的語(yǔ)句。如果語(yǔ)句體由于異常以外的任何原因退出,則來(lái)自
__exit__()的返回值會(huì)被忽略,并會(huì)在該類退出正常的發(fā)生位置繼續(xù)執(zhí)行。
以下代碼:
with EXPRESSION as TARGET:SUITE
在語(yǔ)義上等價(jià)于:
manager = (EXPRESSION)enter = type(manager).__enter__exit = type(manager).__exit__value = enter(manager)hit_except = Falsetry:TARGET = valueSUITEexcept:hit_except = Trueif not exit(manager, *sys.exc_info()):raisefinally:if not hit_except:exit(manager, None, None, None)
如果有多個(gè)項(xiàng)目,則會(huì)視作存在多個(gè) with 語(yǔ)句嵌套來(lái)處理多個(gè)上下文管理器:
with A() as a, B() as b:SUITE
在語(yǔ)義上等價(jià)于:
with A() as a:with B() as b:SUITE
也可以用圓括號(hào)包圍的多行形式的多項(xiàng)目上下文管理器。例如:
with (A() as a,B() as b,):SUITE
在 3.1 版更改: 支持多個(gè)上下文表達(dá)式。
在 3.10 版更改: Support for using grouping parentheses to break the statement in multiple lines.
參見(jiàn)
PEP 343 - “with” 語(yǔ)句
Python with 語(yǔ)句的規(guī)范描述、背景和示例。
8.6. match 語(yǔ)句
3.10 新版功能.
匹配語(yǔ)句用于進(jìn)行模式匹配。語(yǔ)法如下:
- match_stmt ::= 'match' subject_expr ":" NEWLINE INDENT case_block+ DEDENT
- subject_expr ::=
star_named_expression","star_named_expressions?- |
named_expression- case_block ::= 'case' patterns [guard] ":"
block
備注
本節(jié)使用單引號(hào)來(lái)表示 軟關(guān)鍵字。
模式匹配接受一個(gè)模式作為輸入(跟在 case 后),一個(gè)目標(biāo)值(跟在 match 后)。該模式(可能包含子模式)將與目標(biāo)值進(jìn)行匹配。輸出是:
-
匹配成功或失?。ㄒ脖环Q為模式成功或失敗)。
-
可能將匹配的值綁定到一個(gè)名字上。 這方面的先決條件將在下面進(jìn)一步討論。
關(guān)鍵字 match 和 case 是 soft keywords 。
參見(jiàn)
-
PEP 634 —— 結(jié)構(gòu)化模式匹配:規(guī)范
-
PEP 636 —— 結(jié)構(gòu)化模式匹配:教程
8.6.1. 概述
匹配語(yǔ)句邏輯流程的概述如下:
-
對(duì)目標(biāo)表達(dá)式
subject_expr求值后將結(jié)果作為匹配用的目標(biāo)值。 如果目標(biāo)表達(dá)式包含逗號(hào),則使用 the standard rules 構(gòu)建一個(gè)元組。 -
目標(biāo)值將依次與
case_block中的每個(gè)模式進(jìn)行匹配。匹配成功或失敗的具體規(guī)則在下面描述。匹配嘗試也可以與模式中的一些或所有的獨(dú)立名稱綁定。準(zhǔn)確的模式綁定規(guī)則因模式類型而異,具體規(guī)定見(jiàn)下文。成功的模式匹配過(guò)程中產(chǎn)生的名稱綁定將超越所執(zhí)行的塊的范圍,可以在匹配語(yǔ)句之后使用。備注
在模式匹配失敗時(shí),一些子模式可能會(huì)成功。 不要依賴于失敗匹配進(jìn)行的綁定。 反過(guò)來(lái)說(shuō),不要認(rèn)為變量在匹配失敗后保持不變。 確切的行為取決于實(shí)現(xiàn),可能會(huì)有所不同。 這是一個(gè)有意的決定,允許不同的實(shí)現(xiàn)添加優(yōu)化。
-
如果該模式匹配成功,并且完成了對(duì)相應(yīng)的約束項(xiàng)(如果存在)的求值。在這種情況下,保證完成所有的名稱綁定。
-
如果約束項(xiàng)求值為真或缺失,執(zhí)行
case_block中的block。 -
否則,將按照上述方法嘗試下一個(gè)
case_block。 -
如果沒(méi)有進(jìn)一步的 case 塊,匹配語(yǔ)句終止。
-
備注
用戶一般不應(yīng)依賴正在求值的模式。 根據(jù)不同的實(shí)現(xiàn)方式,解釋器可能會(huì)緩存數(shù)值或使用其他優(yōu)化方法來(lái)避免重復(fù)求值。
匹配語(yǔ)句示例:
>>> flag = False>>> match (100, 200):... case (100, 300): # Mismatch: 200 != 300... print('Case 1')... case (100, 200) if flag: # Successful match, but guard fails... print('Case 2')... case (100, y): # Matches and binds y to 200... print(f'Case 3, y: {y}')... case _: # Pattern not attempted... print('Case 4, I match anything!')...Case 3, y: 200
在這個(gè)示例中,if flag 是約束項(xiàng)。請(qǐng)閱讀下一節(jié)以了解更多相關(guān)內(nèi)容。
8.6.2. 約束項(xiàng)
- guard ::= "if"
named_expression
guard (它是 case 的一部分) 必須成立才能讓 case 語(yǔ)句塊中的代碼被執(zhí)行。 它所采用的形式為: if 之后跟一個(gè)表達(dá)式。
擁有 guard 的 case 塊的邏輯流程如下:
-
檢查
case塊中的模式是否匹配成功。如果該模式匹配失敗,則不對(duì)guard進(jìn)行求值,檢查下一個(gè)case塊。 -
如果該模式匹配成功,對(duì)
guard求值。-
如果
guard求值為真,則選用該 case 塊。 -
如果
guard求值為假,則不選用該 case 塊。 -
如果在對(duì)
guard求值過(guò)程中引發(fā)了異常,則異常將被拋出。
-
允許約束項(xiàng)產(chǎn)生副作用,因?yàn)樗麄兪潜磉_(dá)式。約束項(xiàng)求值必須從第一個(gè) case 塊到最后一個(gè) case 塊依次逐個(gè)進(jìn)行,模式匹配失敗的 case 塊將被跳過(guò)。(也就是說(shuō),約束項(xiàng)求值必須按順序進(jìn)行。)一旦選用了一個(gè) case 塊,約束項(xiàng)求值必須由此終止。
8.6.3. 必定匹配的 case 塊
必定匹配的 case 塊是能匹配所有情況的 case 塊。一個(gè)匹配語(yǔ)句最多可以有一個(gè)必定匹配的 case 塊,而且必須是最后一個(gè)。
如果一個(gè) case 塊沒(méi)有約束項(xiàng),并且其模式是必定匹配的,那么它就被認(rèn)為是必定匹配的。 如果我們可以僅從語(yǔ)法上證明一個(gè)模式總是能匹配成功,那么這個(gè)模式就被認(rèn)為是必定匹配的。 只有以下模式是必定匹配的:
-
左側(cè)模式是必定匹配的 AS 模式
-
包含至少一個(gè)必定匹配模式的 或模式
-
捕獲模式
-
通配符模式
-
括號(hào)內(nèi)的必定匹配模式
8.6.4. 模式
備注
本節(jié)使用了超出標(biāo)準(zhǔn) EBNF 的語(yǔ)法符號(hào)。
-
符號(hào)
SEP.RULE+是RULE (SEP RULE)*的簡(jiǎn)寫 -
符號(hào)
!RULE是前向否定斷言的簡(jiǎn)寫
patterns 的頂層語(yǔ)法是:
- patterns ::= open_sequence_pattern | pattern
- pattern ::= as_pattern | or_pattern
- closed_pattern ::= | literal_pattern
- | capture_pattern
- | wildcard_pattern
- | value_pattern
- | group_pattern
- | sequence_pattern
- | mapping_pattern
- | class_pattern
下面的描述將包括一個(gè)“簡(jiǎn)而言之”以描述模式的作用,便于說(shuō)明問(wèn)題(感謝 Raymond Hettinger 提供的一份文件,大部分的描述受其啟發(fā))。請(qǐng)注意,這些描述純粹是為了說(shuō)明問(wèn)題,可能不 反映底層的實(shí)現(xiàn)。此外,它們并沒(méi)有涵蓋所有有效的形式。
8.6.4.1. 或模式
或模式是由豎杠 | 分隔的兩個(gè)或更多的模式。語(yǔ)法:
- or_pattern ::= "|".closed_pattern+
只有最后的子模式可以是 必定匹配的,且每個(gè)子模式必須綁定相同的名字集以避免歧義。
或模式將目標(biāo)值依次與其每個(gè)子模式嘗試匹配,直到有一個(gè)匹配成功,然后該或模式被視作匹配成功。 否則,如果沒(méi)有任何子模式匹配成功,則或模式匹配失敗。
簡(jiǎn)而言之,P1 | P2 | ... 會(huì)首先嘗試匹配 P1 ,如果失敗將接著嘗試匹配 P2 ,如果出現(xiàn)成功的匹配則立即結(jié)束且模式匹配成功,否則模式匹配失敗。
8.6.4.2. AS 模式
AS 模式將關(guān)鍵字 as 左側(cè)的或模式與目標(biāo)值進(jìn)行匹配。語(yǔ)法:
- as_pattern ::= or_pattern "as" capture_pattern
如果或模式匹配失敗,AS 模式也匹配失敗。 否則,AS 模式將目標(biāo)與關(guān)鍵字 as 右邊的名字綁定且匹配陳成功。 capture_pattern 不能是 _ 。
簡(jiǎn)而言之, P as NAME 將與 P 匹配,成功后將設(shè)置 NAME = 。
8.6.4.3. 字面值模式
字面值模式對(duì)應(yīng) Python 中的大多數(shù) 字面值。 語(yǔ)法為:
- literal_pattern ::=
signed_number- |
signed_number"+" NUMBER- |
signed_number"-" NUMBER- |
strings- | "None"
- | "True"
- | "False"
- |
signed_number: NUMBER | "-" NUMBER
規(guī)則 strings 和標(biāo)記 NUMBER 是在 standard Python grammar 中定義的。支持三引號(hào)的字符串。不支持原始字符串和字節(jié)字符串。也不支持 格式字符串字面值 。
signed_number '+' NUMBER 和 signed_number '-' NUMBER 形式是用于表示 復(fù)數(shù);它們要求左邊是一個(gè)實(shí)數(shù)而右邊是一個(gè)虛數(shù)。 例如 3 + 4j。
簡(jiǎn)而言之, LITERAL 只會(huì)在 時(shí)匹配成功。對(duì)于單例 None 、 True 和 False ,會(huì)使用 is 運(yùn)算符。
8.6.4.4. 捕獲模式
捕獲模式將目標(biāo)值與一個(gè)名稱綁定。語(yǔ)法:
capture_pattern ::= !'_' NAME
單獨(dú)的一個(gè)下劃線 _ 不是捕獲模式( !'_' 表達(dá)的就是這個(gè)含義)。 它會(huì)被當(dāng)作 wildcard_pattern 。
在給定的模式中,一個(gè)名字只能被綁定一次。例如 case x, x: ... 時(shí)無(wú)效的,但 case [x] | x: ... 是被允許的。
捕獲模式總是能匹配成功。綁定遵循 PEP 572 中賦值表達(dá)式運(yùn)算符設(shè)立的作用域規(guī)則;名字在最接近的包含函數(shù)作用域內(nèi)成為一個(gè)局部變量,除非有適用的 global 或 nonlocal 語(yǔ)句。
簡(jiǎn)而言之, NAME 總是會(huì)匹配成功且將設(shè)置 NAME = 。
8.6.4.5. 通配符模式
通配符模式總是會(huì)匹配成功(匹配任何內(nèi)容)并且不綁定任何名稱。語(yǔ)法:
wildcard_pattern ::= '_'
在且僅在任何模式中 _ 是一個(gè) 軟關(guān)鍵字。 通常情況下它是一個(gè)標(biāo)識(shí)符,即使是在 match 的目標(biāo)表達(dá)式、guard 和 case 代碼塊中也是如此。
簡(jiǎn)而言之,_ 總是會(huì)匹配成功。
8.6.4.6. 值模式
值模式代表 Python 中具有名稱的值。語(yǔ)法:
- value_pattern ::= attr
- attr ::= name_or_attr "." NAME
- name_or_attr ::= attr | NAME
模式中帶點(diǎn)的名稱會(huì)使用標(biāo)準(zhǔn)的 Python 名稱解析規(guī)則 來(lái)查找。 如果找到的值與目標(biāo)值比較結(jié)果相等則模式匹配成功(使用 == 相等運(yùn)算符)。
簡(jiǎn)而言之, NAME1.NAME2 僅在 時(shí)匹配成功。
備注
如果相同的值在同一個(gè)匹配語(yǔ)句中出現(xiàn)多次,解釋器可能會(huì)緩存找到的第一個(gè)值并重新使用它,而不是重復(fù)查找。 這種緩存與特定匹配語(yǔ)句的執(zhí)行嚴(yán)格掛鉤。
8.6.4.7. 組模式
組模式允許用戶在模式周圍添加括號(hào),以強(qiáng)調(diào)預(yù)期的分組。 除此之外,它沒(méi)有額外的語(yǔ)法。語(yǔ)法:
- group_pattern ::= "(" pattern ")"
簡(jiǎn)單來(lái)說(shuō) (P) 具有與 P 相同的效果。
8.6.4.8. 序列模式
一個(gè)序列模式包含數(shù)個(gè)將與序列元素進(jìn)行匹配的子模式。其語(yǔ)法類似于列表或元組的解包。
- sequence_pattern ::= "[" [maybe_sequence_pattern] "]"
- | "(" [open_sequence_pattern] ")"
- open_sequence_pattern ::= maybe_star_pattern "," [maybe_sequence_pattern]
- maybe_sequence_pattern ::= ",".maybe_star_pattern+ ","?
- maybe_star_pattern ::= star_pattern | pattern
- star_pattern ::= "*" (capture_pattern | wildcard_pattern)
序列模式中使用圓括號(hào)或方括號(hào)沒(méi)有區(qū)別(例如 (...) 和 [...] )。
備注
用圓括號(hào)括起來(lái)且沒(méi)有跟隨逗號(hào)的單個(gè)模式 (例如 (3 | 4)) 是一個(gè) 分組模式。 而用方括號(hào)括起來(lái)的單個(gè)模式 (例如 [3 | 4]) 則仍是一個(gè)序列模式。
一個(gè)序列模式中最多可以有一個(gè)星號(hào)子模式。星號(hào)子模式可以出現(xiàn)在任何位置。如果沒(méi)有星號(hào)子模式,該序列模式是固定長(zhǎng)度的序列模式;否則,其是一個(gè)可變長(zhǎng)度的序列模式。
下面是將一個(gè)序列模式與一個(gè)目標(biāo)值相匹配的邏輯流程:
-
如果目標(biāo)值不是一個(gè)序列 2 ,該序列模式匹配失敗。
-
如果目標(biāo)值是
str、bytes或bytearray的實(shí)例,則該序列模式匹配失敗。 -
隨后的步驟取決于序列模式是固定長(zhǎng)度還是可變長(zhǎng)度的。
如果序列模式是固定長(zhǎng)度的:
-
如果目標(biāo)序列的長(zhǎng)度與子模式的數(shù)量不相等,則該序列模式匹配失敗
-
序列模式中的子模式與目標(biāo)序列中的相應(yīng)項(xiàng)目從左到右進(jìn)行匹配。 一旦一個(gè)子模式匹配失敗,就停止匹配。 如果所有的子模式都成功地與它們的對(duì)應(yīng)項(xiàng)相匹配,那么該序列模式就匹配成功了。
否則,如果序列模式是變長(zhǎng)的:
-
如果目標(biāo)序列的長(zhǎng)度小于非星號(hào)子模式的數(shù)量,則該序列模式匹配失敗。
-
與固定長(zhǎng)度的序列一樣,靠前的非星形子模式與其相應(yīng)的項(xiàng)目進(jìn)行匹配。
-
如果上一步成功,星號(hào)子模式與剩余的目標(biāo)項(xiàng)形成的列表相匹配,不包括星號(hào)子模式之后的非星號(hào)子模式所對(duì)應(yīng)的剩余項(xiàng)。
-
剩余的非星號(hào)子模式將與相應(yīng)的目標(biāo)項(xiàng)匹配,就像固定長(zhǎng)度的序列一樣。
備注
目標(biāo)序列的長(zhǎng)度可通過(guò) len() (即通過(guò)
__len__()協(xié)議) 獲得。 解釋器可能會(huì)以類似于 值模式 的方式緩存這個(gè)長(zhǎng)度信息。 -
簡(jiǎn)而言之, [P1, P2, P3, … , P 僅在滿足以下情況時(shí)匹配成功:
-
檢查
是一個(gè)序列 -
len(subject) == -
將
P1與進(jìn)行匹配(請(qǐng)注意此匹配可以綁定名稱)[0] -
將
P2與進(jìn)行匹配(請(qǐng)注意此匹配可以綁定名稱)[1] -
…… 剩余對(duì)應(yīng)的模式/元素也以此類推。
8.6.4.9. 映射模式
映射模式包含一個(gè)或多個(gè)鍵值模式。其語(yǔ)法類似于字典的構(gòu)造。語(yǔ)法:
- mapping_pattern ::= "{" [items_pattern] "}"
- items_pattern ::= ",".key_value_pattern+ ","?
- key_value_pattern ::= (literal_pattern | value_pattern) ":" pattern
- | double_star_pattern
- double_star_pattern ::= "**" capture_pattern
一個(gè)映射模式中最多可以有一個(gè)雙星號(hào)模式。雙星號(hào)模式必須是映射模式中的最后一個(gè)子模式。
映射模式中不允許出現(xiàn)重復(fù)的鍵。重復(fù)的字面值鍵會(huì)引發(fā) SyntaxError 。若是兩個(gè)鍵有相同的值將會(huì)在運(yùn)行時(shí)引發(fā) ValueError 。
以下是映射模式與目標(biāo)值匹配的邏輯流程:
-
如果目標(biāo)值不是一個(gè)映射 3,則映射模式匹配失敗。
-
若映射模式中給出的每個(gè)鍵都存在于目標(biāo)映射中,且每個(gè)鍵的模式都與目標(biāo)映射的相應(yīng)項(xiàng)匹配成功,則該映射模式匹配成功。
-
如果在映射模式中檢測(cè)到重復(fù)的鍵,該模式將被視作無(wú)效。對(duì)于重復(fù)的字面值,會(huì)引發(fā) SyntaxError ;對(duì)于相同值的命名鍵,會(huì)引發(fā) ValueError 。
備注
鍵值對(duì)使用映射目標(biāo)的 get() 方法的雙參數(shù)形式進(jìn)行匹配。匹配的鍵值對(duì)必須已經(jīng)存在于映射中,而不是通過(guò) __missing__() 或 __getitem__() 即時(shí)創(chuàng)建。
簡(jiǎn)而言之, {KEY1: P1, KEY2: P2, ... } 僅在滿足以下情況時(shí)匹配成功:
-
檢查
是映射 -
KEY1 in -
P1與相匹配[KEY1] -
…… 剩余對(duì)應(yīng)的鍵/模式對(duì)也以此類推。
8.6.4.10. 類模式
類模式表示一個(gè)類以及它的位置參數(shù)和關(guān)鍵字參數(shù)(如果有的話)。語(yǔ)法:
- class_pattern ::= name_or_attr "(" [pattern_arguments ","?] ")"
- pattern_arguments ::= positional_patterns ["," keyword_patterns]
- | keyword_patterns
- positional_patterns ::= ",".pattern+
- keyword_patterns ::= ",".keyword_pattern+
- keyword_pattern ::= NAME "=" pattern
同一個(gè)關(guān)鍵詞不應(yīng)該在類模式中重復(fù)出現(xiàn)。
以下是類模式與目標(biāo)值匹配的邏輯流程:
-
如果
name_or_attr不是內(nèi)置 type 的實(shí)例,引發(fā) TypeError 。 -
如果目標(biāo)值不是
name_or_attr的實(shí)例(通過(guò) isinstance() 測(cè)試),該類模式匹配失敗。 -
如果沒(méi)有模式參數(shù)存在,則該模式匹配成功。 否則,后面的步驟取決于是否有關(guān)鍵字或位置參數(shù)模式存在。
對(duì)于一些內(nèi)置的類型(將在后文詳述),接受一個(gè)位置子模式,它將與整個(gè)目標(biāo)值相匹配;對(duì)于這些類型,關(guān)鍵字模式也像其他類型一樣工作。
如果只存在關(guān)鍵詞模式,它們將被逐一處理,如下所示:
一. 該關(guān)鍵詞被視作主體的一個(gè)屬性進(jìn)行查找。
-
如果這引發(fā)了除 AttributeError 以外的異常,該異常會(huì)被拋出。
-
如果這引發(fā)了 AttributeError ,該類模式匹配失敗。
-
否則,與關(guān)鍵詞模式相關(guān)的子模式將與目標(biāo)的屬性值進(jìn)行匹配。 如果失敗,則類模式匹配失敗;如果成功,則繼續(xù)對(duì)下一個(gè)關(guān)鍵詞進(jìn)行匹配。
二. 如果所有的關(guān)鍵詞模式匹配成功,該類模式匹配成功。
如果存在位置模式,在匹配前會(huì)用類
name_or_attr的 __match_args__ 屬性將其轉(zhuǎn)換為關(guān)鍵詞模式。一. 進(jìn)行與
getattr(cls, "__match_args__", ())等價(jià)的調(diào)用。-
如果這引發(fā)一個(gè)異常,該異常將被拋出。
-
如果返回值不是一個(gè)元組,則轉(zhuǎn)換失敗且引發(fā) TypeError 。
-
若位置模式的數(shù)量超出
len(cls.__match_args__),將引發(fā) TypeError 。 -
否則,位置模式
i會(huì)使用__match_args__[i]轉(zhuǎn)換為關(guān)鍵詞。__match_args__[i]必須是一個(gè)字符串;如果不是則引發(fā) TypeError 。 -
如果有重復(fù)的關(guān)鍵詞,引發(fā) TypeError 。
參見(jiàn)
定制類模式匹配中的位置參數(shù)
二. 若所有的位置模式都被轉(zhuǎn)換為關(guān)鍵詞模式,
匹配的過(guò)程就像只有關(guān)鍵詞模式一樣。
對(duì)于以下內(nèi)置類型,位置子模式的處理是不同的:
-
bool
-
bytearray
-
bytes
-
dict
-
float
-
frozenset
-
int
-
list
-
set
-
str
-
tuple
These classes accept a single positional argument, and the pattern there is matched against the whole object rather than an attribute. For example
int(0|1)matches the value0, but not the value0.0. -
簡(jiǎn)而言之, CLS(P1, attr=P2) 僅在滿足以下情況時(shí)匹配成功:
-
isinstance(, CLS) -
用
CLS.__match_args__將P1轉(zhuǎn)換為關(guān)鍵詞模式 -
對(duì)于每個(gè)關(guān)鍵詞參數(shù)
attr=P2:-
hasattr(, "attr") -
將
P2與進(jìn)行匹配.attr
-
-
…… 剩余對(duì)應(yīng)的關(guān)鍵字參數(shù)/模式對(duì)也以此類推。
參見(jiàn)
-
PEP 634 —— 結(jié)構(gòu)化模式匹配:規(guī)范
-
PEP 636 —— 結(jié)構(gòu)化模式匹配:教程
8.7. 函數(shù)定義
函數(shù)定義就是對(duì)用戶自定義函數(shù)的定義(參見(jiàn) 標(biāo)準(zhǔn)類型層級(jí)結(jié)構(gòu) 一節(jié)):
- funcdef ::= [decorators] "def" funcname "(" [parameter_list] ")"
- ["->" expression] ":" suite
- decorators ::= decorator+
- decorator ::= "@" assignment_expression NEWLINE
- parameter_list ::= defparameter ("," defparameter)* "," "/" ["," [parameter_list_no_posonly]]
- | parameter_list_no_posonly
- parameter_list_no_posonly ::= defparameter ("," defparameter)* ["," [parameter_list_starargs]]
- | parameter_list_starargs
- parameter_list_starargs ::= "*" [parameter] ("," defparameter)* ["," ["**" parameter [","]]]
- | "**" parameter [","]
- parameter ::= identifier [":" expression]
- defparameter ::= parameter ["=" expression]
- funcname ::= identifier
函數(shù)定義是一條可執(zhí)行語(yǔ)句。 它執(zhí)行時(shí)會(huì)在當(dāng)前局部命名空間中將函數(shù)名稱綁定到一個(gè)函數(shù)對(duì)象(函數(shù)可執(zhí)行代碼的包裝器)。 這個(gè)函數(shù)對(duì)象包含對(duì)當(dāng)前全局命名空間的引用,作為函數(shù)被調(diào)用時(shí)所使用的全局命名空間。
函數(shù)定義并不會(huì)執(zhí)行函數(shù)體;只有當(dāng)函數(shù)被調(diào)用時(shí)才會(huì)執(zhí)行此操作。 4
一個(gè)函數(shù)定義可以被一
名稱欄目:創(chuàng)新互聯(lián)Python教程:8.復(fù)合語(yǔ)句
標(biāo)題URL:http://fisionsoft.com.cn/article/cccphgc.html


咨詢
建站咨詢
