3. 數據模型?
3.1. 對象、值與類(lèi)型?
對象 是 Python 中對數據的抽象。 Python 程序中的所有數據都是由對象或對象間關(guān)系來(lái)表示的。 (從某種意義上說(shuō),按照馮·諾依曼的“存儲程序計算機”模型,代碼本身也是由對象來(lái)表示的。)
每個(gè)對象都有各自的標識號、類(lèi)型和值。一個(gè)對象被創(chuàng )建后,它的 標識號 就絕不會(huì )改變;你可以將其理解為該對象在內存中的地址。 'is
' 運算符可以比較兩個(gè)對象的標識號是否相同;id()
函數能返回一個(gè)代表其標識號的整數。
CPython implementation detail: 在 CPython 中,id(x)
就是存放 x
的內存的地址。
對象的類(lèi)型決定該對象所支持的操作 (例如 "對象是否有長(cháng)度屬性?") 并且定義了該類(lèi)型的對象可能的取值。type()
函數能返回一個(gè)對象的類(lèi)型 (類(lèi)型本身也是對象)。與編號一樣,一個(gè)對象的 類(lèi)型 也是不可改變的。1
有些對象的 值 可以改變。值可以改變的對象被稱(chēng)為 可變對象;值不可以改變的對象就被稱(chēng)為 不可變對象。(一個(gè)不可變容器對象如果包含對可變對象的引用,當后者的值改變時(shí),前者的值也會(huì )改變;但是該容器仍屬于不可變對象,因為它所包含的對象集是不會(huì )改變的。因此,不可變并不嚴格等同于值不能改變,實(shí)際含義要更微妙。) 一個(gè)對象的可變性是由其類(lèi)型決定的;例如,數字、字符串和元組是不可變的,而字典和列表是可變的。
對象絕不會(huì )被顯式地銷(xiāo)毀;然而,當無(wú)法訪(fǎng)問(wèn)時(shí)它們可能會(huì )被作為垃圾回收。允許具體的實(shí)現推遲垃圾回收或完全省略此機制 --- 如何實(shí)現垃圾回收是實(shí)現的質(zhì)量問(wèn)題,只要可訪(fǎng)問(wèn)的對象不會(huì )被回收即可。
CPython implementation detail: CPython 目前使用帶有 (可選) 延遲檢測循環(huán)鏈接垃圾的引用計數方案,會(huì )在對象不可訪(fǎng)問(wèn)時(shí)立即回收其中的大部分,但不保證回收包含循環(huán)引用的垃圾。請查看 gc
模塊的文檔了解如何控制循環(huán)垃圾的收集相關(guān)信息。其他實(shí)現會(huì )有不同的行為方式,CPython 現有方式也可能改變。不要依賴(lài)不可訪(fǎng)問(wèn)對象的立即終結機制 (所以你應當總是顯式地關(guān)閉文件)。
注意:使用實(shí)現的跟蹤或調試功能可能令正常情況下會(huì )被回收的對象繼續存活。還要注意通過(guò) 'try
...except
' 語(yǔ)句捕捉異常也可能令對象保持存活。
有些對象包含對 "外部" 資源的引用,例如打開(kāi)文件或窗口。當對象被作為垃圾回收時(shí)這些資源也應該會(huì )被釋放,但由于垃圾回收并不確保發(fā)生,這些對象還提供了明確地釋放外部資源的操作,通常為一個(gè) close()
方法。強烈推薦在程序中顯式關(guān)閉此類(lèi)對象。'try
...finally
' 語(yǔ)句和 'with
' 語(yǔ)句提供了進(jìn)行此種操作的更便捷方式。
有些對象包含對其他對象的引用;它們被稱(chēng)為 容器。容器的例子有元組、列表和字典等。這些引用是容器對象值的組成部分。在多數情況下,當談?wù)撘粋€(gè)容器的值時(shí),我們是指所包含對象的值而不是其編號;但是,當我們談?wù)撘粋€(gè)容器的可變性時(shí),則僅指其直接包含的對象的編號。因此,如果一個(gè)不可變容器 (例如元組) 包含對一個(gè)可變對象的引用,則當該可變對象被改變時(shí)容器的值也會(huì )改變。
類(lèi)型會(huì )影響對象行為的幾乎所有方面。甚至對象編號的重要性也在某種程度上受到影響: 對于不可變類(lèi)型,會(huì )得出新值的運算實(shí)際上會(huì )返回對相同類(lèi)型和取值的任一現有對象的引用,而對于可變類(lèi)型來(lái)說(shuō)這是不允許的。例如在 a = 1; b = 1
之后,a
和 b
可能會(huì )也可能不會(huì )指向同一個(gè)值為一的對象,這取決于具體實(shí)現,但是在 c = []; d = []
之后,c
和 d
保證會(huì )指向兩個(gè)不同、單獨的新建空列表。(請注意 c = d = []
則是將同一個(gè)對象賦值給 c
和 d
。)
3.2. 標準類(lèi)型層級結構?
以下是 Python 內置類(lèi)型的列表。擴展模塊 (具體實(shí)現會(huì )以 C, Java 或其他語(yǔ)言編寫(xiě)) 可以定義更多的類(lèi)型。未來(lái)版本的 Python 可能會(huì )加入更多的類(lèi)型 (例如有理數、高效存儲的整型數組等等),不過(guò)新增類(lèi)型往往都是通過(guò)標準庫來(lái)提供的。
以下部分類(lèi)型的描述中包含有 '特殊屬性列表' 段落。這些屬性提供對具體實(shí)現的訪(fǎng)問(wèn)而非通常使用。它們的定義在未來(lái)可能會(huì )改變。
- None
此類(lèi)型只有一種取值。是一個(gè)具有此值的單獨對象。此對象通過(guò)內置名稱(chēng)
None
訪(fǎng)問(wèn)。在許多情況下它被用來(lái)表示空值,例如未顯式指明返回值的函數將返回 None。它的邏輯值為假。- NotImplemented
此類(lèi)型只有一種取值。 是一個(gè)具有該值的單獨對象。 此對象通過(guò)內置名稱(chēng)
NotImplemented
訪(fǎng)問(wèn)。 數值方法和豐富比較方法如未實(shí)現指定運算符表示的運算則應返回該值。 (解釋器會(huì )根據具體運算符繼續嘗試反向運算或其他回退操作。) 它不應被解讀為布爾值。詳情參見(jiàn) 實(shí)現算術(shù)運算。
在 3.9 版更改: 作為布爾值來(lái)解讀
NotImplemented
已被棄用。 雖然它目前會(huì )被解讀為真值,但將同時(shí)發(fā)出DeprecationWarning
。 它將在未來(lái)的 Python 版本中引發(fā)TypeError
。- Ellipsis
此類(lèi)型只有一種取值。是一個(gè)具有此值的單獨對象。此對象通過(guò)字面值
...
或內置名稱(chēng)Ellipsis
訪(fǎng)問(wèn)。它的邏輯值為真。numbers.Number
此類(lèi)對象由數字字面值創(chuàng )建,并會(huì )被作為算術(shù)運算符和算術(shù)內置函數的返回結果。數字對象是不可變的;一旦創(chuàng )建其值就不再改變。Python 中的數字當然非常類(lèi)似數學(xué)中的數字,但也受限于計算機中的數字表示方法。
The string representations of the numeric classes, computed by
__repr__()
and__str__()
, have the following properties:它們是有效的數字字面值,當被傳給它們的類(lèi)構造器時(shí),將會(huì )產(chǎn)生具有原數字值的對象。
表示形式會(huì )在可能的情況下采用 10 進(jìn)制。
開(kāi)頭的零,除小數點(diǎn)前可能存在的單個(gè)零之外,將不會(huì )被顯示。
末尾的零,除小數點(diǎn)后可能存在的單個(gè)零之外,將不會(huì )被顯示。
正負號僅在當數字為負值時(shí)會(huì )被顯示。
Python 區分整型數、浮點(diǎn)型數和復數:
numbers.Integral
此類(lèi)對象表示數學(xué)中整數集合的成員 (包括正數和負數)。
整型數可細分為兩種類(lèi)型:
- 整型 (
int
) 此類(lèi)對象表示任意大小的數字,僅受限于可用的內存 (包括虛擬內存)。在變換和掩碼運算中會(huì )以二進(jìn)制表示,負數會(huì )以 2 的補碼表示,看起來(lái)像是符號位向左延伸補滿(mǎn)空位。
- 布爾型 (
bool
) 此類(lèi)對象表示邏輯值 False 和 True。代表
False
和True
值的兩個(gè)對象是唯二的布爾對象。布爾類(lèi)型是整型的子類(lèi)型,兩個(gè)布爾值在各種場(chǎng)合的行為分別類(lèi)似于數值 0 和 1,例外情況只有在轉換為字符串時(shí)分別返回字符串"False"
或"True"
。
整型數表示規則的目的是在涉及負整型數的變換和掩碼運算時(shí)提供最為合理的解釋。
- 整型 (
numbers.Real
(float
)此類(lèi)對象表示機器級的雙精度浮點(diǎn)數。其所接受的取值范圍和溢出處理將受制于底層的機器架構 (以及 C 或 Java 實(shí)現)。Python 不支持單精度浮點(diǎn)數;支持后者通常的理由是節省處理器和內存消耗,但這點(diǎn)節省相對于在 Python 中使用對象的開(kāi)銷(xiāo)來(lái)說(shuō)太過(guò)微不足道,因此沒(méi)有理由包含兩種浮點(diǎn)數而令該語(yǔ)言變得復雜。
numbers.Complex
(complex
)此類(lèi)對象以一對機器級的雙精度浮點(diǎn)數來(lái)表示復數值。有關(guān)浮點(diǎn)數的附帶規則對其同樣有效。一個(gè)復數值
z
的實(shí)部和虛部可通過(guò)只讀屬性z.real
和z.imag
來(lái)獲取。
- 序列
此類(lèi)對象表示以非負整數作為索引的有限有序集。內置函數
len()
可返回一個(gè)序列的條目數量。當一個(gè)序列的長(cháng)度為 n 時(shí),索引集包含數字 0, 1, ..., n-1。序列 a 的條目 i 可通過(guò)a[i]
選擇。序列還支持切片:
a[i:j]
選擇索引號為 k 的所有條目,i<=
k<
j。當用作表達式時(shí),序列的切片就是一個(gè)與序列類(lèi)型相同的新序列。新序列的索引還是從 0 開(kāi)始。有些序列還支持帶有第三個(gè) "step" 形參的 "擴展切片":
a[i:j:k]
選擇 a 中索引號為 x 的所有條目,x = i + n*k
, n>=
0
且 i<=
x<
j。序列可根據其可變性來(lái)加以區分:
- 不可變序列
不可變序列類(lèi)型的對象一旦創(chuàng )建就不能再改變。(如果對象包含對其他對象的引用,其中的可變對象就是可以改變的;但是,一個(gè)不可變對象所直接引用的對象集是不能改變的。)
以下類(lèi)型屬于不可變對象:
- 字符串
字符串是由 Unicode 碼位值組成的序列。范圍在
U+0000 - U+10FFFF
之內的所有碼位值都可在字符串中使用。Python 沒(méi)有 char 類(lèi)型;而是將字符串中的每個(gè)碼位表示為一個(gè)長(cháng)度為1
的字符串對象。內置函數ord()
可將一個(gè)碼位由字符串形式轉換成一個(gè)范圍在0 - 10FFFF
之內的整型數;chr()
可將一個(gè)范圍在0 - 10FFFF
之內的整型數轉換為長(cháng)度為1
的對應字符串對象。str.encode()
可以使用指定的文本編碼將str
轉換為bytes
,而bytes.decode()
則可以實(shí)現反向的解碼。- 元組
一個(gè)元組中的條目可以是任意 Python 對象。包含兩個(gè)或以上條目的元組由逗號分隔的表達式構成。只有一個(gè)條目的元組 ('單項元組') 可通過(guò)在表達式后加一個(gè)逗號來(lái)構成 (一個(gè)表達式本身不能創(chuàng )建為元組,因為圓括號要用來(lái)設置表達式分組)。一個(gè)空元組可通過(guò)一對內容為空的圓括號創(chuàng )建。
- 字節串
字節串對象是不可變的數組。其中每個(gè)條目都是一個(gè) 8 位字節,以取值范圍 0 <= x < 256 的整型數表示。字節串字面值 (例如
b'abc'
) 和內置的bytes()
構造器可被用來(lái)創(chuàng )建字節串對象。字節串對象還可以通過(guò)decode()
方法解碼為字符串。
- 可變序列
可變序列在被創(chuàng )建后仍可被改變。下標和切片標注可被用作賦值和
del
(刪除) 語(yǔ)句的目標。目前有兩種內生可變序列類(lèi)型:
- 列表
列表中的條目可以是任意 Python 對象。列表由用方括號括起并由逗號分隔的多個(gè)表達式構成。(注意創(chuàng )建長(cháng)度為 0 或 1 的列表無(wú)需使用特殊規則。)
- 字節數組
字節數組對象屬于可變數組??梢酝ㄟ^(guò)內置的
bytearray()
構造器來(lái)創(chuàng )建。除了是可變的 (因而也是不可哈希的),在其他方面字節數組提供的接口和功能都與不可變的bytes
對象一致。
擴展模塊
array
提供了一個(gè)額外的可變序列類(lèi)型示例,collections
模塊也是如此。
- 集合類(lèi)型
此類(lèi)對象表示由不重復且不可變對象組成的無(wú)序且有限的集合。因此它們不能通過(guò)下標來(lái)索引。但是它們可被迭代,也可用內置函數
len()
返回集合中的條目數。集合常見(jiàn)的用處是快速成員檢測,去除序列中的重復項,以及進(jìn)行交、并、差和對稱(chēng)差等數學(xué)運算。對于集合元素所采用的不可變規則與字典的鍵相同。注意數字類(lèi)型遵循正常的數字比較規則: 如果兩個(gè)數字相等 (例如
1
和1.0
),則同一集合中只能包含其中一個(gè)。目前有兩種內生集合類(lèi)型:
- 集合
此類(lèi)對象表示可變集合。它們可通過(guò)內置的
set()
構造器創(chuàng )建,并且創(chuàng )建之后可以通過(guò)方法進(jìn)行修改,例如add()
。- 凍結集合
此類(lèi)對象表示不可變集合。它們可通過(guò)內置的
frozenset()
構造器創(chuàng )建。由于 frozenset 對象不可變且 hashable,它可以被用作另一個(gè)集合的元素或是字典的鍵。
- 映射
此類(lèi)對象表示由任意索引集合所索引的對象的集合。通過(guò)下標
a[k]
可在映射a
中選擇索引為k
的條目;這可以在表達式中使用,也可作為賦值或del
語(yǔ)句的目標。內置函數len()
可返回一個(gè)映射中的條目數。目前只有一種內生映射類(lèi)型:
- 字典
此類(lèi)對象表示由幾乎任意值作為索引的有限個(gè)對象的集合。不可作為鍵的值類(lèi)型只有包含列表或字典或其他可變類(lèi)型,通過(guò)值而非對象編號進(jìn)行比較的值,其原因在于高效的字典實(shí)現需要使用鍵的哈希值以保持一致性。用作鍵的數字類(lèi)型遵循正常的數字比較規則: 如果兩個(gè)數字相等 (例如
1
和1.0
) 則它們均可來(lái)用來(lái)索引同一個(gè)字典條目。字典會(huì )保留插入順序,這意味著(zhù)鍵將以它們被添加的順序在字典中依次產(chǎn)生。 替換某個(gè)現有的鍵不會(huì )改變其順序,但是移除某個(gè)鍵再重新插入則會(huì )將其添加到末尾而不會(huì )保留其原有位置。
字典是可變的;它們可通過(guò)
{...}
標注來(lái)創(chuàng )建 (參見(jiàn) 字典顯示 小節)。擴展模塊
dbm.ndbm
和dbm.gnu
提供了額外的映射類(lèi)型示例,collections
模塊也是如此。在 3.7 版更改: 在 Python 3.6 版之前字典不會(huì )保留插入順序。 在 CPython 3.6 中插入順序會(huì )被保留,但這在當時(shí)被當作是一個(gè)實(shí)現細節而非確定的語(yǔ)言特性。
- 可調用類(lèi)型
此類(lèi)型可以被應用于函數調用操作 (參見(jiàn) 調用 小節):
- 用戶(hù)定義函數
用戶(hù)定義函數對象可通過(guò)函數定義來(lái)創(chuàng )建 (參見(jiàn) 函數定義 小節)。它被調用時(shí)應附帶一個(gè)參數列表,其中包含的條目應與函數所定義的形參列表一致。
特殊屬性:
屬性
含意
__doc__
該函數的文檔字符串,沒(méi)有則為
None
;不會(huì )被子類(lèi)繼承。可寫(xiě)
該函數的名稱(chēng)。
可寫(xiě)
該函數的 qualified name。
3.3 新版功能.
可寫(xiě)
__module__
該函數所屬模塊的名稱(chēng),沒(méi)有則為
None
。可寫(xiě)
__defaults__
由具有默認值的參數的默認參數值組成的元組,如無(wú)任何參數具有默認值則為
None
。可寫(xiě)
__code__
表示編譯后的函數體的代碼對象。
可寫(xiě)
__globals__
對存放該函數中全局變量的字典的引用 --- 函數所屬模塊的全局命名空間。
只讀
命名空間支持的函數屬性。
可寫(xiě)
__closure__
None
或包含該函數可用變量的綁定的單元的元組。有關(guān)cell_contents
屬性的詳情見(jiàn)下。只讀
__annotations__
包含形參標注的字典。 字典的鍵是形參名,而如果提供了
'return'
則是用于返回值標注。 有關(guān)如何使用此屬性的更多信息,請參閱 對象注解屬性的最佳實(shí)踐。可寫(xiě)
__kwdefaults__
僅包含關(guān)鍵字參數默認值的字典。
可寫(xiě)
大部分標有 "Writable" 的屬性均會(huì )檢查賦值的類(lèi)型。
函數對象也支持獲取和設置任意屬性,例如這可以被用來(lái)給函數附加元數據。使用正規的屬性點(diǎn)號標注獲取和設置此類(lèi)屬性。注意當前實(shí)現僅支持用戶(hù)定義函數屬性。未來(lái)可能會(huì )增加支持內置函數屬性。
單元對象具有
cell_contents
屬性。這可被用來(lái)獲取以及設置單元的值。有關(guān)函數定義的額外信息可以從其代碼對象中提??;參見(jiàn)下文對內部類(lèi)型的描述。
cell
類(lèi)型可以在types
模塊中訪(fǎng)問(wèn)。- 實(shí)例方法
實(shí)例方法用于結合類(lèi)、類(lèi)實(shí)例和任何可調用對象 (通常為用戶(hù)定義函數)。
特殊的只讀屬性:
__self__
為類(lèi)實(shí)例對象本身,__func__
為函數對象;__doc__
為方法的文檔 (與__func__.__doc__
作用相同);__name__
為方法名稱(chēng) (與__func__.__name__
作用相同);__module__
為方法所屬模塊的名稱(chēng),沒(méi)有則為None
。方法還支持獲取 (但不能設置) 下層函數對象的任意函數屬性。
用戶(hù)定義方法對象可在獲取一個(gè)類(lèi)的屬性時(shí)被創(chuàng )建 (也可能通過(guò)該類(lèi)的一個(gè)實(shí)例),如果該屬性為用戶(hù)定義函數對象或類(lèi)方法對象。
當通過(guò)從類(lèi)實(shí)例獲取一個(gè)用戶(hù)定義函數對象的方式創(chuàng )建一個(gè)實(shí)例方法對象時(shí),類(lèi)實(shí)例對象的
__self__
屬性即為該實(shí)例,并會(huì )綁定方法對象。該新建方法的__func__
屬性就是原來(lái)的函數對象。當通過(guò)從類(lèi)或實(shí)例獲取一個(gè)類(lèi)方法對象的方式創(chuàng )建一個(gè)實(shí)例對象時(shí),實(shí)例對象的
__self__
屬性為該類(lèi)本身,其__func__
屬性為類(lèi)方法對應的下層函數對象。當一個(gè)實(shí)例方法對象被調用時(shí),會(huì )調用對應的下層函數 (
__func__
),并將類(lèi)實(shí)例 (__self__
) 插入參數列表的開(kāi)頭。例如,當C
是一個(gè)包含了f()
函數定義的類(lèi),而x
是C
的一個(gè)實(shí)例,則調用x.f(1)
就等同于調用C.f(x, 1)
。當一個(gè)實(shí)例方法對象是衍生自一個(gè)類(lèi)方法對象時(shí),保存在
__self__
中的 "類(lèi)實(shí)例" 實(shí)際上會(huì )是該類(lèi)本身,因此無(wú)論是調用x.f(1)
還是C.f(1)
都等同于調用f(C,1)
,其中f
為對應的下層函數。請注意從函數對象到實(shí)例方法對象的變換會(huì )在每一次從實(shí)例獲取屬性時(shí)發(fā)生。在某些情況下,一種高效的優(yōu)化方式是將屬性賦值給一個(gè)本地變量并調用該本地變量。還要注意這樣的變換只發(fā)生于用戶(hù)定義函數;其他可調用對象 (以及所有不可調用對象) 在被獲取時(shí)都不會(huì )發(fā)生變換。還有一個(gè)需要關(guān)注的要點(diǎn)是作為一個(gè)類(lèi)實(shí)例屬性的用戶(hù)定義函數不會(huì )被轉換為綁定方法;這樣的變換 僅當 函數是類(lèi)屬性時(shí)才會(huì )發(fā)生。
- 生成器函數
A function or method which uses the
yield
statement (see section yield 語(yǔ)句) is called a generator function. Such a function, when called, always returns an iterator object which can be used to execute the body of the function: calling the iterator'siterator.__next__()
method will cause the function to execute until it provides a value using theyield
statement. When the function executes areturn
statement or falls off the end, aStopIteration
exception is raised and the iterator will have reached the end of the set of values to be returned.- 協(xié)程函數
使用
async def
來(lái)定義的函數或方法就被稱(chēng)為 協(xié)程函數。這樣的函數在被調用時(shí)會(huì )返回一個(gè) coroutine 對象。它可能包含await
表達式以及async with
和async for
語(yǔ)句。詳情可參見(jiàn) 協(xié)程對象 一節。- 異步生成器函數
A function or method which is defined using
async def
and which uses theyield
statement is called a asynchronous generator function. Such a function, when called, returns an asynchronous iterator object which can be used in anasync for
statement to execute the body of the function.Calling the asynchronous iterator's
aiterator.__anext__
method will return an awaitable which when awaited will execute until it provides a value using theyield
expression. When the function executes an emptyreturn
statement or falls off the end, aStopAsyncIteration
exception is raised and the asynchronous iterator will have reached the end of the set of values to be yielded.- 內置函數
內置函數對象是對于 C 函數的外部封裝。內置函數的例子包括
len()
和math.sin()
(math
是一個(gè)標準內置模塊)。內置函數參數的數量和類(lèi)型由 C 函數決定。特殊的只讀屬性:__doc__
是函數的文檔字符串,如果沒(méi)有則為None
;__name__
是函數的名稱(chēng);__self__
設定為None
(參見(jiàn)下一條目);__module__
是函數所屬模塊的名稱(chēng),如果沒(méi)有則為None
。- 內置方法
此類(lèi)型實(shí)際上是內置函數的另一種形式,只不過(guò)還包含了一個(gè)傳入 C 函數的對象作為隱式的額外參數。內置方法的一個(gè)例子是
alist.append()
,其中 alist 為一個(gè)列表對象。在此示例中,特殊的只讀屬性__self__
會(huì )被設為 alist 所標記的對象。- 類(lèi)
Classes are callable. These objects normally act as factories for new instances of themselves, but variations are possible for class types that override
__new__()
. The arguments of the call are passed to__new__()
and, in the typical case, to__init__()
to initialize the new instance.- 類(lèi)實(shí)例
Instances of arbitrary classes can be made callable by defining a
__call__()
method in their class.
- 模塊
模塊是 Python 代碼的基本組織單元,由 導入系統 創(chuàng )建,由
import
語(yǔ)句發(fā)起調用,或者通過(guò)importlib.import_module()
和內置的__import__()
等函數發(fā)起調用。 模塊對象具有由字典對象實(shí)現的命名空間(這是被模塊中定義的函數的__globals__
屬性引用的字典)。 屬性引用被轉換為該字典中的查找,例如m.x
相當于m.__dict__["x"]
。 模塊對象不包含用于初始化模塊的代碼對象(因為初始化完成后不需要它)。屬性賦值會(huì )更新模塊的命名空間字典,例如
m.x = 1
等同于m.__dict__["x"] = 1
。預先定義的(可寫(xiě))屬性:
__name__
模塊的名稱(chēng)。
__doc__
模塊的文檔字符串,如果不可用則為
None
。__file__
被加載模塊所對應文件的路徑名稱(chēng),如果它是從文件加載的話(huà)。 對于某些類(lèi)型的模塊來(lái)說(shuō)
__file__
屬性可能是缺失的,例如被靜態(tài)鏈接到解釋器中的 C 模塊。 對于從共享庫動(dòng)態(tài)加載的擴展模塊來(lái)說(shuō),它將是共享庫文件的路徑名稱(chēng)。__annotations__
包含在模塊體執行期間收集的 變量標注 的字典。 有關(guān)使用
__annotations__
的最佳實(shí)踐,請參閱 對象注解屬性的最佳實(shí)踐。
特殊的只讀屬性:
__dict__
為以字典對象表示的模塊命名空間。CPython implementation detail: 由于 CPython 清理模塊字典的設定,當模塊離開(kāi)作用域時(shí)模塊字典將會(huì )被清理,即使該字典還有活動(dòng)的引用。想避免此問(wèn)題,可復制該字典或保持模塊狀態(tài)以直接使用其字典。
- 自定義類(lèi)
自定義類(lèi)這種類(lèi)型一般通過(guò)類(lèi)定義來(lái)創(chuàng )建 (參見(jiàn) 類(lèi)定義 一節)。每個(gè)類(lèi)都有通過(guò)一個(gè)字典對象實(shí)現的獨立命名空間。類(lèi)屬性引用會(huì )被轉化為在此字典中查找,例如
C.x
會(huì )被轉化為C.__dict__["x"]
(不過(guò)也存在一些鉤子對象以允許其他定位屬性的方式)。當未在其中發(fā)現某個(gè)屬性名稱(chēng)時(shí),會(huì )繼續在基類(lèi)中查找。這種基類(lèi)查找使用 C3 方法解析順序,即使存在 '鉆石形' 繼承結構即有多條繼承路徑連到一個(gè)共同祖先也能保持正確的行為。有關(guān) Python 使用的 C3 MRO 的詳情可查看配合 2.3 版發(fā)布的文檔 https://www.python.org/download/releases/2.3/mro/.當一個(gè)類(lèi)屬性引用 (假設類(lèi)名為
C
) 會(huì )產(chǎn)生一個(gè)類(lèi)方法對象時(shí),它將轉化為一個(gè)__self__
屬性為C
的實(shí)例方法對象。當其會(huì )產(chǎn)生一個(gè)靜態(tài)方法對象時(shí),它將轉化為該靜態(tài)方法對象所封裝的對象。從類(lèi)的__dict__
所包含內容以外獲取屬性的其他方式請參看 實(shí)現描述器 一節。類(lèi)屬性賦值會(huì )更新類(lèi)的字典,但不會(huì )更新基類(lèi)的字典。
類(lèi)對象可被調用 (見(jiàn)上文) 以產(chǎn)生一個(gè)類(lèi)實(shí)例 (見(jiàn)下文)。
特殊屬性:
__name__
類(lèi)的名稱(chēng)。
__module__
類(lèi)定義所在模塊的名稱(chēng)。
__dict__
包含類(lèi)命名空間的字典。
__bases__
包含基類(lèi)的元組,按它們在基類(lèi)列表中的出現先后排序。
__doc__
類(lèi)的文檔字符串,如果未定義則為
None
。__annotations__
包含在類(lèi)體執行期間收集的 變量標注 的字典。 有關(guān)使用
__annotations__
的最佳實(shí)踐,請參閱 對象注解屬性的最佳實(shí)踐。
- 類(lèi)實(shí)例
A class instance is created by calling a class object (see above). A class instance has a namespace implemented as a dictionary which is the first place in which attribute references are searched. When an attribute is not found there, and the instance's class has an attribute by that name, the search continues with the class attributes. If a class attribute is found that is a user-defined function object, it is transformed into an instance method object whose
__self__
attribute is the instance. Static method and class method objects are also transformed; see above under "Classes". See section 實(shí)現描述器 for another way in which attributes of a class retrieved via its instances may differ from the objects actually stored in the class's__dict__
. If no class attribute is found, and the object's class has a__getattr__()
method, that is called to satisfy the lookup.Attribute assignments and deletions update the instance's dictionary, never a class's dictionary. If the class has a
__setattr__()
or__delattr__()
method, this is called instead of updating the instance dictionary directly.如果類(lèi)實(shí)例具有某些特殊名稱(chēng)的方法,就可以偽裝為數字、序列或映射。參見(jiàn) 特殊方法名稱(chēng) 一節。
- I/O 對象 (或稱(chēng)文件對象)
file object 表示一個(gè)打開(kāi)的文件。有多種快捷方式可用來(lái)創(chuàng )建文件對象:
open()
內置函數,以及os.popen()
,os.fdopen()
和 socket 對象的makefile()
方法 (還可能使用某些擴展模塊所提供的其他函數或方法)。sys.stdin
,sys.stdout
和sys.stderr
會(huì )初始化為對應于解釋器標準輸入、輸出和錯誤流的文件對象;它們都會(huì )以文本模式打開(kāi),因此都遵循io.TextIOBase
抽象類(lèi)所定義的接口。- 內部類(lèi)型
某些由解釋器內部使用的類(lèi)型也被暴露給用戶(hù)。它們的定義可能隨未來(lái)解釋器版本的更新而變化,為內容完整起見(jiàn)在此處一并介紹。
- 代碼對象
代碼對象表示 編譯為字節的 可執行 Python 代碼,或稱(chēng) bytecode。代碼對象和函數對象的區別在于函數對象包含對函數全局對象 (函數所屬的模塊) 的顯式引用,而代碼對象不包含上下文;而且默認參數值會(huì )存放于函數對象而不是代碼對象內 (因為它們表示在運行時(shí)算出的值)。與函數對象不同,代碼對象不可變,也不包含對可變對象的引用 (不論是直接還是間接)。
Special read-only attributes:
co_name
gives the function name;co_qualname
gives the fully qualified function name;co_argcount
is the total number of positional arguments (including positional-only arguments and arguments with default values);co_posonlyargcount
is the number of positional-only arguments (including arguments with default values);co_kwonlyargcount
is the number of keyword-only arguments (including arguments with default values);co_nlocals
is the number of local variables used by the function (including arguments);co_varnames
is a tuple containing the names of the local variables (starting with the argument names);co_cellvars
is a tuple containing the names of local variables that are referenced by nested functions;co_freevars
is a tuple containing the names of free variables;co_code
is a string representing the sequence of bytecode instructions;co_consts
is a tuple containing the literals used by the bytecode;co_names
is a tuple containing the names used by the bytecode;co_filename
is the filename from which the code was compiled;co_firstlineno
is the first line number of the function;co_lnotab
is a string encoding the mapping from bytecode offsets to line numbers (for details see the source code of the interpreter);co_stacksize
is the required stack size;co_flags
is an integer encoding a number of flags for the interpreter.以下是可用于
co_flags
的標志位定義:如果函數使用*arguments
語(yǔ)法來(lái)接受任意數量的位置參數,則0x04
位被設置;如果函數使用**keywords
語(yǔ)法來(lái)接受任意數量的關(guān)鍵字參數,則0x08
位被設置;如果函數是一個(gè)生成器,則0x20
位被設置。未來(lái)特性聲明 (
from __future__ import division
) 也使用co_flags
中的標志位來(lái)指明代碼對象的編譯是否啟用特定的特性: 如果函數編譯時(shí)啟用未來(lái)除法特性則設置0x2000
位; 在更早的 Python 版本中則使用0x10
和0x1000
位。co_flags
中的其他位被保留為內部使用。如果代碼對象表示一個(gè)函數,
co_consts
中的第一項將是函數的文檔字符串,如果未定義則為None
。- codeobject.co_positions()?
Returns an iterable over the source code positions of each bytecode instruction in the code object.
The iterator returns tuples containing the
(start_line, end_line, start_column, end_column)
. The i-th tuple corresponds to the position of the source code that compiled to the i-th instruction. Column information is 0-indexed utf-8 byte offsets on the given source line.This positional information can be missing. A non-exhaustive lists of cases where this may happen:
Running the interpreter with
-X
no_debug_ranges
.Loading a pyc file compiled while using
-X
no_debug_ranges
.Position tuples corresponding to artificial instructions.
Line and column numbers that can't be represented due to implementation specific limitations.
When this occurs, some or all of the tuple elements can be
None
.3.11 新版功能.
備注
This feature requires storing column positions in code objects which may result in a small increase of disk usage of compiled Python files or interpreter memory usage. To avoid storing the extra information and/or deactivate printing the extra traceback information, the
-X
no_debug_ranges
command line flag or thePYTHONNODEBUGRANGES
environment variable can be used.
- 幀對象
幀對象表示執行幀。它們可能出現在回溯對象中 (見(jiàn)下文),還會(huì )被傳遞給注冊跟蹤函數。
特殊的只讀屬性:
f_back
為前一堆棧幀 (指向調用者),如是最底層堆棧幀則為None
;f_code
為此幀中所執行的代碼對象;f_locals
為用于查找本地變量的字典;f_globals
則用于查找全局變量;f_builtins
用于查找內置 (固有) 名稱(chēng);f_lasti
給出精確指令 (這是代碼對象的字節碼字符串的一個(gè)索引)。訪(fǎng)問(wèn)
f_code
會(huì )引發(fā)一個(gè) 審計事件object.__getattr__
,附帶參數obj
和"f_code"
。特殊的可寫(xiě)屬性:
f_trace
,如果不為None
,則是在代碼執行期間調用各類(lèi)事件的函數 (由調試器使用)。通常每個(gè)新源碼行會(huì )觸發(fā)一個(gè)事件 - 這可以通過(guò)將f_trace_lines
設為False
來(lái)禁用。具體的實(shí)現 可能 會(huì )通過(guò)將
f_trace_opcodes
設為True
來(lái)允許按操作碼請求事件。請注意如果跟蹤函數引發(fā)的異常逃逸到被跟蹤的函數中,這可能會(huì )導致未定義的解釋器行為。f_lineno
為幀的當前行號 --- 在這里寫(xiě)入從一個(gè)跟蹤函數內部跳轉的指定行 (僅用于最底層的幀)。調試器可以通過(guò)寫(xiě)入 f_lineno 實(shí)現一個(gè) Jump 命令 (即設置下一語(yǔ)句)。幀對象支持一個(gè)方法:
- frame.clear()?
此方法清除該幀持有的全部對本地變量的引用。而且如果該幀屬于一個(gè)生成器,生成器會(huì )被完成。這有助于打破包含幀對象的循環(huán)引用 (例如當捕獲一個(gè)異常并保存其回溯在之后使用)。
如果該幀當前正在執行則會(huì )引發(fā)
RuntimeError
。3.4 新版功能.
- 回溯對象
回溯對象表示一個(gè)異常的棧跟蹤記錄。當異常發(fā)生時(shí)會(huì )隱式地創(chuàng )建一個(gè)回溯對象,也可能通過(guò)調用
types.TracebackType
顯式地創(chuàng )建。對于隱式地創(chuàng )建的回溯對象,當查找異常句柄使得執行棧展開(kāi)時(shí),會(huì )在每個(gè)展開(kāi)層級的當前回溯之前插入一個(gè)回溯對象。當進(jìn)入一個(gè)異常句柄時(shí),棧跟蹤將對程序啟用。(參見(jiàn) try 語(yǔ)句 一節。) 它可作為
sys.exc_info()
所返回的元組的第三項,以及所捕獲異常的__traceback__
屬性被獲取。當程序不包含可用的句柄時(shí),棧跟蹤會(huì ) (以良好的格式) 寫(xiě)入標準錯誤流;如果解釋器處于交互模式,它也可作為
sys.last_traceback
對用戶(hù)啟用。對于顯式創(chuàng )建的回溯對象,則由回溯對象的創(chuàng )建者來(lái)決定應該如何鏈接
tb_next
屬性來(lái)構成完整的棧跟蹤。特殊的只讀屬性:
tb_frame
指向當前層級的執行幀;tb_lineno
給出發(fā)生異常所在的行號;tb_lasti
標示具體指令。如果異常發(fā)生于沒(méi)有匹配的 except 子句或有 finally 子句的try
語(yǔ)句中,回溯對象中的行號和最后指令可能與相應幀對象中行號不同。訪(fǎng)問(wèn)
tb_frame
會(huì )引發(fā)一個(gè) 審計事件object.__getattr__
,附帶參數obj
和"tb_frame"
。特殊的可寫(xiě)屬性:
tb_next
為棧跟蹤中的下一層級 (通往發(fā)生異常的幀),如果沒(méi)有下一層級則為None
。在 3.7 版更改: 回溯對象現在可以使用 Python 代碼顯式地實(shí)例化,現有實(shí)例的
tb_next
屬性可以被更新。- 切片對象
Slice objects are used to represent slices for
__getitem__()
methods. They are also created by the built-inslice()
function.特殊的只讀屬性:
start
為下界;stop
為上界;step
為步長(cháng)值; 各值如省略則為None
。這些屬性可具有任意類(lèi)型。切片對象支持一個(gè)方法:
- slice.indices(self, length)?
此方法接受一個(gè)整型參數 length 并計算在切片對象被應用到 length 指定長(cháng)度的條目序列時(shí)切片的相關(guān)信息應如何描述。 其返回值為三個(gè)整型數組成的元組;這些數分別為切片的 start 和 stop 索引號以及 step 步長(cháng)值。索引號缺失或越界則按照與正規切片相一致的方式處理。
- 靜態(tài)方法對象
靜態(tài)方法對象提供了一種勝過(guò)上文所述將函數對象轉換為方法對象的方式。 靜態(tài)方法對象是對任意其他對象的包裝器,通常用來(lái)包裝用戶(hù)自定義的方法對象。 當從類(lèi)或類(lèi)實(shí)例獲取一個(gè)靜態(tài)方法對象時(shí),實(shí)際返回的是經(jīng)過(guò)包裝的對象,它不會(huì )被進(jìn)一步轉換。 靜態(tài)方法對象也是可調用對象。 靜態(tài)方法對象可通過(guò)內置的
staticmethod()
構造器來(lái)創(chuàng )建。- 類(lèi)方法對象
類(lèi)方法對象和靜態(tài)方法一樣是對其他對象的封裝,會(huì )改變從類(lèi)或類(lèi)實(shí)例獲取該對象的方式。類(lèi)方法對象在此類(lèi)獲取操作中的行為已在上文 "用戶(hù)定義方法" 一節中描述。類(lèi)方法對象可通過(guò)內置的
classmethod()
構造器來(lái)創(chuàng )建。
3.3. 特殊方法名稱(chēng)?
A class can implement certain operations that are invoked by special syntax
(such as arithmetic operations or subscripting and slicing) by defining methods
with special names. This is Python's approach to operator overloading,
allowing classes to define their own behavior with respect to language
operators. For instance, if a class defines a method named
__getitem__()
,
and x
is an instance of this class, then x[i]
is roughly equivalent
to type(x).__getitem__(x, i)
. Except where mentioned, attempts to execute an
operation raise an exception when no appropriate method is defined (typically
AttributeError
or TypeError
).
Setting a special method to None
indicates that the corresponding
operation is not available. For example, if a class sets
__iter__()
to None
, the class is not iterable, so calling
iter()
on its instances will raise a TypeError
(without
falling back to __getitem__()
). 2
在實(shí)現模擬任何內置類(lèi)型的類(lèi)時(shí),很重要的一點(diǎn)是模擬的實(shí)現程度對于被模擬對象來(lái)說(shuō)應當是有意義的。例如,提取單個(gè)元素的操作對于某些序列來(lái)說(shuō)是適宜的,但提取切片可能就沒(méi)有意義。(這種情況的一個(gè)實(shí)例是 W3C 的文檔對象模型中的 NodeList
接口。)
3.3.1. 基本定制?
- object.__new__(cls[, ...])?
調用以創(chuàng )建一個(gè) cls 類(lèi)的新實(shí)例。
__new__()
是一個(gè)靜態(tài)方法 (因為是特例所以你不需要顯式地聲明),它會(huì )將所請求實(shí)例所屬的類(lèi)作為第一個(gè)參數。其余的參數會(huì )被傳遞給對象構造器表達式 (對類(lèi)的調用)。__new__()
的返回值應為新對象實(shí)例 (通常是 cls 的實(shí)例)。典型的實(shí)現會(huì )附帶適宜的參數使用
super().__new__(cls[, ...])
,通過(guò)超類(lèi)的__new__()
方法來(lái)創(chuàng )建一個(gè)類(lèi)的新實(shí)例,然后根據需要修改新創(chuàng )建的實(shí)例再將其返回。If
__new__()
is invoked during object construction and it returns an instance of cls, then the new instance’s__init__()
method will be invoked like__init__(self[, ...])
, where self is the new instance and the remaining arguments are the same as were passed to the object constructor.如果
__new__()
未返回一個(gè) cls 的實(shí)例,則新實(shí)例的__init__()
方法就不會(huì )被執行。__new__()
的目的主要是允許不可變類(lèi)型的子類(lèi) (例如 int, str 或 tuple) 定制實(shí)例創(chuàng )建過(guò)程。它也常會(huì )在自定義元類(lèi)中被重載以便定制類(lèi)創(chuàng )建過(guò)程。
- object.__init__(self[, ...])?
在實(shí)例 (通過(guò)
__new__()
) 被創(chuàng )建之后,返回調用者之前調用。其參數與傳遞給類(lèi)構造器表達式的參數相同。一個(gè)基類(lèi)如果有__init__()
方法,則其所派生的類(lèi)如果也有__init__()
方法,就必須顯式地調用它以確保實(shí)例基類(lèi)部分的正確初始化;例如:super().__init__([args...])
.因為對象是由
__new__()
和__init__()
協(xié)作構造完成的 (由__new__()
創(chuàng )建,并由__init__()
定制),所以__init__()
返回的值只能是None
,否則會(huì )在運行時(shí)引發(fā)TypeError
。
- object.__del__(self)?
在實(shí)例將被銷(xiāo)毀時(shí)調用。 這還被稱(chēng)為終結器或析構器(不適當)。 如果一個(gè)基類(lèi)具有
__del__()
方法,則其所派生的類(lèi)如果也有__del__()
方法,就必須顯式地調用它以確保實(shí)例基類(lèi)部分的正確清除。__del__()
方法可以 (但不推薦!) 通過(guò)創(chuàng )建一個(gè)該實(shí)例的新引用來(lái)推遲其銷(xiāo)毀。這被稱(chēng)為對象 重生。__del__()
是否會(huì )在重生的對象將被銷(xiāo)毀時(shí)再次被調用是由具體實(shí)現決定的 ;當前的 CPython 實(shí)現只會(huì )調用一次。當解釋器退出時(shí)不會(huì )確保為仍然存在的對象調用
__del__()
方法。備注
del x
并不直接調用x.__del__()
--- 前者會(huì )將x
的引用計數減一,而后者僅會(huì )在x
的引用計數變?yōu)榱銜r(shí)被調用。CPython implementation detail: It is possible for a reference cycle to prevent the reference count of an object from going to zero. In this case, the cycle will be later detected and deleted by the cyclic garbage collector. A common cause of reference cycles is when an exception has been caught in a local variable. The frame's locals then reference the exception, which references its own traceback, which references the locals of all frames caught in the traceback.
參見(jiàn)
gc
模塊的文檔。警告
由于調用
__del__()
方法時(shí)周邊狀況已不確定,在其執行期間發(fā)生的異常將被忽略,改為打印一個(gè)警告到sys.stderr
。特別地:__del__()
可在任意代碼被執行時(shí)啟用,包括來(lái)自任意線(xiàn)程的代碼。如果__del__()
需要接受鎖或啟用其他阻塞資源,可能會(huì )發(fā)生死鎖,例如該資源已被為執行__del__()
而中斷的代碼所獲取。__del__()
可以在解釋器關(guān)閉階段被執行。因此,它需要訪(fǎng)問(wèn)的全局變量(包含其他模塊)可能已被刪除或設為None
。Python 會(huì )保證先刪除模塊中名稱(chēng)以單個(gè)下劃線(xiàn)打頭的全局變量再刪除其他全局變量;如果已不存在其他對此類(lèi)全局變量的引用,這有助于確保導入的模塊在__del__()
方法被調用時(shí)仍然可用。
- object.__repr__(self)?
由
repr()
內置函數調用以輸出一個(gè)對象的“官方”字符串表示。如果可能,這應類(lèi)似一個(gè)有效的 Python 表達式,能被用來(lái)重建具有相同取值的對象(只要有適當的環(huán)境)。如果這不可能,則應返回形式如<...some useful description...>
的字符串。返回值必須是一個(gè)字符串對象。如果一個(gè)類(lèi)定義了__repr__()
但未定義__str__()
,則在需要該類(lèi)的實(shí)例的“非正式”字符串表示時(shí)也會(huì )使用__repr__()
。此方法通常被用于調試,因此確保其表示的內容包含豐富信息且無(wú)歧義是很重要的。
- object.__str__(self)?
通過(guò)
str(object)
以及內置函數format()
和print()
調用以生成一個(gè)對象的“非正式”或格式良好的字符串表示。返回值必須為一個(gè) 字符串 對象。此方法與
object.__repr__()
的不同點(diǎn)在于__str__()
并不預期返回一個(gè)有效的 Python 表達式:可以使用更方便或更準確的描述信息。內置類(lèi)型
object
所定義的默認實(shí)現會(huì )調用object.__repr__()
。
- object.__format__(self, format_spec)?
通過(guò)
format()
內置函數、擴展、格式化字符串字面值 的求值以及str.format()
方法調用以生成一個(gè)對象的“格式化”字符串表示。 format_spec 參數為包含所需格式選項描述的字符串。 format_spec 參數的解讀是由實(shí)現__format__()
的類(lèi)型決定的,不過(guò)大多數類(lèi)或是將格式化委托給某個(gè)內置類(lèi)型,或是使用相似的格式化選項語(yǔ)法。請參看 格式規格迷你語(yǔ)言 了解標準格式化語(yǔ)法的描述。
返回值必須為一個(gè)字符串對象。
在 3.4 版更改:
object
本身的 __format__ 方法如果被傳入任何非空字符,將會(huì )引發(fā)一個(gè)TypeError
。在 3.7 版更改:
object.__format__(x, '')
現在等同于str(x)
而不再是format(str(x), '')
。
- object.__lt__(self, other)?
- object.__le__(self, other)?
- object.__eq__(self, other)?
- object.__ne__(self, other)?
- object.__gt__(self, other)?
- object.__ge__(self, other)?
以上這些被稱(chēng)為“富比較”方法。運算符號與方法名稱(chēng)的對應關(guān)系如下:
x<y
調用x.__lt__(y)
、x<=y
調用x.__le__(y)
、x==y
調用x.__eq__(y)
、x!=y
調用x.__ne__(y)
、x>y
調用x.__gt__(y)
、x>=y
調用x.__ge__(y)
。如果指定的參數對沒(méi)有相應的實(shí)現,富比較方法可能會(huì )返回單例對象
NotImplemented
。按照慣例,成功的比較會(huì )返回False
或True
。不過(guò)實(shí)際上這些方法可以返回任意值,因此如果比較運算符是要用于布爾值判斷(例如作為if
語(yǔ)句的條件),Python 會(huì )對返回值調用bool()
以確定結果為真還是假。在默認情況下,
object
通過(guò)使用is
來(lái)實(shí)現__eq__()
,并在比較結果為假值時(shí)返回NotImplemented
:True if x is y else NotImplemented
。 對于__ne__()
,默認會(huì )委托給__eq__()
并對結果取反,除非結果為NotImplemented
。 比較運算符之間沒(méi)有其他隱含關(guān)系或默認實(shí)現;例如,(x<y or x==y)
為真并不意味著(zhù)x<=y
。 要根據單根運算自動(dòng)生成排序操作,請參看functools.total_ordering()
。請查看
__hash__()
的相關(guān)段落,了解創(chuàng )建可支持自定義比較運算并可用作字典鍵的 hashable 對象時(shí)要注意的一些事項。這些方法并沒(méi)有對調參數版本(在左邊參數不支持該操作但右邊參數支持時(shí)使用);而是
__lt__()
和__gt__()
互為對方的反射,__le__()
和__ge__()
互為對方的反射,而__eq__()
和__ne__()
則是它們自己的反射。如果兩個(gè)操作數的類(lèi)型不同,且右操作數類(lèi)型是左操作數類(lèi)型的直接或間接子類(lèi),則優(yōu)先選擇右操作數的反射方法,否則優(yōu)先選擇左操作數的方法。虛擬子類(lèi)不會(huì )被考慮。
- object.__hash__(self)?
Called by built-in function
hash()
and for operations on members of hashed collections includingset
,frozenset
, anddict
. The__hash__()
method should return an integer. The only required property is that objects which compare equal have the same hash value; it is advised to mix together the hash values of the components of the object that also play a part in comparison of objects by packing them into a tuple and hashing the tuple. Example:def __hash__(self): return hash((self.name, self.nick, self.color))
備注
hash()
會(huì )從一個(gè)對象自定義的__hash__()
方法返回值中截斷為Py_ssize_t
的大小。通常對 64 位構建為 8 字節,對 32 位構建為 4 字節。如果一個(gè)對象的__hash__()
必須在不同位大小的構建上進(jìn)行互操作,請確保檢查全部所支持構建的寬度。做到這一點(diǎn)的簡(jiǎn)單方法是使用python -c "import sys; print(sys.hash_info.width)"
。如果一個(gè)類(lèi)沒(méi)有定義
__eq__()
方法,那么也不應該定義__hash__()
操作;如果它定義了__eq__()
但沒(méi)有定義__hash__()
,則其實(shí)例將不可被用作可哈希集的項。如果一個(gè)類(lèi)定義了可變對象并實(shí)現了__eq__()
方法,則不應該實(shí)現__hash__()
,因為可哈希集的實(shí)現要求鍵的哈希集是不可變的(如果對象的哈希值發(fā)生改變,它將處于錯誤的哈希桶中)。用戶(hù)定義的類(lèi)默認帶有
__eq__()
和__hash__()
方法;使用它們與任何對象(自己除外)比較必定不相等,并且x.__hash__()
會(huì )返回一個(gè)恰當的值以確保x == y
同時(shí)意味著(zhù)x is y
且hash(x) == hash(y)
。一個(gè)類(lèi)如果重載了
__eq__()
且沒(méi)有定義__hash__()
則會(huì )將其__hash__()
隱式地設為None
。當一個(gè)類(lèi)的__hash__()
方法為None
時(shí),該類(lèi)的實(shí)例將在一個(gè)程序嘗試獲取其哈希值時(shí)正確地引發(fā)TypeError
,并會(huì )在檢測isinstance(obj, collections.abc.Hashable)
時(shí)被正確地識別為不可哈希對象。如果一個(gè)重載了
__eq__()
的類(lèi)需要保留來(lái)自父類(lèi)的__hash__()
實(shí)現,則必須通過(guò)設置__hash__ = <ParentClass>.__hash__
來(lái)顯式地告知解釋器。如果一個(gè)沒(méi)有重載
__eq__()
的類(lèi)需要去掉哈希支持,則應該在類(lèi)定義中包含__hash__ = None
。一個(gè)自定義了__hash__()
以顯式地引發(fā)TypeError
的類(lèi)會(huì )被isinstance(obj, collections.abc.Hashable)
調用錯誤地識別為可哈希對象。備注
在默認情況下,str 和 bytes 對象的
__hash__()
值會(huì )使用一個(gè)不可預知的隨機值“加鹽”。 雖然它們在一個(gè)單獨 Python 進(jìn)程中會(huì )保持不變,但它們的值在重復運行的 Python 間是不可預測的。This is intended to provide protection against a denial-of-service caused by carefully-chosen inputs that exploit the worst case performance of a dict insertion, O(n2) complexity. See http://www.ocert.org/advisories/ocert-2011-003.html for details.
改變哈希值會(huì )影響集合的迭代次序。Python 也從不保證這個(gè)次序不會(huì )被改變(通常它在 32 位和 64 位構建上是不一致的)。
另見(jiàn)
PYTHONHASHSEED
.在 3.3 版更改: 默認啟用哈希隨機化。
- object.__bool__(self)?
調用此方法以實(shí)現真值檢測以及內置的
bool()
操作;應該返回False
或True
。如果未定義此方法,則會(huì )查找并調用__len__()
并在其返回非零值時(shí)視對象的邏輯值為真。如果一個(gè)類(lèi)既未定義__len__()
也未定義__bool__()
則視其所有實(shí)例的邏輯值為真。
3.3.2. 自定義屬性訪(fǎng)問(wèn)?
可以定義下列方法來(lái)自定義對類(lèi)實(shí)例屬性訪(fǎng)問(wèn)(x.name
的使用、賦值或刪除)的具體含義.
- object.__getattr__(self, name)?
當默認屬性訪(fǎng)問(wèn)因引發(fā)
AttributeError
而失敗時(shí)被調用 (可能是調用__getattribute__()
時(shí)由于 name 不是一個(gè)實(shí)例屬性或self
的類(lèi)關(guān)系樹(shù)中的屬性而引發(fā)了AttributeError
;或者是對 name 特性屬性調用__get__()
時(shí)引發(fā)了AttributeError
)。此方法應當返回(找到的)屬性值或是引發(fā)一個(gè)AttributeError
異常。請注意如果屬性是通過(guò)正常機制找到的,
__getattr__()
就不會(huì )被調用。(這是在__getattr__()
和__setattr__()
之間故意設置的不對稱(chēng)性。)這既是出于效率理由也是因為不這樣設置的話(huà)__getattr__()
將無(wú)法訪(fǎng)問(wèn)實(shí)例的其他屬性。要注意至少對于實(shí)例變量來(lái)說(shuō),你不必在實(shí)例屬性字典中插入任何值(而是通過(guò)插入到其他對象)就可以模擬對它的完全控制。請參閱下面的__getattribute__()
方法了解真正獲取對屬性訪(fǎng)問(wèn)的完全控制權的辦法。
- object.__getattribute__(self, name)?
此方法會(huì )無(wú)條件地被調用以實(shí)現對類(lèi)實(shí)例屬性的訪(fǎng)問(wèn)。如果類(lèi)還定義了
__getattr__()
,則后者不會(huì )被調用,除非__getattribute__()
顯式地調用它或是引發(fā)了AttributeError
。此方法應當返回(找到的)屬性值或是引發(fā)一個(gè)AttributeError
異常。為了避免此方法中的無(wú)限遞歸,其實(shí)現應該總是調用具有相同名稱(chēng)的基類(lèi)方法來(lái)訪(fǎng)問(wèn)它所需要的任何屬性,例如object.__getattribute__(self, name)
。備注
此方法在作為通過(guò)特定語(yǔ)法或內置函數隱式地調用的結果的情況下查找特殊方法時(shí)仍可能會(huì )被跳過(guò)。參見(jiàn) 特殊方法查找。
引發(fā)一個(gè) 審計事件
object.__getattr__
,附帶參數obj
,name
。
- object.__setattr__(self, name, value)?
此方法在一個(gè)屬性被嘗試賦值時(shí)被調用。這個(gè)調用會(huì )取代正常機制(即將值保存到實(shí)例字典)。 name 為屬性名稱(chēng), value 為要賦給屬性的值。
如果
__setattr__()
想要賦值給一個(gè)實(shí)例屬性,它應該調用同名的基類(lèi)方法,例如object.__setattr__(self, name, value)
。引發(fā)一個(gè) 審計事件
object.__setattr__
,附帶參數obj
,name
,value
。
- object.__delattr__(self, name)?
類(lèi)似于
__setattr__()
但其作用為刪除而非賦值。此方法應該僅在del obj.name
對于該對象有意義時(shí)才被實(shí)現。引發(fā)一個(gè) 審計事件
object.__delattr__
,附帶參數obj
,name
。
- object.__dir__(self)?
此方法會(huì )在對相應對象調用
dir()
時(shí)被調用。返回值必須為一個(gè)序列。dir()
會(huì )把返回的序列轉換為列表并對其排序。
3.3.2.1. 自定義模塊屬性訪(fǎng)問(wèn)?
特殊名稱(chēng) __getattr__
和 __dir__
還可被用來(lái)自定義對模塊屬性的訪(fǎng)問(wèn)。模塊層級的 __getattr__
函數應當接受一個(gè)參數,其名稱(chēng)為一個(gè)屬性名,并返回計算結果值或引發(fā)一個(gè) AttributeError
。如果通過(guò)正常查找即 object.__getattribute__()
未在模塊對象中找到某個(gè)屬性,則 __getattr__
會(huì )在模塊的 __dict__
中查找,未找到時(shí)會(huì )引發(fā)一個(gè) AttributeError
。如果找到,它會(huì )以屬性名被調用并返回結果值。
__dir__
函數應當不接受任何參數,并且返回一個(gè)表示模塊中可訪(fǎng)問(wèn)名稱(chēng)的字符串序列。 此函數如果存在,將會(huì )重載一個(gè)模塊中的標準 dir()
查找。
想要更細致地自定義模塊的行為(設置屬性和特性屬性等待),可以將模塊對象的 __class__
屬性設置為一個(gè) types.ModuleType
的子類(lèi)。例如:
import sys
from types import ModuleType
class VerboseModule(ModuleType):
def __repr__(self):
return f'Verbose {self.__name__}'
def __setattr__(self, attr, value):
print(f'Setting {attr}...')
super().__setattr__(attr, value)
sys.modules[__name__].__class__ = VerboseModule
備注
定義模塊的 __getattr__
和設置模塊的 __class__
只會(huì )影響使用屬性訪(fǎng)問(wèn)語(yǔ)法進(jìn)行的查找 -- 直接訪(fǎng)問(wèn)模塊全局變量(不論是通過(guò)模塊內的代碼還是通過(guò)對模塊全局字典的引用)是不受影響的。
在 3.5 版更改: __class__
模塊屬性改為可寫(xiě)。
3.7 新版功能: __getattr__
和 __dir__
模塊屬性。
參見(jiàn)
- PEP 562 - 模塊 __getattr__ 和 __dir__
描述用于模塊的
__getattr__
和__dir__
函數。
3.3.2.2. 實(shí)現描述器?
以下方法僅當一個(gè)包含該方法的類(lèi)(稱(chēng)為 描述器 類(lèi))的實(shí)例出現于一個(gè) 所有者 類(lèi)中的時(shí)候才會(huì )起作用(該描述器必須在所有者類(lèi)或其某個(gè)上級類(lèi)的字典中)。在以下示例中,“屬性”指的是名稱(chēng)為所有者類(lèi) __dict__
中的特征屬性的鍵名的屬性。
- object.__get__(self, instance, owner=None)?
調用此方法以獲取所有者類(lèi)的屬性(類(lèi)屬性訪(fǎng)問(wèn))或該類(lèi)的實(shí)例的屬性(實(shí)例屬性訪(fǎng)問(wèn))。 可選的 owner 參數是所有者類(lèi)而 instance 是被用來(lái)訪(fǎng)問(wèn)屬性的實(shí)例,如果通過(guò) owner 來(lái)訪(fǎng)問(wèn)屬性則返回
None
。此方法應當返回計算得到的屬性值或是引發(fā)
AttributeError
異常。PEP 252 指明
__get__()
為帶有一至二個(gè)參數的可調用對象。 Python 自身內置的描述器支持此規格定義;但是,某些第三方工具可能要求必須帶兩個(gè)參數。 Python 自身的__getattribute__()
實(shí)現總是會(huì )傳入兩個(gè)參數,無(wú)論它們是否被要求提供。
- object.__set__(self, instance, value)?
調用此方法以設置 instance 指定的所有者類(lèi)的實(shí)例的屬性為新值 value。
請注意,添加
__set__()
或__delete__()
會(huì )將描述器變成“數據描述器”。 更多細節請參閱 調用描述器。
- object.__delete__(self, instance)?
調用此方法以刪除 instance 指定的所有者類(lèi)的實(shí)例的屬性。
屬性 __objclass__
會(huì )被 inspect
模塊解讀為指定此對象定義所在的類(lèi)(正確設置此屬性有助于動(dòng)態(tài)類(lèi)屬性的運行時(shí)內?。?。對于可調用對象來(lái)說(shuō),它可以指明預期或要求提供一個(gè)特定類(lèi)型(或子類(lèi))的實(shí)例作為第一個(gè)位置參數(例如,CPython 會(huì )為實(shí)現于 C 中的未綁定方法設置此屬性)。
3.3.2.3. 調用描述器?
In general, a descriptor is an object attribute with "binding behavior", one
whose attribute access has been overridden by methods in the descriptor
protocol: __get__()
, __set__()
, and
__delete__()
. If any of
those methods are defined for an object, it is said to be a descriptor.
屬性訪(fǎng)問(wèn)的默認行為是從一個(gè)對象的字典中獲取、設置或刪除屬性。例如,a.x
的查找順序會(huì )從 a.__dict__['x']
開(kāi)始,然后是 type(a).__dict__['x']
,接下來(lái)依次查找 type(a)
的上級基類(lèi),不包括元類(lèi)。
但是,如果找到的值是定義了某個(gè)描述器方法的對象,則 Python 可能會(huì )重載默認行為并轉而發(fā)起調用描述器方法。這具體發(fā)生在優(yōu)先級鏈的哪個(gè)環(huán)節則要根據所定義的描述器方法及其被調用的方式來(lái)決定。
描述器發(fā)起調用的開(kāi)始點(diǎn)是一個(gè)綁定 a.x
。參數的組合方式依 a
而定:
- 直接調用
最簡(jiǎn)單但最不常見(jiàn)的調用方式是用戶(hù)代碼直接發(fā)起調用一個(gè)描述器方法:
x.__get__(a)
。- 實(shí)例綁定
如果綁定到一個(gè)對象實(shí)例,
a.x
會(huì )被轉換為調用:type(a).__dict__['x'].__get__(a, type(a))
。- 類(lèi)綁定
如果綁定到一個(gè)類(lèi),
A.x
會(huì )被轉換為調用:A.__dict__['x'].__get__(None, A)
。- 超綁定
A dotted lookup such as
super(A, a).x
searchesa.__class__.__mro__
for a base classB
followingA
and then returnsB.__dict__['x'].__get__(a, A)
. If not a descriptor,x
is returned unchanged.
For instance bindings, the precedence of descriptor invocation depends on
which descriptor methods are defined. A descriptor can define any combination
of __get__()
, __set__()
and
__delete__()
. If it does not
define __get__()
, then accessing the attribute will return the descriptor
object itself unless there is a value in the object's instance dictionary. If
the descriptor defines __set__()
and/or __delete__()
, it is a data
descriptor; if it defines neither, it is a non-data descriptor. Normally, data
descriptors define both __get__()
and __set__()
, while non-data
descriptors have just the __get__()
method. Data descriptors with
__get__()
and __set__()
(and/or __delete__()
) defined always override a redefinition in an
instance dictionary. In contrast, non-data descriptors can be overridden by
instances.
Python methods (including those decorated with
@staticmethod
and @classmethod
) are
implemented as non-data descriptors. Accordingly, instances can redefine and
override methods. This allows individual instances to acquire behaviors that
differ from other instances of the same class.
property()
函數是作為數據描述器來(lái)實(shí)現的。因此實(shí)例不能重載特性屬性的行為。
3.3.2.4. __slots__?
__slots__ allow us to explicitly declare data members (like
properties) and deny the creation of __dict__
and __weakref__
(unless explicitly declared in __slots__ or available in a parent.)
The space saved over using __dict__
can be significant.
Attribute lookup speed can be significantly improved as well.
- object.__slots__?
This class variable can be assigned a string, iterable, or sequence of strings with variable names used by instances. __slots__ reserves space for the declared variables and prevents the automatic creation of
__dict__
and __weakref__ for each instance.
3.3.2.4.1. 使用 __slots__ 的注意事項?
When inheriting from a class without __slots__, the
__dict__
and __weakref__ attribute of the instances will always be accessible.Without a
__dict__
variable, instances cannot be assigned new variables not listed in the __slots__ definition. Attempts to assign to an unlisted variable name raisesAttributeError
. If dynamic assignment of new variables is desired, then add'__dict__'
to the sequence of strings in the __slots__ declaration.Without a __weakref__ variable for each instance, classes defining __slots__ do not support
weak references
to its instances. If weak reference support is needed, then add'__weakref__'
to the sequence of strings in the __slots__ declaration.__slots__ are implemented at the class level by creating descriptors for each variable name. As a result, class attributes cannot be used to set default values for instance variables defined by __slots__; otherwise, the class attribute would overwrite the descriptor assignment.
The action of a __slots__ declaration is not limited to the class where it is defined. __slots__ declared in parents are available in child classes. However, child subclasses will get a
__dict__
and __weakref__ unless they also define __slots__ (which should only contain names of any additional slots).如果一個(gè)類(lèi)定義的位置在某個(gè)基類(lèi)中也有定義,則由基類(lèi)位置定義的實(shí)例變量將不可訪(fǎng)問(wèn)(除非通過(guò)直接從基類(lèi)獲取其描述器的方式)。這會(huì )使得程序的含義變成未定義。未來(lái)可能會(huì )添加一個(gè)防止此情況的檢查。
非空的 __slots__ 不適用于派生自“可變長(cháng)度”內置類(lèi)型例如
int
、bytes
和tuple
的派生類(lèi)。Any non-string iterable may be assigned to __slots__.
If a
dictionary
is used to assign __slots__, the dictionary keys will be used as the slot names. The values of the dictionary can be used to provide per-attribute docstrings that will be recognised byinspect.getdoc()
and displayed in the output ofhelp()
.__class__
assignment works only if both classes have the same __slots__.Multiple inheritance with multiple slotted parent classes can be used, but only one parent is allowed to have attributes created by slots (the other bases must have empty slot layouts) - violations raise
TypeError
.If an iterator is used for __slots__ then a descriptor is created for each of the iterator's values. However, the __slots__ attribute will be an empty iterator.
3.3.3. 自定義類(lèi)創(chuàng )建?
Whenever a class inherits from another class, __init_subclass__()
is
called on the parent class. This way, it is possible to write classes which
change the behavior of subclasses. This is closely related to class
decorators, but where class decorators only affect the specific class they're
applied to, __init_subclass__
solely applies to future subclasses of the
class defining the method.
- classmethod object.__init_subclass__(cls)?
當所在類(lèi)派生子類(lèi)時(shí)此方法就會(huì )被調用。cls 將指向新的子類(lèi)。如果定義為一個(gè)普通實(shí)例方法,此方法將被隱式地轉換為類(lèi)方法。
傳入一個(gè)新類(lèi)的關(guān)鍵字參數會(huì )被傳給父類(lèi)的
__init_subclass__
。為了與其他使用__init_subclass__
的類(lèi)兼容,應當根據需要去掉部分關(guān)鍵字參數再將其余的傳給基類(lèi),例如:class Philosopher: def __init_subclass__(cls, /, default_name, **kwargs): super().__init_subclass__(**kwargs) cls.default_name = default_name class AustralianPhilosopher(Philosopher, default_name="Bruce"): pass
object.__init_subclass__
的默認實(shí)現什么都不做,只在帶任意參數調用時(shí)引發(fā)一個(gè)錯誤。備注
元類(lèi)提示
metaclass
將被其它類(lèi)型機制消耗掉,并不會(huì )被傳給__init_subclass__
的實(shí)現。實(shí)際的元類(lèi)(而非顯式的提示)可通過(guò)type(cls)
訪(fǎng)問(wèn)。3.6 新版功能.
When a class is created, type.__new__()
scans the class variables
and makes callbacks to those with a __set_name__()
hook.
- object.__set_name__(self, owner, name)?
Automatically called at the time the owning class owner is created. The object has been assigned to name in that class:
class A: x = C() # Automatically calls: x.__set_name__(A, 'x')
If the class variable is assigned after the class is created,
__set_name__()
will not be called automatically. If needed,__set_name__()
can be called directly:class A: pass c = C() A.x = c # The hook is not called c.__set_name__(A, 'x') # Manually invoke the hook
詳情參見(jiàn) 創(chuàng )建類(lèi)對象。
3.6 新版功能.
3.3.3.1. 元類(lèi)?
默認情況下,類(lèi)是使用 type()
來(lái)構建的。類(lèi)體會(huì )在一個(gè)新的命名空間內執行,類(lèi)名會(huì )被局部綁定到 type(name, bases, namespace)
的結果。
類(lèi)創(chuàng )建過(guò)程可通過(guò)在定義行傳入 metaclass
關(guān)鍵字參數,或是通過(guò)繼承一個(gè)包含此參數的現有類(lèi)來(lái)進(jìn)行定制。在以下示例中,MyClass
和 MySubclass
都是 Meta
的實(shí)例:
class Meta(type):
pass
class MyClass(metaclass=Meta):
pass
class MySubclass(MyClass):
pass
在類(lèi)定義內指定的任何其他關(guān)鍵字參數都會(huì )在下面所描述的所有元類(lèi)操作中進(jìn)行傳遞。
當一個(gè)類(lèi)定義被執行時(shí),將發(fā)生以下步驟:
解析 MRO 條目;
確定適當的元類(lèi);
準備類(lèi)命名空間;
執行類(lèi)主體;
創(chuàng )建類(lèi)對象。
3.3.3.2. 解析 MRO 條目?
如果在類(lèi)定義中出現的基類(lèi)不是 type
的實(shí)例,則使用 __mro_entries__
方法對其進(jìn)行搜索,當找到結果時(shí),它會(huì )以原始基類(lèi)元組做參數進(jìn)行調用。此方法必須返回類(lèi)的元組以替代此基類(lèi)被使用。元組可以為空,在此情況下原始基類(lèi)將被忽略。
參見(jiàn)
PEP 560 - 對 typing 模塊和泛型類(lèi)型的核心支持
3.3.3.3. 確定適當的元類(lèi)?
為一個(gè)類(lèi)定義確定適當的元類(lèi)是根據以下規則:
如果沒(méi)有基類(lèi)且沒(méi)有顯式指定元類(lèi),則使用
type()
;如果給出一個(gè)顯式元類(lèi)而且 不是
type()
的實(shí)例,則其會(huì )被直接用作元類(lèi);如果給出一個(gè)
type()
的實(shí)例作為顯式元類(lèi),或是定義了基類(lèi),則使用最近派生的元類(lèi)。
最近派生的元類(lèi)會(huì )從顯式指定的元類(lèi)(如果有)以及所有指定的基類(lèi)的元類(lèi)(即 type(cls)
)中選取。最近派生的元類(lèi)應為 所有 這些候選元類(lèi)的一個(gè)子類(lèi)型。如果沒(méi)有一個(gè)候選元類(lèi)符合該條件,則類(lèi)定義將失敗并拋出 TypeError
。
3.3.3.4. 準備類(lèi)命名空間?
Once the appropriate metaclass has been identified, then the class namespace
is prepared. If the metaclass has a __prepare__
attribute, it is called
as namespace = metaclass.__prepare__(name, bases, **kwds)
(where the
additional keyword arguments, if any, come from the class definition). The
__prepare__
method should be implemented as a
classmethod
. The
namespace returned by __prepare__
is passed in to __new__
, but when
the final class object is created the namespace is copied into a new dict
.
如果元類(lèi)沒(méi)有 __prepare__
屬性,則類(lèi)命名空間將初始化為一個(gè)空的有序映射。
參見(jiàn)
- PEP 3115 - Python 3000 中的元類(lèi)
引入
__prepare__
命名空間鉤子
3.3.3.5. 執行類(lèi)主體?
類(lèi)主體會(huì )以(類(lèi)似于) exec(body, globals(), namespace)
的形式被執行。普通調用與 exec()
的關(guān)鍵區別在于當類(lèi)定義發(fā)生于函數內部時(shí),詞法作用域允許類(lèi)主體(包括任何方法)引用來(lái)自當前和外部作用域的名稱(chēng)。
但是,即使當類(lèi)定義發(fā)生于函數內部時(shí),在類(lèi)內部定義的方法仍然無(wú)法看到在類(lèi)作用域層次上定義的名稱(chēng)。類(lèi)變量必須通過(guò)實(shí)例的第一個(gè)形參或類(lèi)方法來(lái)訪(fǎng)問(wèn),或者是通過(guò)下一節中描述的隱式詞法作用域的 __class__
引用。
3.3.3.6. 創(chuàng )建類(lèi)對象?
一旦執行類(lèi)主體完成填充類(lèi)命名空間,將通過(guò)調用 metaclass(name, bases, namespace, **kwds)
創(chuàng )建類(lèi)對象(此處的附加關(guān)鍵字參數與傳入 __prepare__
的相同)。
如果類(lèi)主體中有任何方法引用了 __class__
或 super
,這個(gè)類(lèi)對象會(huì )通過(guò)零參數形式的 super()
. __class__
所引用,這是由編譯器所創(chuàng )建的隱式閉包引用。這使用零參數形式的 super()
能夠正確標識正在基于詞法作用域來(lái)定義的類(lèi),而被用于進(jìn)行當前調用的類(lèi)或實(shí)例則是基于傳遞給方法的第一個(gè)參數來(lái)標識的。
CPython implementation detail: 在 CPython 3.6 及之后的版本中,__class__
單元會(huì )作為類(lèi)命名空間中的 __classcell__
條目被傳給元類(lèi)。 如果存在,它必須被向上傳播給 type.__new__
調用,以便能正確地初始化該類(lèi)。 如果不這樣做,在 Python 3.8 中將引發(fā) RuntimeError
。
When using the default metaclass type
, or any metaclass that ultimately
calls type.__new__
, the following additional customization steps are
invoked after creating the class object:
The
type.__new__
method collects all of the attributes in the class namespace that define a__set_name__()
method;Those
__set_name__
methods are called with the class being defined and the assigned name of that particular attribute;The
__init_subclass__()
hook is called on the immediate parent of the new class in its method resolution order.
在類(lèi)對象創(chuàng )建之后,它會(huì )被傳給包含在類(lèi)定義中的類(lèi)裝飾器(如果有的話(huà)),得到的對象將作為已定義的類(lèi)綁定到局部命名空間。
當通過(guò) type.__new__
創(chuàng )建一個(gè)新類(lèi)時(shí),提供以作為命名空間形參的對象會(huì )被復制到一個(gè)新的有序映射并丟棄原對象。這個(gè)新副本包裝于一個(gè)只讀代理中,后者則成為類(lèi)對象的 __dict__
屬性。
參見(jiàn)
- PEP 3135 - 新的超類(lèi)型
描述隱式的
__class__
閉包引用
3.3.3.7. 元類(lèi)的作用?
元類(lèi)的潛在作用非常廣泛。已經(jīng)過(guò)嘗試的設想包括枚舉、日志、接口檢查、自動(dòng)委托、自動(dòng)特征屬性創(chuàng )建、代理、框架以及自動(dòng)資源鎖定/同步等等。
3.3.4. 自定義實(shí)例及子類(lèi)檢查?
以下方法被用來(lái)重載 isinstance()
和 issubclass()
內置函數的默認行為。
特別地,元類(lèi) abc.ABCMeta
實(shí)現了這些方法以便允許將抽象基類(lèi)(ABC)作為“虛擬基類(lèi)”添加到任何類(lèi)或類(lèi)型(包括內置類(lèi)型),包括其他 ABC 之中。
- class.__instancecheck__(self, instance)?
如果 instance 應被視為 class 的一個(gè)(直接或間接)實(shí)例則返回真值。如果定義了此方法,則會(huì )被調用以實(shí)現
isinstance(instance, class)
。
- class.__subclasscheck__(self, subclass)?
Return true 如果 subclass 應被視為 class 的一個(gè)(直接或間接)子類(lèi)則返回真值。如果定義了此方法,則會(huì )被調用以實(shí)現
issubclass(subclass, class)
。
請注意這些方法的查找是基于類(lèi)的類(lèi)型(元類(lèi))。它們不能作為類(lèi)方法在實(shí)際的類(lèi)中被定義。這與基于實(shí)例被調用的特殊方法的查找是一致的,只有在此情況下實(shí)例本身被當作是類(lèi)。
參見(jiàn)
- PEP 3119 - 引入抽象基類(lèi)
新增功能描述,通過(guò)
__instancecheck__()
和__subclasscheck__()
來(lái)定制isinstance()
和issubclass()
行為,加入此功能的動(dòng)機是出于向該語(yǔ)言添加抽象基類(lèi)的內容(參見(jiàn)abc
模塊)。
3.3.5. 模擬泛型類(lèi)型?
When using type annotations, it is often useful to
parameterize a generic type using Python's square-brackets notation.
For example, the annotation list[int]
might be used to signify a
list
in which all the elements are of type int
.
參見(jiàn)
- PEP 484 - Type Hints
Introducing Python's framework for type annotations
- Generic Alias Types
Documentation for objects representing parameterized generic classes
- 泛型(Generic), user-defined generics and
typing.Generic
Documentation on how to implement generic classes that can be parameterized at runtime and understood by static type-checkers.
A class can generally only be parameterized if it defines the special
class method __class_getitem__()
.
- classmethod object.__class_getitem__(cls, key)?
按照 key 參數指定的類(lèi)型返回一個(gè)表示泛型類(lèi)的專(zhuān)門(mén)化對象。
When defined on a class,
__class_getitem__()
is automatically a class method. As such, there is no need for it to be decorated with@classmethod
when it is defined.
3.3.5.1. The purpose of __class_getitem__?
The purpose of __class_getitem__()
is to allow runtime
parameterization of standard-library generic classes in order to more easily
apply type hints to these classes.
To implement custom generic classes that can be parameterized at runtime and
understood by static type-checkers, users should either inherit from a standard
library class that already implements __class_getitem__()
, or
inherit from typing.Generic
, which has its own implementation of
__class_getitem__()
.
Custom implementations of __class_getitem__()
on classes defined
outside of the standard library may not be understood by third-party
type-checkers such as mypy. Using __class_getitem__()
on any class for
purposes other than type hinting is discouraged.
3.3.5.2. __class_getitem__ versus __getitem__?
Usually, the subscription of an object using square
brackets will call the __getitem__()
instance method defined on
the object's class. However, if the object being subscribed is itself a class,
the class method __class_getitem__()
may be called instead.
__class_getitem__()
should return a GenericAlias
object if it is properly defined.
Presented with the expression obj[x]
, the Python interpreter
follows something like the following process to decide whether
__getitem__()
or __class_getitem__()
should be
called:
from inspect import isclass
def subscribe(obj, x):
"""Return the result of the expression 'obj[x]'"""
class_of_obj = type(obj)
# If the class of obj defines __getitem__,
# call class_of_obj.__getitem__(obj, x)
if hasattr(class_of_obj, '__getitem__'):
return class_of_obj.__getitem__(obj, x)
# Else, if obj is a class and defines __class_getitem__,
# call obj.__class_getitem__(x)
elif isclass(obj) and hasattr(obj, '__class_getitem__'):
return obj.__class_getitem__(x)
# Else, raise an exception
else:
raise TypeError(
f"'{class_of_obj.__name__}' object is not subscriptable"
)
In Python, all classes are themselves instances of other classes. The class of
a class is known as that class's metaclass, and most classes have the
type
class as their metaclass. type
does not define
__getitem__()
, meaning that expressions such as list[int]
,
dict[str, float]
and tuple[str, bytes]
all result in
__class_getitem__()
being called:
>>> # list has class "type" as its metaclass, like most classes:
>>> type(list)
<class 'type'>
>>> type(dict) == type(list) == type(tuple) == type(str) == type(bytes)
True
>>> # "list[int]" calls "list.__class_getitem__(int)"
>>> list[int]
list[int]
>>> # list.__class_getitem__ returns a GenericAlias object:
>>> type(list[int])
<class 'types.GenericAlias'>
However, if a class has a custom metaclass that defines
__getitem__()
, subscribing the class may result in different
behaviour. An example of this can be found in the enum
module:
>>> from enum import Enum
>>> class Menu(Enum):
... """A breakfast menu"""
... SPAM = 'spam'
... BACON = 'bacon'
...
>>> # Enum classes have a custom metaclass:
>>> type(Menu)
<class 'enum.EnumMeta'>
>>> # EnumMeta defines __getitem__,
>>> # so __class_getitem__ is not called,
>>> # and the result is not a GenericAlias object:
>>> Menu['SPAM']
<Menu.SPAM: 'spam'>
>>> type(Menu['SPAM'])
<enum 'Menu'>
參見(jiàn)
- PEP 560 - Core Support for typing module and generic types
Introducing
__class_getitem__()
, and outlining when a subscription results in__class_getitem__()
being called instead of__getitem__()
3.3.6. 模擬可調用對象?
- object.__call__(self[, args...])?
此方法會(huì )在實(shí)例作為一個(gè)函數被“調用”時(shí)被調用;如果定義了此方法,則
x(arg1, arg2, ...)
就大致可以被改寫(xiě)為type(x).__call__(x, arg1, ...)
。
3.3.7. 模擬容器類(lèi)型?
The following methods can be defined to implement container objects. Containers
usually are sequences (such as lists
or
tuples
) or mappings (like
dictionaries
),
but can represent other containers as well. The first set of methods is used
either to emulate a sequence or to emulate a mapping; the difference is that for
a sequence, the allowable keys should be the integers k for which 0 <= k <
N
where N is the length of the sequence, or slice
objects, which define a
range of items. It is also recommended that mappings provide the methods
keys()
, values()
, items()
, get()
, clear()
,
setdefault()
, pop()
, popitem()
, copy()
, and
update()
behaving similar to those for Python's standard dictionary
objects. The collections.abc
module provides a
MutableMapping
abstract base class to help create those methods from a base set of
__getitem__()
, __setitem__()
, __delitem__()
, and keys()
.
Mutable sequences should provide methods append()
, count()
,
index()
, extend()
, insert()
, pop()
, remove()
,
reverse()
and sort()
, like Python standard list
objects. Finally,
sequence types should implement addition (meaning concatenation) and
multiplication (meaning repetition) by defining the methods
__add__()
, __radd__()
, __iadd__()
,
__mul__()
, __rmul__()
and __imul__()
described below; they should not define other numerical
operators. It is recommended that both mappings and sequences implement the
__contains__()
method to allow efficient use of the in
operator; for
mappings, in
should search the mapping's keys; for sequences, it should
search through the values. It is further recommended that both mappings and
sequences implement the __iter__()
method to allow efficient iteration
through the container; for mappings, __iter__()
should iterate
through the object's keys; for sequences, it should iterate through the values.
- object.__len__(self)?
調用此方法以實(shí)現內置函數
len()
。應該返回對象的長(cháng)度,以一個(gè)>=
0 的整數表示。此外,如果一個(gè)對象未定義__bool__()
方法而其__len__()
方法返回值為零,則在布爾運算中會(huì )被視為假值。CPython implementation detail: 在 CPython 中,要求長(cháng)度最大為
sys.maxsize
。如果長(cháng)度大于sys.maxsize
則某些特性 (例如len()
) 可能會(huì )引發(fā)OverflowError
。要通過(guò)真值檢測來(lái)防止引發(fā)OverflowError
,對象必須定義__bool__()
方法。
- object.__length_hint__(self)?
調用此方法以實(shí)現
operator.length_hint()
。 應該返回對象長(cháng)度的估計值(可能大于或小于實(shí)際長(cháng)度)。 此長(cháng)度應為一個(gè)>=
0 的整數。 返回值也可以為NotImplemented
,這會(huì )被視作與__length_hint__
方法完全不存在時(shí)一樣處理。 此方法純粹是為了優(yōu)化性能,并不要求正確無(wú)誤。3.4 新版功能.
備注
切片是通過(guò)下述三個(gè)專(zhuān)門(mén)方法完成的。以下形式的調用
a[1:2] = b
會(huì )為轉寫(xiě)為
a[slice(1, 2, None)] = b
其他形式以此類(lèi)推。略去的切片項總是以 None
補全。
- object.__getitem__(self, key)?
Called to implement evaluation of
self[key]
. For sequence types, the accepted keys should be integers and slice objects. Note that the special interpretation of negative indexes (if the class wishes to emulate a sequence type) is up to the__getitem__()
method. If key is of an inappropriate type,TypeError
may be raised; if of a value outside the set of indexes for the sequence (after any special interpretation of negative values),IndexError
should be raised. For mapping types, if key is missing (not in the container),KeyError
should be raised.備注
for
循環(huán)在有不合法索引時(shí)會(huì )期待捕獲IndexError
以便正確地檢測到序列的結束。備注
When subscripting a class, the special class method
__class_getitem__()
may be called instead of__getitem__()
. See __class_getitem__ versus __getitem__ for more details.
- object.__setitem__(self, key, value)?
調用此方法以實(shí)現向
self[key]
賦值。注意事項與__getitem__()
相同。為對象實(shí)現此方法應該僅限于需要映射允許基于鍵修改值或添加鍵,或是序列允許元素被替換時(shí)。不正確的 key 值所引發(fā)的異常應與__getitem__()
方法的情況相同。
- object.__delitem__(self, key)?
調用此方法以實(shí)現
self[key]
的刪除。注意事項與__getitem__()
相同。為對象實(shí)現此方法應該權限于需要映射允許移除鍵,或是序列允許移除元素時(shí)。不正確的 key 值所引發(fā)的異常應與__getitem__()
方法的情況相同。
- object.__missing__(self, key)?
此方法由
dict
.__getitem__()
在找不到字典中的鍵時(shí)調用以實(shí)現 dict 子類(lèi)的self[key]
。
- object.__iter__(self)?
This method is called when an iterator is required for a container. This method should return a new iterator object that can iterate over all the objects in the container. For mappings, it should iterate over the keys of the container.
- object.__reversed__(self)?
此方法(如果存在)會(huì )被
reversed()
內置函數調用以實(shí)現逆向迭代。它應當返回一個(gè)新的以逆序逐個(gè)迭代容器內所有對象的迭代器對象。如果未提供
__reversed__()
方法,則reversed()
內置函數將回退到使用序列協(xié)議 (__len__()
和__getitem__()
)。支持序列協(xié)議的對象應當僅在能夠提供比reversed()
所提供的實(shí)現更高效的實(shí)現時(shí)才提供__reversed__()
方法。
成員檢測運算符 (in
和 not in
) 通常以對容器進(jìn)行逐個(gè)迭代的方式來(lái)實(shí)現。 不過(guò),容器對象可以提供以下特殊方法并采用更有效率的實(shí)現,這樣也不要求對象必須為可迭代對象。
- object.__contains__(self, item)?
調用此方法以實(shí)現成員檢測運算符。如果 item 是 self 的成員則應返回真,否則返回假。對于映射類(lèi)型,此檢測應基于映射的鍵而不是值或者鍵值對。
對于未定義
__contains__()
的對象,成員檢測將首先嘗試通過(guò)__iter__()
進(jìn)行迭代,然后再使用__getitem__()
的舊式序列迭代協(xié)議,參看 語(yǔ)言參考中的相應部分。
3.3.8. 模擬數字類(lèi)型?
定義以下方法即可模擬數字類(lèi)型。特定種類(lèi)的數字不支持的運算(例如非整數不能進(jìn)行位運算)所對應的方法應當保持未定義狀態(tài)。
- object.__add__(self, other)?
- object.__sub__(self, other)?
- object.__mul__(self, other)?
- object.__matmul__(self, other)?
- object.__truediv__(self, other)?
- object.__floordiv__(self, other)?
- object.__mod__(self, other)?
- object.__divmod__(self, other)?
- object.__pow__(self, other[, modulo])?
- object.__lshift__(self, other)?
- object.__rshift__(self, other)?
- object.__and__(self, other)?
- object.__xor__(self, other)?
- object.__or__(self, other)?
These methods are called to implement the binary arithmetic operations (
+
,-
,*
,@
,/
,//
,%
,divmod()
,pow()
,**
,<<
,>>
,&
,^
,|
). For instance, to evaluate the expressionx + y
, where x is an instance of a class that has an__add__()
method,type(x).__add__(x, y)
is called. The__divmod__()
method should be the equivalent to using__floordiv__()
and__mod__()
; it should not be related to__truediv__()
. Note that__pow__()
should be defined to accept an optional third argument if the ternary version of the built-inpow()
function is to be supported.如果這些方法中的某一個(gè)不支持與所提供參數進(jìn)行運算,它應該返回
NotImplemented
。
- object.__radd__(self, other)?
- object.__rsub__(self, other)?
- object.__rmul__(self, other)?
- object.__rmatmul__(self, other)?
- object.__rtruediv__(self, other)?
- object.__rfloordiv__(self, other)?
- object.__rmod__(self, other)?
- object.__rdivmod__(self, other)?
- object.__rpow__(self, other[, modulo])?
- object.__rlshift__(self, other)?
- object.__rrshift__(self, other)?
- object.__rand__(self, other)?
- object.__rxor__(self, other)?
- object.__ror__(self, other)?
These methods are called to implement the binary arithmetic operations (
+
,-
,*
,@
,/
,//
,%
,divmod()
,pow()
,**
,<<
,>>
,&
,^
,|
) with reflected (swapped) operands. These functions are only called if the left operand does not support the corresponding operation 3 and the operands are of different types. 4 For instance, to evaluate the expressionx - y
, where y is an instance of a class that has an__rsub__()
method,type(y).__rsub__(y, x)
is called iftype(x).__sub__(x, y)
returns NotImplemented.請注意三元版的
pow()
并不會(huì )嘗試調用__rpow__()
(因為強制轉換規則會(huì )太過(guò)復雜)。備注
如果右操作數類(lèi)型為左操作數類(lèi)型的一個(gè)子類(lèi),且該子類(lèi)提供了指定運算的反射方法,則此方法將先于左操作數的非反射方法被調用。 此行為可允許子類(lèi)重載其祖先類(lèi)的運算符。
- object.__iadd__(self, other)?
- object.__isub__(self, other)?
- object.__imul__(self, other)?
- object.__imatmul__(self, other)?
- object.__itruediv__(self, other)?
- object.__ifloordiv__(self, other)?
- object.__imod__(self, other)?
- object.__ipow__(self, other[, modulo])?
- object.__ilshift__(self, other)?
- object.__irshift__(self, other)?
- object.__iand__(self, other)?
- object.__ixor__(self, other)?
- object.__ior__(self, other)?
調用這些方法來(lái)實(shí)現擴展算術(shù)賦值 (
+=
,-=
,*=
,@=
,/=
,//=
,%=
,**=
,<<=
,>>=
,&=
,^=
,|=
)。這些方法應該嘗試進(jìn)行自身操作 (修改 self) 并返回結果 (結果應該但并非必須為 self)。如果某個(gè)方法未被定義,相應的擴展算術(shù)賦值將回退到普通方法。例如,如果 x 是具有__iadd__()
方法的類(lèi)的一個(gè)實(shí)例,則x += y
就等價(jià)于x = x.__iadd__(y)
。否則就如x + y
的求值一樣選擇x.__add__(y)
和y.__radd__(x)
。在某些情況下,擴展賦值可導致未預期的錯誤 (參見(jiàn) 為什么 a_tuple[i] += ['item'] 會(huì )引發(fā)異常?),但此行為實(shí)際上是數據模型的一個(gè)組成部分。
- object.__neg__(self)?
- object.__pos__(self)?
- object.__abs__(self)?
- object.__invert__(self)?
調用此方法以實(shí)現一元算術(shù)運算 (
-
,+
,abs()
和~
)。
- object.__complex__(self)?
- object.__int__(self)?
- object.__float__(self)?
調用這些方法以實(shí)現內置函數
complex()
,int()
和float()
。應當返回一個(gè)相應類(lèi)型的值。
- object.__index__(self)?
調用此方法以實(shí)現
operator.index()
以及 Python 需要無(wú)損地將數字對象轉換為整數對象的場(chǎng)合(例如切片或是內置的bin()
,hex()
和oct()
函數)。 存在此方法表明數字對象屬于整數類(lèi)型。 必須返回一個(gè)整數。如果未定義
__int__()
,__float__()
和__complex__()
則相應的內置函數int()
,float()
和complex()
將回退為__index__()
。
- object.__round__(self[, ndigits])?
- object.__trunc__(self)?
- object.__floor__(self)?
- object.__ceil__(self)?
調用這些方法以實(shí)現內置函數
round()
以及math
函數trunc()
,floor()
和ceil()
。 除了將 ndigits 傳給__round__()
的情況之外這些方法的返回值都應當是原對象截斷為Integral
(通常為int
)。The built-in function
int()
falls back to__trunc__()
if neither__int__()
nor__index__()
is defined.在 3.11 版更改: The delegation of
int()
to__trunc__()
is deprecated.
3.3.9. with 語(yǔ)句上下文管理器?
上下文管理器 是一個(gè)對象,它定義了在執行 with
語(yǔ)句時(shí)要建立的運行時(shí)上下文。 上下文管理器處理進(jìn)入和退出所需運行時(shí)上下文以執行代碼塊。 通常使用 with
語(yǔ)句(在 with 語(yǔ)句 中描述),但是也可以通過(guò)直接調用它們的方法來(lái)使用。
上下文管理器的典型用法包括保存和恢復各種全局狀態(tài),鎖定和解鎖資源,關(guān)閉打開(kāi)的文件等等。
要了解上下文管理器的更多信息,請參閱 上下文管理器類(lèi)型。
- object.__enter__(self)?
進(jìn)入與此對象相關(guān)的運行時(shí)上下文。
with
語(yǔ)句將會(huì )綁定這個(gè)方法的返回值到as
子句中指定的目標,如果有的話(huà)。
- object.__exit__(self, exc_type, exc_value, traceback)?
退出關(guān)聯(lián)到此對象的運行時(shí)上下文。 各個(gè)參數描述了導致上下文退出的異常。 如果上下文是無(wú)異常地退出的,三個(gè)參數都將為
None
。如果提供了異常,并且希望方法屏蔽此異常(即避免其被傳播),則應當返回真值。 否則的話(huà),異常將在退出此方法時(shí)按正常流程處理。
請注意
__exit__()
方法不應該重新引發(fā)被傳入的異常,這是調用者的責任。
3.3.10. 定制類(lèi)模式匹配中的位置參數?
當在模式中使用類(lèi)名稱(chēng)時(shí),默認不允許模式中出現位置參數,例如 case MyClass(x, y)
通常是無(wú)效的,除非 MyClass
提供了特別支持。 要能使用這樣的模式,類(lèi)必須定義一個(gè) __match_args__ 屬性。
- object.__match_args__?
該類(lèi)變量可以被賦值為一個(gè)字符串元組。 當該類(lèi)被用于帶位置參數的類(lèi)模式時(shí),每個(gè)位置參數都將被轉換為關(guān)鍵字參數,并使用 __match_args__ 中的對應值作為關(guān)鍵字。 缺失此屬性就等價(jià)于將其設為
()
。
舉例來(lái)說(shuō),如果 MyClass.__match_args__
為 ("left", "center", "right")
則意味著(zhù) case MyClass(x, y)
就等價(jià)于 case MyClass(left=x, center=y)
。 請注意模式中參數的數量必須小于等于 __match_args__ 中元素的數量;如果前者大于后者,則嘗試模式匹配時(shí)將引發(fā) TypeError
。
3.10 新版功能.
參見(jiàn)
- PEP 634 - 結構化模式匹配
有關(guān) Python
match
語(yǔ)句的規范說(shuō)明。
3.3.11. 特殊方法查找?
對于自定義類(lèi)來(lái)說(shuō),特殊方法的隱式發(fā)起調用僅保證在其定義于對象類(lèi)型中時(shí)能正確地發(fā)揮作用,而不能定義在對象實(shí)例字典中。 該行為就是以下代碼會(huì )引發(fā)異常的原因。:
>>> class C:
... pass
...
>>> c = C()
>>> c.__len__ = lambda: 5
>>> len(c)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: object of type 'C' has no len()
The rationale behind this behaviour lies with a number of special methods such
as __hash__()
and __repr__()
that are implemented
by all objects,
including type objects. If the implicit lookup of these methods used the
conventional lookup process, they would fail when invoked on the type object
itself:
>>> 1 .__hash__() == hash(1)
True
>>> int.__hash__() == hash(int)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: descriptor '__hash__' of 'int' object needs an argument
以這種方式不正確地嘗試發(fā)起調用一個(gè)類(lèi)的未綁定方法有時(shí)被稱(chēng)為‘元類(lèi)混淆’,可以通過(guò)在查找特殊方法時(shí)繞過(guò)實(shí)例的方式來(lái)避免:
>>> type(1).__hash__(1) == hash(1)
True
>>> type(int).__hash__(int) == hash(int)
True
In addition to bypassing any instance attributes in the interest of
correctness, implicit special method lookup generally also bypasses the
__getattribute__()
method even of the object's metaclass:
>>> class Meta(type):
... def __getattribute__(*args):
... print("Metaclass getattribute invoked")
... return type.__getattribute__(*args)
...
>>> class C(object, metaclass=Meta):
... def __len__(self):
... return 10
... def __getattribute__(*args):
... print("Class getattribute invoked")
... return object.__getattribute__(*args)
...
>>> c = C()
>>> c.__len__() # Explicit lookup via instance
Class getattribute invoked
10
>>> type(c).__len__(c) # Explicit lookup via type
Metaclass getattribute invoked
10
>>> len(c) # Implicit lookup
10
Bypassing the __getattribute__()
machinery in this fashion
provides significant scope for speed optimisations within the
interpreter, at the cost of some flexibility in the handling of
special methods (the special method must be set on the class
object itself in order to be consistently invoked by the interpreter).
3.4. 協(xié)程?
3.4.1. 可等待對象?
An awaitable object generally implements an __await__()
method.
Coroutine objects returned from async def
functions
are awaitable.
備注
The generator iterator objects returned from generators
decorated with types.coroutine()
are also awaitable, but they do not implement __await__()
.
- object.__await__(self)?
必須返回一個(gè) iterator。 應當被用來(lái)實(shí)現 awaitable 對象。 例如,
asyncio.Future
實(shí)現了此方法以與await
表達式相兼容。
3.5 新版功能.
參見(jiàn)
PEP 492 了解有關(guān)可等待對象的詳細信息。
3.4.2. 協(xié)程對象?
Coroutine objects are awaitable objects.
A coroutine's execution can be controlled by calling __await__()
and
iterating over the result. When the coroutine has finished executing and
returns, the iterator raises StopIteration
, and the exception's
value
attribute holds the return value. If the
coroutine raises an exception, it is propagated by the iterator. Coroutines
should not directly raise unhandled StopIteration
exceptions.
協(xié)程也具有下面列出的方法,它們類(lèi)似于生成器的對應方法 (參見(jiàn) 生成器-迭代器的方法)。 但是,與生成器不同,協(xié)程并不直接支持迭代。
在 3.5.2 版更改: 等待一個(gè)協(xié)程超過(guò)一次將引發(fā) RuntimeError
。
- coroutine.send(value)?
Starts or resumes execution of the coroutine. If value is
None
, this is equivalent to advancing the iterator returned by__await__()
. If value is notNone
, this method delegates to thesend()
method of the iterator that caused the coroutine to suspend. The result (return value,StopIteration
, or other exception) is the same as when iterating over the__await__()
return value, described above.
- coroutine.throw(value)?
- coroutine.throw(type[, value[, traceback]])
Raises the specified exception in the coroutine. This method delegates to the
throw()
method of the iterator that caused the coroutine to suspend, if it has such a method. Otherwise, the exception is raised at the suspension point. The result (return value,StopIteration
, or other exception) is the same as when iterating over the__await__()
return value, described above. If the exception is not caught in the coroutine, it propagates back to the caller.
- coroutine.close()?
此方法會(huì )使得協(xié)程清理自身并退出。 如果協(xié)程被掛起,此方法會(huì )先委托給導致協(xié)程掛起的迭代器的
close()
方法,如果存在該方法。 然后它會(huì )在掛起點(diǎn)引發(fā)GeneratorExit
,使得協(xié)程立即清理自身。 最后,協(xié)程會(huì )被標記為已結束執行,即使它根本未被啟動(dòng)。當協(xié)程對象將要被銷(xiāo)毀時(shí),會(huì )使用以上處理過(guò)程來(lái)自動(dòng)關(guān)閉。
3.4.3. 異步迭代器?
異步迭代器 可以在其 __anext__
方法中調用異步代碼。
異步迭代器可在 async for
語(yǔ)句中使用。
- object.__aiter__(self)?
必須返回一個(gè) 異步迭代器 對象。
- object.__anext__(self)?
必須返回一個(gè) 可迭代對象 輸出迭代器的下一結果值。 當迭代結束時(shí)應該引發(fā)
StopAsyncIteration
錯誤。
異步可迭代對象的一個(gè)示例:
class Reader:
async def readline(self):
...
def __aiter__(self):
return self
async def __anext__(self):
val = await self.readline()
if val == b'':
raise StopAsyncIteration
return val
3.5 新版功能.
在 3.7 版更改: Prior to Python 3.7, __aiter__()
could return an awaitable
that would resolve to an
asynchronous iterator.
Starting with Python 3.7, __aiter__()
must return an
asynchronous iterator object. Returning anything else
will result in a TypeError
error.
3.4.4. 異步上下文管理器?
異步上下文管理器 是 上下文管理器 的一種,它能夠在其 __aenter__
和 __aexit__
方法中暫停執行。
異步上下文管理器可在 async with
語(yǔ)句中使用。
- object.__aenter__(self)?
在語(yǔ)義上類(lèi)似于
__enter__()
,僅有的區別是它必須返回一個(gè) 可等待對象。
- object.__aexit__(self, exc_type, exc_value, traceback)?
在語(yǔ)義上類(lèi)似于
__exit__()
,僅有的區別是它必須返回一個(gè) 可等待對象。
異步上下文管理器類(lèi)的一個(gè)示例:
class AsyncContextManager:
async def __aenter__(self):
await log('entering context')
async def __aexit__(self, exc_type, exc, tb):
await log('exiting context')
3.5 新版功能.
備注
- 1
在某些情況下 有可能 基于可控的條件改變一個(gè)對象的類(lèi)型。 但這通常不是個(gè)好主意,因為如果處理不當會(huì )導致一些非常怪異的行為。
- 2
The
__hash__()
,__iter__()
,__reversed__()
, and__contains__()
methods have special handling for this; others will still raise aTypeError
, but may do so by relying on the behavior thatNone
is not callable.- 3
這里的“不支持”是指該類(lèi)無(wú)此方法,或方法返回
NotImplemented
。 如果你想強制回退到右操作數的反射方法,請不要設置方法為None
— 那會(huì )造成顯式地 阻塞 此種回退的相反效果。- 4
For operands of the same type, it is assumed that if the non-reflected method -- such as
__add__()
-- fails then the overall operation is not supported, which is why the reflected method is not called.