6. 表示式¶
本章解釋 Python 中表達式元素的含義。
語法說明:在本章和後續章節中,將使用擴充套件的 BNF 表示法來描述語法,而不是詞法分析。當(一個語法的替代)語法規則具有以下形式時
name ::= othername
並且沒有給出語義,則 name
的這種形式的語義與 othername
的語義相同。
6.1. 算術轉換¶
當下面對算術運算子的描述使用短語“數值引數被轉換為公共型別”時,這意味著內建型別的運算子實現的工作方式如下
如果任一引數是複數,則另一個引數將轉換為複數;
否則,如果任一引數是浮點數,則另一個引數將轉換為浮點數;
否則,兩者必須是整數,並且不需要轉換。
某些運算子(例如,作為“%”運算子的左引數的字串)適用一些附加規則。擴充套件必須定義自己的轉換行為。
6.2. 原子¶
原子是表示式的最基本元素。最簡單的原子是識別符號或字面值。用括號、方括號或花括號括起來的形式也在語法上歸類為原子。原子的語法為
atom ::=identifier
|literal
|enclosure
enclosure ::=parenth_form
|list_display
|dict_display
|set_display
|generator_expression
|yield_atom
6.2.1. 識別符號(名稱)¶
作為原子的識別符號是名稱。有關詞法定義,請參見 識別符號和關鍵字 部分,有關命名和繫結的文件,請參見 命名和繫結 部分。
當名稱繫結到物件時,對原子的求值會產生該物件。當名稱未繫結時,嘗試對其求值會引發 NameError
異常。
6.2.1.1. 私有名稱混淆¶
當在類定義中以文字形式出現的識別符號以兩個或多個下劃線字元開頭,並且不以兩個或多個下劃線結尾時,它將被視為該類的私有名稱。
另請參閱
類規範。
更精確地說,私有名稱在為其生成程式碼之前被轉換為更長的形式。如果轉換後的名稱長度超過 255 個字元,則可能會發生實現定義的截斷。
轉換與識別符號使用的句法上下文無關,但只有以下私有識別符號會被混淆
用作賦值或讀取變數的名稱或正在訪問的屬性的任何名稱。
但是,巢狀函式、類和類型別名的
__name__
屬性不會被混淆。匯入的模組的名稱,例如
import __spam
中的__spam
。如果模組是包的一部分(即,其名稱包含一個點),則該名稱不會被混淆,例如import __foo.bar
中的__foo
不會被混淆。匯入的成員的名稱,例如
from spam import __f
中的__f
。
轉換規則定義如下
在識別符號前面插入刪除前導下劃線並插入單個前導下劃線的類名,例如,在名為
Foo
、_Foo
或__Foo
的類中出現的識別符號__spam
將轉換為_Foo__spam
。如果類名僅由下劃線組成,則轉換是標識,例如,在名為
_
或__
的類中出現的識別符號__spam
將保持不變。
6.2.2. 字面值¶
Python 支援字串和位元組字面值以及各種數字字面值
literal ::=stringliteral
|bytesliteral
|integer
|floatnumber
|imagnumber
對字面值的求值會產生具有給定值的給定型別(字串、位元組、整數、浮點數、複數)的物件。在浮點數和虛數(複數)字面值的情況下,該值可能是近似值。有關詳細資訊,請參見 字面值 部分。
所有字面值都對應於不可變的資料型別,因此物件的標識不如其值重要。對具有相同值的字面值(程式文字中的相同出現或不同的出現)進行多次求值可能會獲得相同的物件或具有相同值的不同物件。
6.2.3. 圓括號形式¶
帶括號的形式是一個用括號括起來的可選表示式列表
parenth_form ::= "(" [starred_expression
] ")"
帶括號的表示式列表會產生該表示式列表產生的任何內容:如果列表至少包含一個逗號,則會產生一個元組;否則,它會產生構成表示式列表的單個表示式。
一對空括號會產生一個空元組物件。由於元組是不可變的,因此適用與字面值相同的規則(即,空元組的兩次出現可能產生也可能不產生相同的物件)。
請注意,元組不是由括號形成的,而是由逗號的使用形成的。例外情況是空元組,對於空元組,確實需要括號 — 允許在表示式中使用不帶括號的“nothing”會導致歧義,並允許常見的拼寫錯誤被忽略。
6.2.4. 列表、集合和字典的顯示¶
為了構造列表、集合或字典,Python 提供了特殊的語法,稱為“顯示”,它們各有兩種風格
要麼明確列出容器內容,要麼
它們是透過一組迴圈和過濾指令計算出來的,稱為推導式。
推導式的常見語法元素為
comprehension ::=assignment_expression
comp_for
comp_for ::= ["async"] "for"target_list
"in"or_test
[comp_iter
] comp_iter ::=comp_for
|comp_if
comp_if ::= "if"or_test
[comp_iter
]
推導式由一個表示式組成,後跟至少一個 for
子句和零個或多個 for
或 if
子句。在這種情況下,新容器的元素是那些透過將每個 for
或 if
子句視為塊(從左到右巢狀)並求值表示式來產生元素的,每次到達最內層塊時都會產生一個元素。
但是,除了最左側 for
子句中的可迭代表達式外,推導式是在單獨的隱式巢狀作用域中執行的。這確保了在目標列表中賦值的名稱不會“洩漏”到封閉作用域中。
最左側 for
子句中的可迭代表達式會在外層作用域中直接求值,然後作為引數傳遞給隱式巢狀的作用域。後續的 for
子句以及最左側 for
子句中的任何過濾條件都不能在外層作用域中求值,因為它們可能依賴於從最左側可迭代物件獲得的值。例如:[x*y for x in range(10) for y in range(x, x+10)]
。
為了確保推導式始終產生適當型別的容器,禁止在隱式巢狀作用域中使用 yield
和 yield from
表示式。
自 Python 3.6 起,在 async def
函式中,可以使用 async for
子句來迭代 非同步迭代器。 async def
函式中的推導式可以包含前導表示式之後的 for
或 async for
子句,還可以包含額外的 for
或 async for
子句,並且還可以使用 await
表示式。
如果推導式包含 async for
子句,或者除了最左側 for
子句中的可迭代表達式之外,在任何位置包含 await
表示式或其他非同步推導式,則稱為非同步推導式。非同步推導式可能會掛起其所在的協程函式的執行。另請參閱 PEP 530。
3.6 版本新增: 引入了非同步推導式。
3.8 版本更改: 禁止在隱式巢狀作用域中使用 yield
和 yield from
。
3.11 版本更改: 現在允許在非同步函式中的推導式內使用非同步推導式。外部推導式隱式變為非同步的。
6.2.5. 列表顯示¶
列表顯示是用方括號括起來的可能為空的一系列表示式。
list_display ::= "[" [flexible_expression_list
|comprehension
] "]"
列表顯示會產生一個新的列表物件,其內容由一系列表示式或推導式指定。當提供以逗號分隔的表示式列表時,其元素將從左到右求值,並按該順序放入列表物件中。當提供推導式時,列表將根據推導式產生的元素構建。
6.2.6. 集合顯示¶
集合顯示用花括號表示,並透過缺少分隔鍵和值的分號來與字典顯示區分開。
set_display ::= "{" (flexible_expression_list
|comprehension
) "}"
集合顯示會產生一個新的可變集合物件,其內容由一系列表示式或推導式指定。當提供以逗號分隔的表示式列表時,其元素將從左到右求值並新增到集合物件中。當提供推導式時,集合將根據推導式產生的元素構建。
不能使用 {}
構造空集合;此字面量構造一個空字典。
6.2.7. 字典顯示¶
字典顯示是用花括號括起來的可能為空的一系列字典項(鍵/值對)。
dict_display ::= "{" [dict_item_list
|dict_comprehension
] "}" dict_item_list ::=dict_item
(","dict_item
)* [","] dict_item ::=expression
":"expression
| "**"or_expr
dict_comprehension ::=expression
":"expression
comp_for
字典顯示會產生一個新的字典物件。
如果給出以逗號分隔的字典項序列,則會從左到右求值,以定義字典的條目:每個鍵物件都用作字典中的鍵來儲存相應的值。這意味著您可以在字典項列表中多次指定相同的鍵,並且該鍵的最終字典值將是最後給出的值。
雙星號 **
表示字典解包。它的運算元必須是 對映。每個對映項都會新增到新字典中。後面的值會替換較早的字典項和較早的字典解包設定的值。
3.5 版本新增: 將解包引入字典顯示,最初由 PEP 448 提出。
與列表和集合推導式相反,字典推導式需要兩個用冒號分隔的表示式,後跟通常的“for”和“if”子句。當推導式執行時,生成的鍵和值元素會按照它們產生的順序插入新字典中。
鍵值的型別限制在前面的 標準型別層次結構 一節中列出。(總而言之,鍵型別應該是 可雜湊的,這排除了所有可變物件。)不會檢測重複鍵之間的衝突;給定鍵值的最後一個值(在顯示中按文字最右邊的值)優先。
3.8 版本更改: 在 Python 3.8 之前,在字典推導式中,鍵和值的求值順序沒有明確定義。在 CPython 中,值在鍵之前求值。從 3.8 開始,鍵在值之前求值,正如 PEP 572 提出的那樣。
6.2.8. 生成器表示式¶
生成器表示式是括號中緊湊的生成器表示法。
generator_expression ::= "("expression
comp_for
")"
生成器表示式會產生一個新的生成器物件。它的語法與推導式相同,只不過它用括號而不是方括號或花括號括起來。
當為生成器物件呼叫 __next__()
方法時,生成器表示式中使用的變數會延遲求值(與普通生成器的方式相同)。但是,最左側 for
子句中的可迭代表達式會立即求值,因此它產生的錯誤將在定義生成器表示式的點發出,而不是在檢索第一個值的點發出。後續的 for
子句以及最左側 for
子句中的任何過濾條件都不能在外層作用域中求值,因為它們可能依賴於從最左側可迭代物件獲得的值。例如:(x*y for x in range(10) for y in range(x, x+10))
。
在只有一個引數的呼叫中,可以省略括號。有關詳細資訊,請參閱 呼叫 一節。
為了避免干擾生成器表示式本身的操作,禁止在隱式定義的生成器中使用 yield
和 yield from
表示式。
如果生成器表示式包含 async for
子句或 await
表示式,則稱為非同步生成器表示式。非同步生成器表示式返回一個新的非同步生成器物件,該物件是一個非同步迭代器(請參閱 非同步迭代器)。
3.6 版本新增: 引入了非同步生成器表示式。
3.7 版本更改: 在 Python 3.7 之前,非同步生成器表示式只能出現在 async def
協程中。從 3.7 開始,任何函式都可以使用非同步生成器表示式。
3.8 版本更改: 禁止在隱式巢狀作用域中使用 yield
和 yield from
。
6.2.9. Yield 表示式¶
yield_atom ::= "("yield_expression
")" yield_from ::= "yield" "from"expression
yield_expression ::= "yield"yield_list
|yield_from
當定義生成器函式或非同步生成器函式時,會使用 yield 表示式,因此只能在函式定義的函式體中使用。在函式體中使用 yield 表示式會導致該函式成為生成器函式,而在async def
函式的函式體中使用則會導致該協程函式成為非同步生成器函式。例如:
def gen(): # defines a generator function
yield 123
async def agen(): # defines an asynchronous generator function
yield 123
由於 `yield` 表示式會對包含它的作用域產生副作用,因此不允許將其作為隱式定義的作用域的一部分,而這些隱式定義的作用域用於實現推導式和生成器表示式。
在 3.8 版本中更改: 禁止在用於實現推導式和生成器表示式的隱式巢狀作用域中使用 Yield 表示式。
生成器函式將在下面介紹,而非同步生成器函式將在非同步生成器函式章節中單獨介紹。
當呼叫生成器函式時,它會返回一個稱為生成器的迭代器。然後,該生成器控制生成器函式的執行。當呼叫生成器的方法之一時,執行開始。此時,執行會進行到第一個 yield 表示式,在那裡它再次被掛起,將yield_list
的值返回給生成器的呼叫者,如果省略了yield_list
,則返回None
。所謂掛起,是指保留所有區域性狀態,包括區域性變數的當前繫結、指令指標、內部求值堆疊以及任何異常處理的狀態。當透過呼叫生成器的方法之一恢復執行時,該函式可以像 yield 表示式只是另一個外部呼叫一樣繼續執行。恢復後,yield 表示式的值取決於恢復執行的方法。如果使用__next__()
(通常透過for
或內建的next()
函式),則結果為None
。否則,如果使用send()
,則結果將是傳遞給該方法的值。
所有這些都使得生成器函式與協程非常相似;它們多次 yield,它們有多個入口點,並且它們的執行可以被掛起。唯一的區別是生成器函式無法控制在 yield 後應該在哪裡繼續執行;控制權總是轉移到生成器的呼叫者。
yield 表示式允許在try
結構中的任何位置使用。如果生成器在完成(透過達到零引用計數或被垃圾回收)之前沒有恢復,則會呼叫生成器迭代器的close()
方法,允許執行任何掛起的finally
子句。
當使用yield from <expr>
時,提供的表示式必須是可迭代的。透過迭代該可迭代物件產生的值將直接傳遞給當前生成器方法的呼叫者。任何使用send()
傳入的值和任何使用throw()
傳入的異常,如果底層迭代器具有適當的方法,則會傳遞給該迭代器。如果不是這種情況,那麼send()
將引發AttributeError
或TypeError
,而throw()
將立即引發傳入的異常。
當底層迭代器完成時,引發的StopIteration
例項的value
屬性將成為 yield 表示式的值。它可以在引發StopIteration
時顯式設定,或者當子迭代器是生成器時自動設定(透過從子生成器返回一個值)。
在 3.3 版本中更改: 添加了 yield from <expr>
以將控制流委託給子迭代器。
當 yield 表示式是賦值語句右側的唯一表達式時,可以省略括號。
另請參閱
6.2.9.1. 生成器迭代器方法¶
本小節介紹生成器迭代器的方法。它們可用於控制生成器函式的執行。
請注意,當生成器已經在執行時呼叫以下任何生成器方法都會引發ValueError
異常。
- generator.__next__()¶
啟動生成器函式的執行或在上次執行的 yield 表示式處恢復執行。當使用
__next__()
方法恢復生成器函式時,當前的 yield 表示式始終求值為None
。然後,執行繼續到下一個 yield 表示式,生成器再次被掛起,並將yield_list
的值返回給__next__()
的呼叫者。如果生成器在沒有 yield 另一個值的情況下退出,則會引發StopIteration
異常。
- generator.send(value)¶
恢復執行並向生成器函式“傳送”一個值。value 引數將成為當前 yield 表示式的結果。
send()
方法返回生成器 yield 的下一個值,如果生成器退出時沒有 yield 其他值,則引發StopIteration
異常。當呼叫send()
來啟動生成器時,必須使用None
作為引數呼叫,因為沒有 yield 表示式可以接收該值。
- generator.throw(value)¶
- generator.throw(type[, value[, traceback]])
在生成器暫停的位置引發異常,並返回生成器函式 yield 的下一個值。如果生成器退出時沒有 yield 其他值,則會引發
StopIteration
異常。如果生成器函式沒有捕獲傳入的異常,或者引發了不同的異常,則該異常會傳播給呼叫者。在典型用法中,此呼叫會使用單個異常例項,類似於
raise
關鍵字的使用方式。但是,為了向後相容,支援第二個簽名,該簽名遵循舊版本 Python 的約定。 type 引數應該是異常類,而 value 應該是異常例項。如果未提供 value,則會呼叫 type 建構函式來獲取一個例項。如果提供了 traceback,則會將其設定到異常上,否則可能會清除儲存在 value 中的任何現有
__traceback__
屬性。在 3.12 版本中更改: 第二個簽名(type[, value[, traceback]])已棄用,並可能在未來的 Python 版本中刪除。
- generator.close()¶
在生成器函式暫停的位置引發
GeneratorExit
異常。如果生成器函式捕獲了異常並返回值,則此值將從close()
返回。如果生成器函式已關閉,或引發GeneratorExit
異常(透過不捕獲該異常),則close()
返回None
。如果生成器 yield 一個值,則會引發RuntimeError
異常。如果生成器引發任何其他異常,則該異常會傳播給呼叫者。如果生成器由於異常或正常退出而已經退出,則close()
返回None
,並且沒有其他影響。在 3.13 版本中更改: 如果生成器在關閉時返回值,則該值將由
close()
返回。
6.2.9.2. 示例¶
這是一個簡單的示例,演示了生成器和生成器函式的行為
>>> def echo(value=None):
... print("Execution starts when 'next()' is called for the first time.")
... try:
... while True:
... try:
... value = (yield value)
... except Exception as e:
... value = e
... finally:
... print("Don't forget to clean up when 'close()' is called.")
...
>>> generator = echo(1)
>>> print(next(generator))
Execution starts when 'next()' is called for the first time.
1
>>> print(next(generator))
None
>>> print(generator.send(2))
2
>>> generator.throw(TypeError, "spam")
TypeError('spam',)
>>> generator.close()
Don't forget to clean up when 'close()' is called.
有關使用 yield from
的示例,請參閱 “Python 中的新特性” 中的 PEP 380:委託給子生成器的語法。
6.2.9.3. 非同步生成器函式¶
使用 async def
定義的函式或方法中存在 yield 表示式,進一步將該函式定義為非同步生成器函式。
當呼叫非同步生成器函式時,它會返回一個非同步迭代器,稱為非同步生成器物件。然後,該物件控制生成器函式的執行。非同步生成器物件通常在協程函式中的 async for
語句中使用,類似於生成器物件在 for
語句中的使用方式。
呼叫非同步生成器的其中一個方法會返回一個 可等待物件,並且當等待此物件時開始執行。屆時,執行將進行到第一個 yield 表示式,並在那裡再次暫停,將 yield_list
的值返回給等待的協程。與生成器一樣,暫停意味著保留所有區域性狀態,包括區域性變數的當前繫結、指令指標、內部求值堆疊以及任何異常處理的狀態。當透過等待非同步生成器的方法返回的下一個物件恢復執行時,該函式可以像 yield 表示式只是另一個外部呼叫一樣繼續執行。恢復後 yield 表示式的值取決於恢復執行的方法。如果使用 __anext__()
,則結果為 None
。否則,如果使用 asend()
,則結果將是傳遞給該方法的值。
如果非同步生成器碰巧透過 break
、取消呼叫者任務或其他異常而提前退出,則生成器的非同步清理程式碼將執行,並可能引發異常或在意外的上下文中訪問上下文變數——可能在其依賴的任務的生命週期之後,或者在呼叫非同步生成器垃圾回收鉤子的事件迴圈關閉期間。為了防止這種情況,呼叫者必須顯式呼叫 aclose()
方法來最終完成生成器,並最終將其從事件迴圈中分離。
在非同步生成器函式中,允許在 try
構造中的任何位置使用 yield 表示式。但是,如果在非同步生成器最終完成之前(透過達到零引用計數或被垃圾回收)沒有恢復,則 try
構造中的 yield 表示式可能會導致無法執行掛起的 finally
子句。在這種情況下,事件迴圈或執行非同步生成器的排程程式有責任呼叫非同步生成器迭代器的 aclose()
方法並執行生成的協程物件,從而允許執行任何掛起的 finally
子句。
為了在事件迴圈終止時處理最終完成,事件迴圈應定義一個 finalizer 函式,該函式接受一個非同步生成器迭代器,並推測呼叫 aclose()
並執行協程。可以透過呼叫 sys.set_asyncgen_hooks()
註冊此 finalizer 。首次迭代時,非同步生成器迭代器將儲存註冊的 finalizer,以便在最終完成時呼叫。有關 finalizer 方法的參考示例,請參閱 Lib/asyncio/base_events.py 中 asyncio.Loop.shutdown_asyncgens
的實現。
當在非同步生成器函式中使用表示式 yield from <expr>
時,這是一個語法錯誤。
6.2.9.4. 非同步生成器迭代器方法¶
本小節描述了非同步生成器迭代器的方法,這些方法用於控制生成器函式的執行。
- coroutine agen.__anext__()¶
返回一個可等待物件,當執行時,它會開始執行非同步生成器,或者在上次執行的 yield 表示式處恢復它。當非同步生成器函式透過
__anext__()
方法恢復時,當前 yield 表示式在返回的可等待物件中始終求值為None
,該可等待物件執行時將繼續執行下一個 yield 表示式。yield 表示式的yield_list
的值是由完成的協程引發的StopIteration
異常的值。如果非同步生成器在沒有產生另一個值的情況下退出,則該可等待物件會引發StopAsyncIteration
異常,表示非同步迭代已完成。此方法通常由
async for
迴圈隱式呼叫。
- 協程 agen.asend(value)¶
返回一個可等待物件,當執行時,它會恢復非同步生成器的執行。與生成器的
send()
方法一樣,此方法將一個值“傳送”到非同步生成器函式中,並且 value 引數成為當前 yield 表示式的結果。asend()
方法返回的可等待物件將返回生成器產生的下一個值,作為引發的StopIteration
異常的值,如果非同步生成器在沒有產生另一個值的情況下退出,則會引發StopAsyncIteration
異常。當呼叫asend()
來啟動非同步生成器時,必須使用None
作為引數呼叫,因為沒有可以接收值的 yield 表示式。
- 協程 agen.athrow(value)¶
- 協程 agen.athrow(type[, value[, traceback]])
返回一個可等待物件,該物件在非同步生成器暫停的位置引發
type
型別的異常,並返回生成器函式產生的下一個值,作為引發的StopIteration
異常的值。如果非同步生成器在沒有產生另一個值的情況下退出,則該可等待物件會引發StopAsyncIteration
異常。如果生成器函式沒有捕獲傳入的異常,或者引發了不同的異常,那麼當該可等待物件執行時,該異常將傳播到該可等待物件的呼叫者。在 3.12 版本中更改: 第二個簽名(type[, value[, traceback]])已棄用,並可能在未來的 Python 版本中刪除。
- 協程 agen.aclose()¶
返回一個可等待物件,當執行時,它會在非同步生成器函式暫停的位置丟擲一個
GeneratorExit
異常。如果非同步生成器函式隨後正常退出、已經關閉或引發GeneratorExit
異常(透過不捕獲異常),則返回的可等待物件會引發StopIteration
異常。後續呼叫非同步生成器返回的任何其他可等待物件都會引發StopAsyncIteration
異常。如果非同步生成器產生了一個值,則該可等待物件會引發RuntimeError
異常。如果非同步生成器引發任何其他異常,則該異常會傳播到該可等待物件的呼叫者。如果非同步生成器由於異常或正常退出而已經退出,則進一步呼叫aclose()
將返回一個什麼都不做的可等待物件。
6.3. 基本要素¶
基本要素表示語言中最緊密繫結的操作。它們的語法是
primary ::=atom
|attributeref
|subscription
|slicing
|call
6.3.1. 屬性引用¶
屬性引用是一個基本要素,後跟一個句點和一個名稱
attributeref ::=primary
"."identifier
基本要素必須求值為支援屬性引用的型別的物件,大多數物件都支援屬性引用。然後,會要求此物件生成名稱為識別符號的屬性。產生的型別和值由物件決定。多次求值相同的屬性引用可能會產生不同的物件。
可以透過重寫 __getattribute__()
方法或 __getattr__()
方法來自定義此生成。首先呼叫 __getattribute__()
方法,如果該屬性不可用,則返回一個值或引發 AttributeError
。
如果引發了 AttributeError
,並且物件具有 __getattr__()
方法,則將呼叫該方法作為回退。
6.3.2. 下標¶
容器類例項的下標通常會從容器中選擇一個元素。 泛型類的下標通常會返回一個 GenericAlias 物件。
subscription ::=primary
"["flexible_expression_list
"]"
當一個物件被下標時,直譯器將求值基本要素和表示式列表。
基本要素必須求值為支援下標的物件。物件可以透過定義 __getitem__()
和 __class_getitem__()
中的一個或兩個來支援下標。當下標基本要素時,表示式列表的求值結果將被傳遞給這些方法之一。有關何時呼叫 __class_getitem__
而不是 __getitem__
的更多詳細資訊,請參閱 __class_getitem__ 與 __getitem__。
如果表示式列表包含至少一個逗號,或者如果任何表示式帶有星號,則表示式列表將求值為一個包含表示式列表項的 tuple
。否則,表示式列表將求值為列表唯一成員的值。
在 3.11 版本中更改: 表示式列表中的表示式可以帶有星號。請參閱 PEP 646。
對於內建物件,有兩種型別的物件透過 __getitem__()
支援下標
對映。如果基本要素是一個 對映,則表示式列表必須求值為一個其值是對映的鍵之一的物件,並且下標會選擇對映中與該鍵對應的值。內建對映類的一個示例是
dict
類。序列。如果主要物件是序列,則表示式列表必須求值為一個
int
或一個slice
(如下節所述)。內建序列類的示例包括str
、list
和tuple
類。
正式語法沒有為序列中的負索引做出特殊規定。但是,所有內建序列都提供一個__getitem__()
方法,該方法透過將序列的長度新增到索引來解釋負索引,例如,x[-1]
選擇x
的最後一項。結果值必須是一個非負整數,小於序列中的專案數,並且下標選擇索引值為該值的專案(從零開始計數)。由於對負索引和切片的支援發生在物件的__getitem__()
方法中,因此重寫此方法的子類將需要顯式新增該支援。
字串
是一種特殊的序列,其項是字元。字元不是單獨的資料型別,而是一個恰好包含一個字元的字串。
6.3.3. 切片¶
切片選擇序列物件(例如,字串、元組或列表)中的一系列項。切片可以用作表示式或賦值中的目標,或者用作del
語句中的目標。切片的語法是
slicing ::=primary
"["slice_list
"]" slice_list ::=slice_item
(","slice_item
)* [","] slice_item ::=expression
|proper_slice
proper_slice ::= [lower_bound
] ":" [upper_bound
] [ ":" [stride
] ] lower_bound ::=expression
upper_bound ::=expression
stride ::=expression
這裡的正式語法存在歧義:任何看起來像表示式列表的東西也看起來像切片列表,因此任何下標都可以解釋為切片。為了避免進一步使語法複雜化,我們定義在這種情況下,解釋為下標的優先順序高於解釋為切片的優先順序(如果切片列表不包含任何適當的切片,則屬於這種情況)。
切片的語義如下。主要物件使用從切片列表構造的鍵進行索引(使用與普通下標相同的__getitem__()
方法)。如果切片列表至少包含一個逗號,則鍵是一個元組,其中包含切片項的轉換;否則,單獨的切片項的轉換就是鍵。作為表示式的切片項的轉換是該表示式。適當的切片的轉換是一個切片物件(請參閱標準型別層次結構部分),其start
、stop
和step
屬性分別是作為下界、上界和步長給定的表示式的值,如果缺少表示式則替換為None
。
6.3.4. 呼叫¶
呼叫使用一個可能為空的引數序列呼叫一個可呼叫物件(例如,一個函式)
call ::=primary
"(" [argument_list
[","] |comprehension
] ")" argument_list ::=positional_arguments
[","starred_and_keywords
] [","keywords_arguments
] |starred_and_keywords
[","keywords_arguments
] |keywords_arguments
positional_arguments ::= positional_item ("," positional_item)* positional_item ::=assignment_expression
| "*"expression
starred_and_keywords ::= ("*"expression
|keyword_item
) ("," "*"expression
| ","keyword_item
)* keywords_arguments ::= (keyword_item
| "**"expression
) (","keyword_item
| "," "**"expression
)* keyword_item ::=identifier
"="expression
位置引數和關鍵字引數之後可以有一個可選的尾隨逗號,但不會影響語義。
主要物件必須求值為一個可呼叫物件(使用者定義的函式、內建函式、內建物件的方法、類物件、類例項的方法以及所有具有__call__()
方法的物件都是可呼叫的)。在嘗試呼叫之前,將評估所有引數表示式。有關形式引數列表的語法,請參閱函式定義部分。
如果存在關鍵字引數,它們首先被轉換為位置引數,如下所示。首先,為形式引數建立一個未填充的槽列表。如果有 N 個位置引數,則將它們放置在前 N 個槽中。接下來,對於每個關鍵字引數,使用識別符號來確定相應的槽(如果識別符號與第一個形式引數名稱相同,則使用第一個槽,依此類推)。如果該槽已被填充,則會引發TypeError
異常。否則,該引數將被放置在該槽中,填充它(即使表示式為None
,也會填充該槽)。當所有引數都已處理完畢後,仍未填充的槽將使用函式定義中的相應預設值填充。(預設值是在定義函式時計算一次;因此,用作預設值的可變物件(如列表或字典)將被所有不為相應槽指定引數值的呼叫共享;通常應避免這種情況。)如果有任何未填充的槽沒有指定預設值,則會引發TypeError
異常。否則,填充的槽列表將用作呼叫的引數列表。
CPython 實現細節: 一個實現可能會提供一些內建函式,這些函式的位置引數沒有名稱,即使它們為了文件的目的而“命名”,因此不能透過關鍵字提供。在 CPython 中,對於使用PyArg_ParseTuple()
來解析其引數的 C 實現的函式來說,情況就是如此。
如果位置引數的數量多於形式引數槽的數量,則會引發TypeError
異常,除非存在使用語法*identifier
的形式引數;在這種情況下,該形式引數接收一個包含多餘的位置引數的元組(如果沒有多餘的位置引數,則接收一個空元組)。
如果任何關鍵字引數與形式引數名稱不對應,則會引發TypeError
異常,除非存在使用語法**identifier
的形式引數;在這種情況下,該形式引數接收一個字典,其中包含多餘的關鍵字引數(使用關鍵字作為鍵,引數值作為對應的值),如果沒有多餘的關鍵字引數,則接收一個(新的)空字典。
如果語法*expression
出現在函式呼叫中,則expression
必須求值為一個可迭代物件。來自這些可迭代物件的元素被視為附加的位置引數。對於呼叫f(x1, x2, *y, x3, x4)
,如果y求值為一個序列y1,…,yM,則等效於呼叫 M+4 個位置引數 x1, x2, y1, …, yM, x3, x4。
這樣做的結果是,儘管*expression
語法可能出現在顯式關鍵字引數之後,但它會在關鍵字引數(以及任何**expression
引數 – 見下文)之前被處理。所以
>>> def f(a, b):
... print(a, b)
...
>>> f(b=1, *(2,))
2 1
>>> f(a=1, *(2,))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f() got multiple values for keyword argument 'a'
>>> f(1, *(2,))
1 2
在同一個呼叫中同時使用關鍵字引數和*expression
語法是不尋常的,因此實際上這種混淆通常不會發生。
如果語法**expression
出現在函式呼叫中,則expression
必須求值為一個對映,其內容被視為附加的關鍵字引數。如果與鍵匹配的引數已被賦予一個值(透過顯式關鍵字引數或來自另一個解包),則會引發TypeError
異常。
當使用**expression
時,此對映中的每個鍵都必須是一個字串。對映中的每個值都將分配給第一個符合關鍵字賦值條件的形式引數,其名稱與該鍵相同。鍵不必是 Python 識別符號(例如,"max-temp °F"
是可以接受的,儘管它不會與任何可以宣告的形式引數匹配)。如果沒有與形式引數匹配的項,則鍵值對將由**
引數收集(如果存在),如果不存在,則會引發TypeError
異常。
使用 *identifier
或 **identifier
語法的形式引數不能用作位置引數槽或關鍵字引數名稱。
在 3.5 版本中更改: 函式呼叫接受任意數量的 *
和 **
解包,位置引數可以跟隨可迭代物件解包 (*
),並且關鍵字引數可以跟隨字典解包 (**
)。最初由 PEP 448 提出。
除非引發異常,否則呼叫總是返回某個值,可能是 None
。此值的計算方式取決於可呼叫物件的型別。
如果它是—
- 使用者定義的函式
將執行該函式的程式碼塊,並傳遞引數列表。程式碼塊要做的第一件事是將形式引數繫結到實參;這在 函式定義 部分中進行了描述。當代碼塊執行
return
語句時,這將指定函式呼叫的返回值。如果執行到達程式碼塊末尾而沒有執行return
語句,則返回值為None
。- 內建函式或方法
結果取決於直譯器;有關內建函式和方法的描述,請參閱 內建函式。
- 類物件
返回該類的新例項。
- 類例項方法
呼叫相應的使用者定義函式,其引數列表比呼叫的引數列表長一個:例項成為第一個引數。
- 類例項
該類必須定義一個
__call__()
方法;然後效果與呼叫該方法相同。
6.4. Await 表示式¶
暫停 協程 在 可等待 物件上的執行。只能在 協程函式 內部使用。
await_expr ::= "await" primary
在 3.5 版本中新增。
6.5. 冪運算子¶
冪運算子的繫結比其左側的一元運算子更緊密;它比其右側的一元運算子繫結得更鬆散。語法是
power ::= (await_expr
|primary
) ["**"u_expr
]
因此,在沒有括號的冪運算子和一元運算子序列中,運算子從右向左求值(這不會限制運算元的求值順序):-1**2
的結果為 -1
。
當使用兩個引數呼叫時,冪運算子具有與內建 pow()
函式相同的語義:它產生其左引數的右引數次冪。數值引數首先被轉換為公共型別,並且結果是該型別。
對於 int 運算元,除非第二個引數為負數,否則結果與運算元具有相同的型別;在這種情況下,所有引數都轉換為 float 並傳遞 float 結果。例如,10**2
返回 100
,但 10**-2
返回 0.01
。
將 0.0
提升為負冪會導致 ZeroDivisionError
。將負數提升為分數冪會導致 complex
數字。(在早期版本中,它引發了 ValueError
。)
可以使用特殊的 __pow__()
和 __rpow__()
方法自定義此操作。
6.6. 一元算術和按位運算¶
所有一元算術和按位運算具有相同的優先順序
u_expr ::=power
| "-"u_expr
| "+"u_expr
| "~"u_expr
一元 -
(減號)運算子產生其數值引數的否定;可以使用 __neg__()
特殊方法覆蓋該操作。
一元 +
(加號)運算子產生其數值引數不變;可以使用 __pos__()
特殊方法覆蓋該操作。
一元 ~
(取反)運算子產生其整數引數的按位取反。 x
的按位取反定義為 -(x+1)
。它僅適用於整數或覆蓋 __invert__()
特殊方法的自定義物件。
在所有三種情況下,如果引數沒有正確的型別,則會引發 TypeError
異常。
6.7. 二元算術運算¶
二元算術運算具有傳統的優先順序。請注意,其中一些運算也適用於某些非數值型別。除了冪運算子之外,只有兩個級別,一個用於乘法運算子,另一個用於加法運算子
m_expr ::=u_expr
|m_expr
"*"u_expr
|m_expr
"@"m_expr
|m_expr
"//"u_expr
|m_expr
"/"u_expr
|m_expr
"%"u_expr
a_expr ::=m_expr
|a_expr
"+"m_expr
|a_expr
"-"m_expr
*
(乘法)運算子產生其引數的乘積。引數必須都是數字,或者一個引數必須是整數,另一個引數必須是序列。在前一種情況下,數字將轉換為公共型別,然後相乘在一起。在後一種情況下,執行序列重複;負重複因子產生一個空序列。
可以使用特殊的 __mul__()
和 __rmul__()
方法自定義此操作。
@
(at)運算子旨在用於矩陣乘法。沒有內建的 Python 型別實現此運算子。
可以使用特殊的 __matmul__()
和 __rmatmul__()
方法自定義此操作。
在 3.5 版本中新增。
/
(除法)和 //
(向下取整除法)運算子產生其引數的商。數值引數首先被轉換為公共型別。整數除法產生浮點數,而整數向下取整除法產生整數;結果是數學除法的結果,對該結果應用“floor”函式。除以零會引發 ZeroDivisionError
異常。
可以使用特殊的 __truediv__()
和 __rtruediv__()
方法自定義除法運算。可以使用特殊的 __floordiv__()
和 __rfloordiv__()
方法自定義向下取整除法運算。
%
(取模)運算子產生第一個引數除以第二個引數的餘數。數值引數首先被轉換為公共型別。零右引數引發 ZeroDivisionError
異常。引數可以是浮點數,例如,3.14%0.7
等於 0.34
(因為 3.14
等於 4*0.7 + 0.34
)。取模運算子總是產生一個與其第二個運算元(或零)具有相同符號的結果;結果的絕對值嚴格小於第二個運算元的絕對值 [1]。
向下取整除法和取模運算子由以下恆等式連線:x == (x//y)*y + (x%y)
。向下取整除法和取模也與內建函式 divmod()
連線:divmod(x, y) == (x//y, x%y)
。[2]。
除了對數字執行模運算外,%
運算子也被字串物件過載以執行舊式字串格式化(也稱為插值)。字串格式化的語法在 Python 庫參考的 printf 樣式字串格式化 部分中描述。
模運算可以使用特殊的 __mod__()
和 __rmod__()
方法進行自定義。
對於複數,未定義向下取整除法運算子、模運算子和 divmod()
函式。如果適用,請使用 abs()
函式將其轉換為浮點數。
+
(加法)運算子產生其引數之和。引數必須都是數字或都是相同型別的序列。在前一種情況下,數字將轉換為通用型別,然後相加。在後一種情況下,序列將被連線。
可以使用特殊的 __add__()
和 __radd__()
方法自定義此操作。
-
(減法)運算子產生其引數之差。數字引數首先會轉換為通用型別。
可以使用特殊的 __sub__()
和 __rsub__()
方法自定義此操作。
6.8. 移位操作¶
移位運算的優先順序低於算術運算
shift_expr ::=a_expr
|shift_expr
("<<" | ">>")a_expr
這些運算子接受整數作為引數。它們將第一個引數向左或向右移動第二個引數給定的位數。
可以使用特殊的 __lshift__()
和 __rlshift__()
方法自定義左移操作。可以使用特殊的 __rshift__()
和 __rrshift__()
方法自定義右移操作。
右移 n 位定義為向下取整除以 pow(2,n)
。左移 n 位定義為乘以 pow(2,n)
。
6.9. 二進位制按位運算¶
三個按位運算中的每一個都有不同的優先順序
and_expr ::=shift_expr
|and_expr
"&"shift_expr
xor_expr ::=and_expr
|xor_expr
"^"and_expr
or_expr ::=xor_expr
|or_expr
"|"xor_expr
&
運算子產生其引數的按位與,這些引數必須是整數,或者其中一個必須是重寫 __and__()
或 __rand__()
特殊方法的自定義物件。
^
運算子產生其引數的按位異或(獨佔 OR),這些引數必須是整數,或者其中一個必須是重寫 __xor__()
或 __rxor__()
特殊方法的自定義物件。
|
運算子產生其引數的按位(包括)或,這些引數必須是整數,或者其中一個必須是重寫 __or__()
或 __ror__()
特殊方法的自定義物件。
6.10. 比較¶
與 C 不同,Python 中的所有比較操作都具有相同的優先順序,該優先順序低於任何算術、移位或按位運算的優先順序。同樣與 C 不同的是,像 a < b < c
這樣的表示式具有數學中傳統的解釋
comparison ::=or_expr
(comp_operator
or_expr
)* comp_operator ::= "<" | ">" | "==" | ">=" | "<=" | "!=" | "is" ["not"] | ["not"] "in"
比較產生布爾值:True
或 False
。自定義的 *富比較方法* 可能會返回非布林值。在這種情況下,Python 將在布林上下文中對此值呼叫 bool()
。
比較可以任意連結,例如,x < y <= z
等價於 x < y and y <= z
,只是 y
只被計算一次(但在兩種情況下,當發現 x < y
為假時,z
都不會被計算)。
形式上,如果 a、b、c、…、y、z 是表示式,op1、op2、…、opN 是比較運算子,則 a op1 b op2 c ... y opN z
等價於 a op1 b and b op2 c and ... y opN z
,只是每個表示式最多計算一次。
請注意,a op1 b op2 c
並不意味著 a 和 c 之間有任何形式的比較,因此,例如,x < y > z
是完全合法的(儘管可能不太好看)。
6.10.1. 值比較¶
運算子 <
、>
、==
、>=
、<=
和 !=
比較兩個物件的值。物件不需要具有相同的型別。
第 物件、值和型別 章指出,物件具有一個值(除了型別和標識)。物件的值在 Python 中是一個相當抽象的概念:例如,沒有用於訪問物件值的規範方法。此外,不要求以特定方式構造物件的值,例如由其所有資料屬性組成。比較運算子實現了物件值的特定概念。可以將它們視為透過它們的比較實現間接地定義物件的值。
因為所有型別都是 object
的(直接或間接)子型別,它們從 object
繼承預設的比較行為。型別可以透過實現 *富比較方法*(如 __lt__()
)來自定義它們的比較行為,如 基本自定義 中所述。
相等比較(==
和 !=
)的預設行為基於物件的標識。因此,具有相同標識的例項的相等比較導致相等,而具有不同標識的例項的相等比較導致不相等。這種預設行為的一個動機是希望所有物件都是自反的(即,x is y
意味著 x == y
)。
不提供預設的順序比較(<
、>
、<=
和 >=
);嘗試會引發 TypeError
。這種預設行為的一個動機是缺少與相等類似的不可變數。
預設相等比較的行為(即具有不同標識的例項始終不相等)可能與那些需要對物件值和基於值的相等性進行合理定義的型別相反。此類型別將需要自定義其比較行為,事實上,許多內建型別已經這樣做了。
以下列表描述了最重要的內建型別的比較行為。
內建數值型別(數值型別 — int、float、complex)以及標準庫型別
fractions.Fraction
和decimal.Decimal
的數值可以在它們型別內部以及跨型別之間進行比較,但複數不支援順序比較。在所涉及型別的限制範圍內,它們的比較在數學上(演算法上)是正確的,且不會損失精度。非數字值
float('NaN')
和decimal.Decimal('NaN')
是特殊的。任何數字與非數字值的有序比較都為假。一個反直覺的含義是非數字值不等於自身。例如,如果x = float('NaN')
,則3 < x
、x < 3
和x == x
均為假,而x != x
為真。此行為符合 IEEE 754 標準。None
和NotImplemented
是單例物件。 PEP 8 建議對單例物件的比較應始終使用is
或is not
,絕不使用相等運算子。二進位制序列(
bytes
或bytearray
的例項)可以在其型別內部和跨型別之間進行比較。 它們使用元素的數值按字典順序進行比較。字串(
str
的例項)使用其字元的數字 Unicode 程式碼點(內建函式ord()
的結果)按字典順序進行比較。 [3]字串和二進位制序列不能直接比較。
序列(
tuple
、list
或range
的例項)只能在各自型別內部進行比較,但範圍不支援順序比較。跨這些型別進行相等比較會導致不相等,跨這些型別進行排序比較會引發TypeError
。序列使用對應元素的比較按字典順序進行比較。內建容器通常假設相同的物件等於它們自身。這允許它們繞過對相同物件的相等性測試,以提高效能並維護其內部不變性。
內建集合之間的字典順序比較的工作方式如下:
要使兩個集合比較相等,它們必須是相同的型別,具有相同的長度,並且每對對應的元素必須比較相等(例如,
[1,2] == (1,2)
為假,因為型別不同)。支援順序比較的集合按其第一個不相等的元素的順序排序(例如,
[1,2,x] <= [1,2,y]
的值與x <= y
的值相同)。如果對應的元素不存在,則較短的集合排序靠前(例如,[1,2] < [1,2,3]
為真)。
對映(
dict
的例項)當且僅當它們具有相等的(key, value)
對時才比較相等。鍵和值的相等性比較會強制執行自反性。順序比較(
<
、>
、<=
和>=
)會引發TypeError
。集合(
set
或frozenset
的例項)可以在其型別內部和跨型別之間進行比較。它們定義順序比較運算子來表示子集和超集測試。 這些關係不定義全序(例如,兩個集合
{1,2}
和{2,3}
不相等,也不是彼此的子集,也不是彼此的超集)。因此,集合不適合作為依賴於全序的函式的引數(例如,min()
、max()
和sorted()
在給定集合列表作為輸入時會產生未定義的結果)。集合的比較會強制執行其元素的自反性。
大多數其他內建型別沒有實現比較方法,因此它們繼承預設的比較行為。
自定義其比較行為的使用者定義類應儘可能遵循一些一致性規則:
相等比較應該是自反的。 換句話說,相同的物件應該比較相等。
x is y
意味著x == y
比較應該是對稱的。 換句話說,以下表達式應該具有相同的結果:
x == y
和y == x
x != y
和y != x
x < y
和y > x
x <= y
和y >= x
比較應該是傳遞的。以下(非詳盡的)示例說明了這一點:
x > y and y > z
意味著x > z
x < y and y <= z
意味著x < z
反向比較應導致布林否定。 換句話說,以下表達式應該具有相同的結果:
x == y
和not x != y
x < y
和not x >= y
(對於全序)x > y
和not x <= y
(對於全序)最後兩個表示式適用於完全排序的集合(例如,序列,但不適用於集合或對映)。另請參閱
total_ordering()
裝飾器。hash()
的結果應與相等性一致。相等的物件應具有相同的雜湊值,或者被標記為不可雜湊。
Python 不會強制執行這些一致性規則。實際上,非數字值就是一個不遵循這些規則的例子。
6.10.2. 成員檢測操作¶
運算子 in
和 not in
用於測試成員關係。x in s
的求值結果為 True
,如果 x 是 s 的成員,否則為 False
。x not in s
返回 x in s
的否定。所有內建的序列和集合型別都支援此操作,字典也支援,其中 in
測試字典是否具有給定的鍵。對於諸如列表、元組、集合、frozenset、字典或 collections.deque 之類的容器型別,表示式 x in y
等效於 any(x is e or x == e for e in y)
。
對於字串和位元組型別,當且僅當 x 是 y 的子字串時,x in y
為 True
。等效的測試是 y.find(x) != -1
。空字串始終被認為是任何其他字串的子字串,因此 "" in "abc"
將返回 True
。
對於定義了 __contains__()
方法的使用者定義類,如果 y.__contains__(x)
返回 true 值,則 x in y
返回 True
,否則返回 False
。
對於未定義 __contains__()
但定義了 __iter__()
的使用者定義類,如果迭代 y
時生成了某個值 z
,並且表示式 x is z or x == z
為 true,則 x in y
為 True
。如果在迭代過程中引發異常,則如同 in
引發了該異常。
最後,嘗試舊式迭代協議:如果一個類定義了 __getitem__()
,當且僅當存在一個非負整數索引 i,使得 x is y[i] or x == y[i]
,並且沒有更小的整數索引引發 IndexError
異常時,x in y
為 True
。(如果引發任何其他異常,則如同 in
引發了該異常)。
6.10.3. 身份比較¶
運算子 is
和 is not
測試物件的身份:當且僅當 x 和 y 是同一個物件時,x is y
為 true。物件的身份使用 id()
函式確定。x is not y
產生相反的真值。[4]
6.11. 布林運算¶
or_test ::=and_test
|or_test
"or"and_test
and_test ::=not_test
|and_test
"and"not_test
not_test ::=comparison
| "not"not_test
在布林運算的上下文中,以及當表示式被控制流語句使用時,以下值被解釋為 false:False
、None
、所有型別的數值零以及空字串和容器(包括字串、元組、列表、字典、集合和凍結集合)。所有其他值都解釋為 true。使用者定義的物件可以透過提供 __bool__()
方法來定製它們的真值。
運算子 not
如果其引數為 false,則返回 True
,否則返回 False
。
表示式 x and y
首先計算 x;如果 x 為 false,則返回其值;否則,計算 y 並返回結果值。
表示式 x or y
首先計算 x;如果 x 為 true,則返回其值;否則,計算 y 並返回結果值。
請注意,and
和 or
都不限制它們返回的值和型別為 False
和 True
,而是返回最後計算的引數。這有時很有用,例如,如果 s
是一個字串,如果它為空,則應替換為預設值,則表示式 s or 'foo'
會產生所需的值。因為 not
必須建立一個新值,所以它會返回一個布林值,而不管其引數的型別如何(例如,not 'foo'
會產生 False
而不是 ''
)。
6.12. 賦值表示式¶
assignment_expression ::= [identifier
":="]expression
賦值表示式(有時也稱為“命名錶達式”或“海象”)將一個 expression
賦值給一個 identifier
,同時返回 expression
的值。
一個常見的用例是在處理匹配的正則表示式時
if matching := pattern.search(data):
do_something(matching)
或者,當按塊處理檔案流時
while chunk := file.read(9000):
process(chunk)
當賦值表示式用作表示式語句以及用作切片、條件、lambda、關鍵字引數和推導式 if 表示式中的子表示式以及 assert
、with
和 assignment
語句時,必須用括號括起來。在所有其他可以使用它們的地方,都不需要括號,包括在 if
和 while
語句中。
在 3.8 版本中新增: 有關賦值表示式的更多詳細資訊,請參閱 PEP 572。
6.13. 條件表示式¶
conditional_expression ::=or_test
["if"or_test
"else"expression
] expression ::=conditional_expression
|lambda_expr
條件表示式(有時稱為“三元運算子”)在所有 Python 操作中優先順序最低。
表示式 x if C else y
首先計算條件 C,而不是 x。如果 C 為 true,則計算 x 並返回其值;否則,計算 y 並返回其值。
有關條件表示式的更多詳細資訊,請參閱 PEP 308。
6.14. Lambdas¶
lambda_expr ::= "lambda" [parameter_list
] ":"expression
Lambda 表示式(有時稱為 lambda 形式)用於建立匿名函式。表示式 lambda parameters: expression
產生一個函式物件。未命名的物件的行為類似於用以下方式定義的函式物件
def <lambda>(parameters):
return expression
有關引數列表的語法,請參閱 函式定義 部分。請注意,使用 lambda 表示式建立的函式不能包含語句或註釋。
6.15. 表示式列表¶
starred_expression ::= ["*"]or_expr
flexible_expression ::=assignment_expression
|starred_expression
flexible_expression_list ::=flexible_expression
(","flexible_expression
)* [","] starred_expression_list ::=starred_expression
(","starred_expression
)* [","] expression_list ::=expression
(","expression
)* [","] yield_list ::=expression_list
|starred_expression
"," [starred_expression_list
]
除非是列表或集合顯示的一部分,否則包含至少一個逗號的表示式列表會產生一個元組。元組的長度是列表中表達式的數量。表示式從左到右求值。
星號 *
表示可迭代物件解包。它的運算元必須是可迭代物件。可迭代物件被展開成一系列項,這些項被包含在新元組、列表或集合中,在解包的位置。
3.5 版本新增: 表示式列表中的可迭代物件解包,最初由PEP 448 提出。
3.11 版本新增: 表示式列表中的任何項都可以使用星號。參見 PEP 646。
只有建立一個單項元組時才需要尾隨逗號,例如 1,
;在所有其他情況下,它是可選的。不帶尾隨逗號的單個表示式不會建立元組,而是產生該表示式的值。(要建立一個空元組,請使用一對空括號:()
。)
6.16. 求值順序¶
Python 從左到右求值表示式。請注意,在求值賦值時,會先求值右側,然後再求值左側。
在以下各行中,表示式將按照其後綴的算術順序求值
expr1, expr2, expr3, expr4
(expr1, expr2, expr3, expr4)
{expr1: expr2, expr3: expr4}
expr1 + expr2 * (expr3 - expr4)
expr1(expr2, expr3, *expr4, **expr5)
expr3, expr4 = expr1, expr2
6.17. 運算子優先順序¶
下表總結了 Python 中運算子的優先順序,從最高優先順序(最強結合)到最低優先順序(最弱結合)。同一框中的運算子具有相同的優先順序。除非明確給出語法,否則運算子是二元的。同一框中的運算子從左到右分組(除了指數運算和條件表示式,它們從右到左分組)。
請注意,比較、成員資格測試和身份測試都具有相同的優先順序,並且具有如 比較 部分所述的從左到右的鏈式特性。
運算子 |
描述 |
---|---|
|
繫結或加括號的表示式,列表顯示,字典顯示,集合顯示 |
|
下標,切片,呼叫,屬性引用 |
Await 表示式 |
|
|
指數運算 [5] |
|
正號,負號,按位 NOT |
|
乘法、矩陣乘法、除法、向下取整除法、餘數 [6] |
|
加法和減法 |
|
移位 |
|
按位 AND |
|
按位 XOR |
|
按位 OR |
比較,包括成員資格測試和身份測試 |
|
布林 NOT |
|
布林 AND |
|
布林 OR |
|
|
條件表示式 |
Lambda 表示式 |
|
|
賦值表示式 |
腳註