掃二維碼與項目經(jīng)理溝通
我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流
對象 是 python 中對數(shù)據(jù)的抽象。 Python 程序中的所有數(shù)據(jù)都是由對象或?qū)ο箝g關(guān)系來表示的。 (從某種意義上說,按照馮·諾依曼的“存儲程序計算機”模型,代碼本身也是由對象來表示的。)

成都創(chuàng)新互聯(lián)公司專注于商河企業(yè)網(wǎng)站建設(shè),自適應(yīng)網(wǎng)站建設(shè),成都商城網(wǎng)站開發(fā)。商河網(wǎng)站建設(shè)公司,為商河等地區(qū)提供建站服務(wù)。全流程按需網(wǎng)站策劃,專業(yè)設(shè)計,全程項目跟蹤,成都創(chuàng)新互聯(lián)公司專業(yè)和態(tài)度為您提供的服務(wù)
每個對象都有各自的標(biāo)識號、類型和值。一個對象被創(chuàng)建后,它的 標(biāo)識號 就絕不會改變;你可以將其理解為該對象在內(nèi)存中的地址。 ‘is‘ 運算符可以比較兩個對象的標(biāo)識號是否相同;id() 函數(shù)能返回一個代表其標(biāo)識號的整數(shù)。
CPython 實現(xiàn)細(xì)節(jié): 在 CPython 中,id(x) 就是存放 x 的內(nèi)存的地址。
對象的類型決定該對象所支持的操作 (例如 “對象是否有長度屬性?”) 并且定義了該類型的對象可能的取值。type() 函數(shù)能返回一個對象的類型 (類型本身也是對象)。與編號一樣,一個對象的 類型 也是不可改變的。1
有些對象的 值 可以改變。值可以改變的對象被稱為 可變對象;值不可以改變的對象就被稱為 不可變對象。(一個不可變?nèi)萜鲗ο笕绻瑢勺儗ο蟮囊?,?dāng)后者的值改變時,前者的值也會改變;但是該容器仍屬于不可變對象,因為它所包含的對象集是不會改變的。因此,不可變并不嚴(yán)格等同于值不能改變,實際含義要更微妙。) 一個對象的可變性是由其類型決定的;例如,數(shù)字、字符串和元組是不可變的,而字典和列表是可變的。
對象絕不會被顯式地銷毀;然而,當(dāng)無法訪問時它們可能會被作為垃圾回收。允許具體的實現(xiàn)推遲垃圾回收或完全省略此機制 —- 如何實現(xiàn)垃圾回收是實現(xiàn)的質(zhì)量問題,只要可訪問的對象不會被回收即可。
CPython 實現(xiàn)細(xì)節(jié): CPython 目前使用帶有 (可選) 延遲檢測循環(huán)鏈接垃圾的引用計數(shù)方案,會在對象不可訪問時立即回收其中的大部分,但不保證回收包含循環(huán)引用的垃圾。請查看 gc 模塊的文檔了解如何控制循環(huán)垃圾的收集相關(guān)信息。其他實現(xiàn)會有不同的行為方式,CPython 現(xiàn)有方式也可能改變。不要依賴不可訪問對象的立即終結(jié)機制 (所以你應(yīng)當(dāng)總是顯式地關(guān)閉文件)。
注意:使用實現(xiàn)的跟蹤或調(diào)試功能可能令正常情況下會被回收的對象繼續(xù)存活。還要注意通過 ‘try…except‘ 語句捕捉異常也可能令對象保持存活。
有些對象包含對 “外部” 資源的引用,例如打開文件或窗口。當(dāng)對象被作為垃圾回收時這些資源也應(yīng)該會被釋放,但由于垃圾回收并不確保發(fā)生,這些對象還提供了明確地釋放外部資源的操作,通常為一個 close() 方法。強烈推薦在程序中顯式關(guān)閉此類對象?!痶ry…finally‘ 語句和 ‘with‘ 語句提供了進行此種操作的更便捷方式。
有些對象包含對其他對象的引用;它們被稱為 容器。容器的例子有元組、列表和字典等。這些引用是容器對象值的組成部分。在多數(shù)情況下,當(dāng)談?wù)撘粋€容器的值時,我們是指所包含對象的值而不是其編號;但是,當(dāng)我們談?wù)撘粋€容器的可變性時,則僅指其直接包含的對象的編號。因此,如果一個不可變?nèi)萜?(例如元組) 包含對一個可變對象的引用,則當(dāng)該可變對象被改變時容器的值也會改變。
類型會影響對象行為的幾乎所有方面。甚至對象編號的重要性也在某種程度上受到影響: 對于不可變類型,會得出新值的運算實際上會返回對相同類型和取值的任一現(xiàn)有對象的引用,而對于可變類型來說這是不允許的。例如在 a = 1; b = 1 之后,a 和 b 可能會也可能不會指向同一個值為一的對象,這取決于具體實現(xiàn),但是在 c = []; d = [] 之后,c 和 d 保證會指向兩個不同、單獨的新建空列表。(請注意 c = d = [] 則是將同一個對象賦值給 c 和 d。)
以下是 Python 內(nèi)置類型的列表。擴展模塊 (具體實現(xiàn)會以 C, Java 或其他語言編寫) 可以定義更多的類型。未來版本的 Python 可能會加入更多的類型 (例如有理數(shù)、高效存儲的整型數(shù)組等等),不過新增類型往往都是通過標(biāo)準(zhǔn)庫來提供的。
以下部分類型的描述中包含有 ‘特殊屬性列表’ 段落。這些屬性提供對具體實現(xiàn)的訪問而非通常使用。它們的定義在未來可能會改變。
None
此類型只有一種取值。是一個具有此值的單獨對象。此對象通過內(nèi)置名稱 None 訪問。在許多情況下它被用來表示空值,例如未顯式指明返回值的函數(shù)將返回 None。它的邏輯值為假。
NotImplemented
此類型只有一種取值。 是一個具有該值的單獨對象。 此對象通過內(nèi)置名稱 NotImplemented 訪問。 數(shù)值方法和豐富比較方法如未實現(xiàn)指定運算符表示的運算則應(yīng)返回該值。 (解釋器會根據(jù)具體運算符繼續(xù)嘗試反向運算或其他回退操作。) 它不應(yīng)被解讀為布爾值。
詳情參見 實現(xiàn)算術(shù)運算。
在 3.9 版更改: 作為布爾值來解讀 NotImplemented 已被棄用。 雖然它目前會被解讀為真值,但將同時發(fā)出 DeprecationWarning。 它將在未來的 Python 版本中引發(fā) TypeError。
Ellipsis
此類型只有一種取值。是一個具有此值的單獨對象。此對象通過字面值 ... 或內(nèi)置名稱 Ellipsis 訪問。它的邏輯值為真。
numbers.Number
此類對象由數(shù)字字面值創(chuàng)建,并會被作為算術(shù)運算符和算術(shù)內(nèi)置函數(shù)的返回結(jié)果。數(shù)字對象是不可變的;一旦創(chuàng)建其值就不再改變。Python 中的數(shù)字當(dāng)然非常類似數(shù)學(xué)中的數(shù)字,但也受限于計算機中的數(shù)字表示方法。
數(shù)字類的字符串表示形式,由 __repr__() 和 __str__() 算出,具有以下特征屬性:
它們是有效的數(shù)字字面值,當(dāng)被傳給它們的類構(gòu)造器時,將會產(chǎn)生具有原數(shù)字值的對象。
表示形式會在可能的情況下采用 10 進制。
開頭的零,除小數(shù)點前可能存在的單個零之外,將不會被顯示。
末尾的零,除小數(shù)點后可能存在的單個零之外,將不會被顯示。
正負(fù)號僅在當(dāng)數(shù)字為負(fù)值時會被顯示。
Python 區(qū)分整型數(shù)、浮點型數(shù)和復(fù)數(shù):
numbers.Integral
此類對象表示數(shù)學(xué)中整數(shù)集合的成員 (包括正數(shù)和負(fù)數(shù))。
整型數(shù)可細(xì)分為兩種類型:
整型 (int)
此類對象表示任意大小的數(shù)字,僅受限于可用的內(nèi)存 (包括虛擬內(nèi)存)。在變換和掩碼運算中會以二進制表示,負(fù)數(shù)會以 2 的補碼表示,看起來像是符號位向左延伸補滿空位。
布爾型 (bool)
此類對象表示邏輯值 False 和 True。代表 False 和 True 值的兩個對象是唯二的布爾對象。布爾類型是整型的子類型,兩個布爾值在各種場合的行為分別類似于數(shù)值 0 和 1,例外情況只有在轉(zhuǎn)換為字符串時分別返回字符串 "False" 或 "True"。
整型數(shù)表示規(guī)則的目的是在涉及負(fù)整型數(shù)的變換和掩碼運算時提供最為合理的解釋。
numbers.Real (float)
此類對象表示機器級的雙精度浮點數(shù)。其所接受的取值范圍和溢出處理將受制于底層的機器架構(gòu) (以及 C 或 Java 實現(xiàn))。Python 不支持單精度浮點數(shù);支持后者通常的理由是節(jié)省處理器和內(nèi)存消耗,但這點節(jié)省相對于在 Python 中使用對象的開銷來說太過微不足道,因此沒有理由包含兩種浮點數(shù)而令該語言變得復(fù)雜。
numbers.Complex (complex)
此類對象以一對機器級的雙精度浮點數(shù)來表示復(fù)數(shù)值。有關(guān)浮點數(shù)的附帶規(guī)則對其同樣有效。一個復(fù)數(shù)值 z 的實部和虛部可通過只讀屬性 z.real 和 z.imag 來獲取。
序列
此類對象表示以非負(fù)整數(shù)作為索引的有限有序集。內(nèi)置函數(shù) len() 可返回一個序列的條目數(shù)量。當(dāng)一個序列的長度為 n 時,索引集包含數(shù)字 0, 1, …, n-1。序列 a 的條目 i 可通過 a[i] 選擇。
序列還支持切片: a[i:j] 選擇索引號為 k 的所有條目,i <= k < j。當(dāng)用作表達(dá)式時,序列的切片就是一個與序列類型相同的新序列。新序列的索引還是從 0 開始。
有些序列還支持帶有第三個 “step” 形參的 “擴展切片”: a[i:j:k] 選擇 a 中索引號為 x 的所有條目,x = i + n*k, n >= 0 且 i <= x < j。
序列可根據(jù)其可變性來加以區(qū)分:
不可變序列
不可變序列類型的對象一旦創(chuàng)建就不能再改變。(如果對象包含對其他對象的引用,其中的可變對象就是可以改變的;但是,一個不可變對象所直接引用的對象集是不能改變的。)
以下類型屬于不可變對象:
字符串
A string is a sequence of values that represent Unicode code points. All the code points in the range U+0000 - U+10FFFF can be represented in a string. Python doesn’t have a char type; instead, every code point in the string is represented as a string object with length 1. The built-in function ord() converts a code point from its string form to an integer in the range 0 - 10FFFF; chr() converts an integer in the range 0 - 10FFFF to the corresponding length 1 string object. str.encode() can be used to convert a str to bytes using the given text encoding, and bytes.decode() can be used to achieve the opposite.
元組
一個元組中的條目可以是任意 Python 對象。包含兩個或以上條目的元組由逗號分隔的表達(dá)式構(gòu)成。只有一個條目的元組 (‘單項元組’) 可通過在表達(dá)式后加一個逗號來構(gòu)成 (一個表達(dá)式本身不能創(chuàng)建為元組,因為圓括號要用來設(shè)置表達(dá)式分組)。一個空元組可通過一對內(nèi)容為空的圓括號創(chuàng)建。
字節(jié)串
字節(jié)串對象是不可變的數(shù)組。其中每個條目都是一個 8 位字節(jié),以取值范圍 0 <= x < 256 的整型數(shù)表示。字節(jié)串字面值 (例如 b'abc') 和內(nèi)置的 bytes() 構(gòu)造器可被用來創(chuàng)建字節(jié)串對象。字節(jié)串對象還可以通過 decode() 方法解碼為字符串。
可變序列
可變序列在被創(chuàng)建后仍可被改變。下標(biāo)和切片標(biāo)注可被用作賦值和 del (刪除) 語句的目標(biāo)。
目前有兩種內(nèi)生可變序列類型:
列表
列表中的條目可以是任意 Python 對象。列表由用方括號括起并由逗號分隔的多個表達(dá)式構(gòu)成。(注意創(chuàng)建長度為 0 或 1 的列表無需使用特殊規(guī)則。)
字節(jié)數(shù)組
字節(jié)數(shù)組對象屬于可變數(shù)組??梢酝ㄟ^內(nèi)置的 bytearray() 構(gòu)造器來創(chuàng)建。除了是可變的 (因而也是不可哈希的),在其他方面字節(jié)數(shù)組提供的接口和功能都與不可變的 bytes 對象一致。
擴展模塊 array 提供了一個額外的可變序列類型示例,collections 模塊也是如此。
集合類型
此類對象表示由不重復(fù)且不可變對象組成的無序且有限的集合。因此它們不能通過下標(biāo)來索引。但是它們可被迭代,也可用內(nèi)置函數(shù) len() 返回集合中的條目數(shù)。集合常見的用處是快速成員檢測,去除序列中的重復(fù)項,以及進行交、并、差和對稱差等數(shù)學(xué)運算。
對于集合元素所采用的不可變規(guī)則與字典的鍵相同。注意數(shù)字類型遵循正常的數(shù)字比較規(guī)則: 如果兩個數(shù)字相等 (例如 1 和 1.0),則同一集合中只能包含其中一個。
目前有兩種內(nèi)生集合類型:
集合
此類對象表示可變集合。它們可通過內(nèi)置的 set() 構(gòu)造器創(chuàng)建,并且創(chuàng)建之后可以通過方法進行修改,例如 add()。
凍結(jié)集合
此類對象表示不可變集合。它們可通過內(nèi)置的 frozenset() 構(gòu)造器創(chuàng)建。由于 frozenset 對象不可變且 hashable,它可以被用作另一個集合的元素或是字典的鍵。
映射
此類對象表示由任意索引集合所索引的對象的集合。通過下標(biāo) a[k] 可在映射 a 中選擇索引為 k 的條目;這可以在表達(dá)式中使用,也可作為賦值或 del 語句的目標(biāo)。內(nèi)置函數(shù) len() 可返回一個映射中的條目數(shù)。
目前只有一種內(nèi)生映射類型:
字典
此類對象表示由幾乎任意值作為索引的有限個對象的集合。不可作為鍵的值類型只有包含列表或字典或其他可變類型,通過值而非對象編號進行比較的值,其原因在于高效的字典實現(xiàn)需要使用鍵的哈希值以保持一致性。用作鍵的數(shù)字類型遵循正常的數(shù)字比較規(guī)則: 如果兩個數(shù)字相等 (例如 1 和 1.0) 則它們均可來用來索引同一個字典條目。
字典會保留插入順序,這意味著鍵將以它們被添加的順序在字典中依次產(chǎn)生。 替換某個現(xiàn)有的鍵不會改變其順序,但是移除某個鍵再重新插入則會將其添加到末尾而不會保留其原有位置。
字典是可變的;它們可通過 {...} 標(biāo)注來創(chuàng)建 (參見 字典顯示 小節(jié))。
擴展模塊 dbm.ndbm 和 dbm.gnu 提供了額外的映射類型示例,collections 模塊也是如此。
在 3.7 版更改: 在 Python 3.6 版之前字典不會保留插入順序。 在 CPython 3.6 中插入順序會被保留,但這在當(dāng)時被當(dāng)作是一個實現(xiàn)細(xì)節(jié)而非確定的語言特性。
可調(diào)用類型
此類型可以被應(yīng)用于函數(shù)調(diào)用操作 (參見 調(diào)用 小節(jié)):
用戶定義函數(shù)
用戶定義函數(shù)對象可通過函數(shù)定義來創(chuàng)建 (參見 函數(shù)定義 小節(jié))。它被調(diào)用時應(yīng)附帶一個參數(shù)列表,其中包含的條目應(yīng)與函數(shù)所定義的形參列表一致。
特殊屬性:
|
屬性 |
含意 | |
|---|---|---|
大部分標(biāo)有 “Writable” 的屬性均會檢查賦值的類型。
函數(shù)對象也支持獲取和設(shè)置任意屬性,例如這可以被用來給函數(shù)附加元數(shù)據(jù)。使用正規(guī)的屬性點號標(biāo)注獲取和設(shè)置此類屬性。注意當(dāng)前實現(xiàn)僅支持用戶定義函數(shù)屬性。未來可能會增加支持內(nèi)置函數(shù)屬性。
單元對象具有 cell_contents 屬性。這可被用來獲取以及設(shè)置單元的值。
有關(guān)函數(shù)定義的額外信息可以從其代碼對象中提取;參見下文對內(nèi)部類型的描述。 cell 類型可以在 types 模塊中訪問。
實例方法
實例方法用于結(jié)合類、類實例和任何可調(diào)用對象 (通常為用戶定義函數(shù))。
特殊的只讀屬性: __self__ 為類實例對象本身,__func__ 為函數(shù)對象;__doc__ 為方法的文檔 (與 __func__.__doc__ 作用相同);__name__ 為方法名稱 (與 __func__.__name__ 作用相同);__module__ 為方法所屬模塊的名稱,沒有則為 None。
方法還支持獲取 (但不能設(shè)置) 下層函數(shù)對象的任意函數(shù)屬性。
用戶定義方法對象可在獲取一個類的屬性時被創(chuàng)建 (也可能通過該類的一個實例),如果該屬性為用戶定義函數(shù)對象或類方法對象。
當(dāng)通過從類實例獲取一個用戶定義函數(shù)對象的方式創(chuàng)建一個實例方法對象時,類實例對象的 __self__ 屬性即為該實例,并會綁定方法對象。該新建方法的 __func__ 屬性就是原來的函數(shù)對象。
當(dāng)通過從類或?qū)嵗@取一個類方法對象的方式創(chuàng)建一個實例對象時,實例對象的 __self__ 屬性為該類本身,其 __func__ 屬性為類方法對應(yīng)的下層函數(shù)對象。
當(dāng)一個實例方法對象被調(diào)用時,會調(diào)用對應(yīng)的下層函數(shù) (__func__),并將類實例 (__self__) 插入?yún)?shù)列表的開頭。例如,當(dāng) C 是一個包含了 f() 函數(shù)定義的類,而 x 是 C 的一個實例,則調(diào)用 x.f(1) 就等同于調(diào)用 C.f(x, 1)。
當(dāng)一個實例方法對象是衍生自一個類方法對象時,保存在 __self__ 中的 “類實例” 實際上會是該類本身,因此無論是調(diào)用 x.f(1) 還是 C.f(1) 都等同于調(diào)用 f(C,1),其中 f 為對應(yīng)的下層函數(shù)。
請注意從函數(shù)對象到實例方法對象的變換會在每一次從實例獲取屬性時發(fā)生。在某些情況下,一種高效的優(yōu)化方式是將屬性賦值給一個本地變量并調(diào)用該本地變量。還要注意這樣的變換只發(fā)生于用戶定義函數(shù);其他可調(diào)用對象 (以及所有不可調(diào)用對象) 在被獲取時都不會發(fā)生變換。還有一個需要關(guān)注的要點是作為一個類實例屬性的用戶定義函數(shù)不會被轉(zhuǎn)換為綁定方法;這樣的變換 僅當(dāng) 函數(shù)是類屬性時才會發(fā)生。
生成器函數(shù)
一個使用 yield 語句(見 yield 語句 章節(jié))的函數(shù)或方法被稱為 生成器函數(shù)。 這樣的函數(shù)在被調(diào)用時,總是返回一個可以執(zhí)行該函數(shù)體的 iterator 對象:調(diào)用該迭代器的 iterator.__next__() 方法將導(dǎo)致這個函數(shù)一直運行到它使用 yield 語句提供一個值。 當(dāng)這個函數(shù)執(zhí)行 return 語句或到達(dá)函數(shù)體末尾時,將引發(fā) StopIteration 異常并且該迭代器將到達(dá)所返回的值集合的末尾。
協(xié)程函數(shù)
使用 async def 來定義的函數(shù)或方法就被稱為 協(xié)程函數(shù)。這樣的函數(shù)在被調(diào)用時會返回一個 coroutine 對象。它可能包含 await 表達(dá)式以及 async with 和 async for 語句。詳情可參見 協(xié)程對象 一節(jié)。
異步生成器函數(shù)
使用 async def 來定義并使用了 yield 語句的函數(shù)或方法被稱為 異步生成器函數(shù)。 這樣的函數(shù)在被調(diào)用時,將返回一個 asynchronous iterator 對象,該對象可在 async for 語句中被用來執(zhí)行函數(shù)體。
調(diào)用異步迭代器的 aiterator.__anext__ 方法將返回一個 awaitable,此對象會在被等待時執(zhí)行直到使用 yield 產(chǎn)生一個值。 當(dāng)函數(shù)執(zhí)行到空的 return 語句或函數(shù)末尾時,將會引發(fā) StopAsyncIteration 異常并且異步迭代器也將到達(dá)要產(chǎn)生的值集合的末尾。
內(nèi)置函數(shù)
內(nèi)置函數(shù)對象是對于 C 函數(shù)的外部封裝。內(nèi)置函數(shù)的例子包括 len() 和 math.sin() (math 是一個標(biāo)準(zhǔn)內(nèi)置模塊)。內(nèi)置函數(shù)參數(shù)的數(shù)量和類型由 C 函數(shù)決定。特殊的只讀屬性: __doc__ 是函數(shù)的文檔字符串,如果沒有則為 None; __name__ 是函數(shù)的名稱; __self__ 設(shè)定為 None (參見下一條目); __module__ 是函數(shù)所屬模塊的名稱,如果沒有則為 None。
內(nèi)置方法
此類型實際上是內(nèi)置函數(shù)的另一種形式,只不過還包含了一個傳入 C 函數(shù)的對象作為隱式的額外參數(shù)。內(nèi)置方法的一個例子是 alist.append(),其中 alist 為一個列表對象。在此示例中,特殊的只讀屬性 __self__ 會被設(shè)為 alist 所標(biāo)記的對象。
類
類是可調(diào)用對象。 這些對象通常是用作創(chuàng)建自身實例的“工廠”,但類也可以有重載 __new__() 的變體類型。 調(diào)用的參數(shù)會傳遞給 __new__(),并且在通常情況下,也會傳遞給 __init__() 來初始化新的實例。to initialize the new instance.
類實例
任意類的實例可以通過在其所屬類中定義 __call__() 方法變成可調(diào)用對象。
模塊
模塊是 Python 代碼的基本組織單元,由 導(dǎo)入系統(tǒng) 創(chuàng)建,由 import 語句發(fā)起調(diào)用,或者通過 importlib.import_module() 和內(nèi)置的 __import__() 等函數(shù)發(fā)起調(diào)用。 模塊對象具有由字典對象實現(xiàn)的命名空間(這是被模塊中定義的函數(shù)的 __globals__ 屬性引用的字典)。 屬性引用被轉(zhuǎn)換為該字典中的查找,例如 m.x 相當(dāng)于 m.__dict__["x"]。 模塊對象不包含用于初始化模塊的代碼對象(因為初始化完成后不需要它)。
屬性賦值會更新模塊的命名空間字典,例如 m.x = 1 等同于 m.__dict__["x"] = 1。
預(yù)先定義的(可寫)屬性:
__name__
模塊的名稱。
__doc__模塊的文檔字符串,如果不可用則為
None。__file__
被加載模塊所對應(yīng)文件的路徑名稱,如果它是從文件加載的話。 對于某些類型的模塊來說 __file__ 屬性可能是缺失的,例如被靜態(tài)鏈接到解釋器中的 C 模塊。 對于從共享庫動態(tài)加載的擴展模塊來說,它將是共享庫文件的路徑名稱。
__annotations__包含在模塊體執(zhí)行期間收集的 變量標(biāo)注 的字典。 有關(guān)使用
__annotations__的最佳實踐,請參閱 對象注解屬性的最佳實踐。
特殊的只讀屬性: __dict__ 為以字典對象表示的模塊命名空間。
CPython 實現(xiàn)細(xì)節(jié): 由于 CPython 清理模塊字典的設(shè)定,當(dāng)模塊離開作用域時模塊字典將會被清理,即使該字典還有活動的引用。想避免此問題,可復(fù)制該字典或保持模塊狀態(tài)以直接使用其字典。
自定義類
自定義類這種類型一般通過類定義來創(chuàng)建 (參見 類定義 一節(jié))。每個類都有通過一個字典對象實現(xiàn)的獨立命名空間。類屬性引用會被轉(zhuǎn)化為在此字典中查找,例如 C.x 會被轉(zhuǎn)化為 C.__dict__["x"] (不過也存在一些鉤子對象以允許其他定位屬性的方式)。當(dāng)未在其中發(fā)現(xiàn)某個屬性名稱時,會繼續(xù)在基類中查找。這種基類查找使用 C3 方法解析順序,即使存在 ‘鉆石形’ 繼承結(jié)構(gòu)即有多條繼承路徑連到一個共同祖先也能保持正確的行為。有關(guān) Python 使用的 C3 MRO 的詳情可查看配合 2.3 版發(fā)布的文檔 https://www.python.org/download/releases/2.3/mro/.
當(dāng)一個類屬性引用 (假設(shè)類名為 C) 會產(chǎn)生一個類方法對象時,它將轉(zhuǎn)化為一個 __self__ 屬性為 C 的實例方法對象。當(dāng)其會產(chǎn)生一個靜態(tài)方法對象時,它將轉(zhuǎn)化為該靜態(tài)方法對象所封裝的對象。從類的 __dict__ 所包含內(nèi)容以外獲取屬性的其他方式請參看 實現(xiàn)描述器 一節(jié)。
類屬性賦值會更新類的字典,但不會更新基類的字典。
類對象可被調(diào)用 (見上文) 以產(chǎn)生一個類實例 (見下文)。
特殊屬性:
__name__
類的名稱。
__module__類定義所在模塊的名稱。
__dict__
包含類命名空間的字典。
__bases__
包含基類的元組,按它們在基類列表中的出現(xiàn)先后排序。
__doc__類的文檔字符串,如果未定義則為
None。
__annotations__包含在類體執(zhí)行期間收集的 變量標(biāo)注 的字典。 有關(guān)使用
__annotations__的最佳實踐,請參閱 對象注解屬性的最佳實踐。
類實例
類實例可通過調(diào)用類對象來創(chuàng)建(見上文)。 每個類實例都有通過一個字典對象實現(xiàn)的獨立命名空間,屬性引用會首先在此字典中查找。 當(dāng)未在其中發(fā)現(xiàn)某個屬性,而實例對應(yīng)的類中有該屬性時,會繼續(xù)在類屬性中查找。 如果找到的類屬性為一個用戶自定義函數(shù)對象,它會被轉(zhuǎn)化為實例方法對象,其 __self__ 屬性即該實例。 靜態(tài)方法和類方法對象也會被轉(zhuǎn)化;參見上文的“類”小節(jié)。 要了解其他通過類實例來獲取相應(yīng)類屬性的方式請參閱 實現(xiàn)描述器 小節(jié),這樣得到的屬性可能與實際存放在類的 __dict__ 中的對象不同。 如果未找到類屬性,而對象所屬的類具有 __getattr__() 方法,則會調(diào)用該方法來滿足查找要求。
屬性賦值和刪除會更新實例的字典,但絕不會更新類的字典。 如果類具有 __setattr__() 或 __delattr__() 方法,則將調(diào)用該方法而不再直接更新實例的字典。
如果類實例具有某些特殊名稱的方法,就可以偽裝為數(shù)字、序列或映射。參見 特殊方法名稱 一節(jié)。
特殊屬性: __dict__ 為屬性字典; __class__ 為實例對應(yīng)的類。
I/O 對象 (或稱文件對象)
file object 表示一個打開的文件。有多種快捷方式可用來創(chuàng)建文件對象: open() 內(nèi)置函數(shù),以及 os.popen(), os.fdopen() 和 socket 對象的 makefile() 方法 (還可能使用某些擴展模塊所提供的其他函數(shù)或方法)。
sys.stdin, sys.stdout 和 sys.stderr 會初始化為對應(yīng)于解釋器標(biāo)準(zhǔn)輸入、輸出和錯誤流的文件對象;它們都會以文本模式打開,因此都遵循 io.TextIOBase 抽象類所定義的接口。
內(nèi)部類型
某些由解釋器內(nèi)部使用的類型也被暴露給用戶。它們的定義可能隨未來解釋器版本的更新而變化,為內(nèi)容完整起見在此處一并介紹。
代碼對象
代碼對象表示 編譯為字節(jié)的 可執(zhí)行 Python 代碼,或稱 bytecode。代碼對象和函數(shù)對象的區(qū)別在于函數(shù)對象包含對函數(shù)全局對象 (函數(shù)所屬的模塊) 的顯式引用,而代碼對象不包含上下文;而且默認(rèn)參數(shù)值會存放于函數(shù)對象而不是代碼對象內(nèi) (因為它們表示在運行時算出的值)。與函數(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 的標(biāo)志位定義:如果函數(shù)使用 *arguments 語法來接受任意數(shù)量的位置參數(shù),則 0x04 位被設(shè)置;如果函數(shù)使用 **keywords 語法來接受任意數(shù)量的關(guān)鍵字參數(shù),則 0x08 位被設(shè)置;如果函數(shù)是一個生成器,則 0x20 位被設(shè)置。
未來特性聲明 (from __future__ import division) 也使用 co_flags 中的標(biāo)志位來指明代碼對象的編譯是否啟用特定的特性: 如果函數(shù)編譯時啟用未來除法特性則設(shè)置 0x2000 位; 在更早的 Python 版本中則使用 0x10 和 0x1000 位。
co_flags 中的其他位被保留為內(nèi)部使用。
如果代碼對象表示一個函數(shù),co_consts 中的第一項將是函數(shù)的文檔字符串,如果未定義則為 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 the PYTHONNODEBUGRANGES environment variable can be used.
幀對象
幀對象表示執(zhí)行幀。它們可能出現(xiàn)在回溯對象中 (見下文),還會被傳遞給注冊跟蹤函數(shù)。
特殊的只讀屬性: f_back 為前一堆棧幀 (指向調(diào)用者),如是最底層堆棧幀則為 None; f_code 為此幀中所執(zhí)行的代碼對象; f_locals 為用于查找本地變量的字典; f_globals 則用于查找全局變量; f_builtins 用于查找內(nèi)置 (固有) 名稱; f_lasti 給出精確指令 (這是代碼對象的字節(jié)碼字符串的一個索引)。
訪問 f_code 會引發(fā)一個 審計事件 object.__getattr__,附帶參數(shù) obj 和 "f_code"。
特殊的可寫屬性: f_trace,如果不為 None,則是在代碼執(zhí)行期間調(diào)用各類事件的函數(shù) (由調(diào)試器使用)。通常每個新源碼行會觸發(fā)一個事件 - 這可以通過將 f_trace_lines 設(shè)為 False 來禁用。
具體的實現(xiàn) 可能 會通過將 f_trace_opcodes 設(shè)為 True 來允許按操作碼請求事件。請注意如果跟蹤函數(shù)引發(fā)的異常逃逸到被跟蹤的函數(shù)中,這可能會導(dǎo)致未定義的解釋器行為。
f_lineno 為幀的當(dāng)前行號 —- 在這里寫入從一個跟蹤函數(shù)內(nèi)部跳轉(zhuǎn)的指定行 (僅用于最底層的幀)。調(diào)試器可以通過寫入 f_lineno 實現(xiàn)一個 Jump 命令 (即設(shè)置下一語句)。
幀對象支持一個方法:
frame.clear()
此方法清除該幀持有的全部對本地變量的引用。而且如果該幀屬于一個生成器,生成器會被完成。這有助于打破包含幀對象的循環(huán)引用 (例如當(dāng)捕獲一個異常并保存其回溯在之后使用)。
如果該幀當(dāng)前正在執(zhí)行則會引發(fā) RuntimeError。
3.4 新版功能.
回溯對象
回溯對象表示一個異常的棧跟蹤記錄。當(dāng)異常發(fā)生時會隱式地創(chuàng)建一個回溯對象,也可能通過調(diào)用 types.TracebackType 顯式地創(chuàng)建。
對于隱式地創(chuàng)建的回溯對象,當(dāng)查找異常句柄使得執(zhí)行棧展開時,會在每個展開層級的當(dāng)前回溯之前插入一個回溯對象。當(dāng)進入一個異常句柄時,棧跟蹤將對程序啟用。(參見 try 語句 一節(jié)。) 它可作為 sys.exc_info() 所返回的元組的第三項,以及所捕獲異常的 __traceback__ 屬性被獲取。
當(dāng)程序不包含可用的句柄時,棧跟蹤會 (以良好的格式) 寫入標(biāo)準(zhǔn)錯誤流;如果解釋器處于交互模式,它也可作為 sys.last_traceback 對用戶啟用。
對于顯式創(chuàng)建的回溯對象,則由回溯對象的創(chuàng)建者來決定應(yīng)該如何鏈接 tb_next 屬性來構(gòu)成完整的棧跟蹤。
特殊的只讀屬性: tb_frame 指向當(dāng)前層級的執(zhí)行幀; tb_lineno 給出發(fā)生異常所在的行號; tb_lasti 標(biāo)示具體指令。如果異常發(fā)生于沒有匹配的 except 子句或有 finally 子句的 try 語句中,回溯對象中的行號和最后指令可能與相應(yīng)幀對象中行號不同。
訪問 tb_frame 會引發(fā)一個 審計事件 object.__getattr__,附帶參數(shù) obj 和 "tb_frame"。
特殊的可寫屬性: tb_next 為棧跟蹤中的下一層級 (通往發(fā)生異常的幀),如果沒有下一層級則為 None。
在 3.7 版更改: 回溯對象現(xiàn)在可以使用 Python 代碼顯式地實例化,現(xiàn)有實例的 tb_next 屬性可以被更新。
切片對象
切片對象被用來表示 __getitem__() 方法所使用的切片。 該對象也可使用內(nèi)置的 slice() 函數(shù)來創(chuàng)建。
特殊的只讀屬性: start 為下界; stop 為上界; step 為步長值; 各值如省略則為 None。這些屬性可具有任意類型。
切片對象支持一個方法:
slice.indices(self, length)
此方法接受一個整型參數(shù) length 并計算在切片對象被應(yīng)用到 length 指定長度的條目序列時切片的相關(guān)信息應(yīng)如何描述。 其返回值為三個整型數(shù)組成的元組;這些數(shù)分別為切片的 start 和 stop 索引號以及 step 步長值。索引號缺失或越界則按照與正規(guī)切片相一致的方式處理。
靜態(tài)方法對象
靜態(tài)方法對象提供了一種勝過上文所述將函數(shù)對象轉(zhuǎn)換為方法對象的方式。 靜態(tài)方法對象是對任意其他對象的包裝器,通常用來包裝用戶自定義的方法對象。 當(dāng)從類或類實例獲取一個靜態(tài)方法對象時,實際返回的是經(jīng)過包裝的對象,它不會被進一步轉(zhuǎn)換。 靜態(tài)方法對象也是可調(diào)用對象。 靜態(tài)方法對象可通過內(nèi)置的 staticmethod() 構(gòu)造器來創(chuàng)建。
類方法對象
類方法對象和靜態(tài)方法一樣是對其他對象的封裝,會改變從類或類實例獲取該對象的方式。類方法對象在此類獲取操作中的行為已在上文 “用戶定義方法” 一節(jié)中描述。類方法對象可通過內(nèi)置的 classmethod() 構(gòu)造器來創(chuàng)建。
一個類可以通過定義具有特殊名稱的方法來實現(xiàn)由特殊語法來發(fā)起調(diào)用的特定操作(例如算術(shù)運算或抽取與切片)。 這是 Python 實現(xiàn) 運算符重載 的方式,允許每個類自行定義基于該語言運算符的特定行為。 舉例來說,如果一個類定義了名為 __getitem__() 的方法,并且 x 是該類的一個實例,則 x[i] 基本就等價于 type(x).__getitem__(x, i)。 除非有說明例外情況,在沒有定義適當(dāng)方法的時候嘗試執(zhí)行某種操作將引發(fā)一個異常 (通常為 AttributeError 或 TypeError)。
將一個特殊方法設(shè)為 None 表示對應(yīng)的操作不可用。 例如,如果一個類將 __iter__() 設(shè)為 None,則該類就是不可迭代的,因此對其實例調(diào)用 iter() 將引發(fā)一個 TypeError (而不會回退至 __getitem__())。 2
在實現(xiàn)模擬任何內(nèi)置類型的類時,很重要的一點是模擬的實現(xiàn)程度對于被模擬對象來說應(yīng)當(dāng)是有意義的。例如,提取單個元素的操作對于某些序列來說是適宜的,但提取切片可能就沒有意義。(這種情況的一個實例是 W3C 的文檔對象模型中的 NodeList 接口。)
object.__new__(cls[, …])
調(diào)用以創(chuàng)建一個 cls 類的新實例。__new__() 是一個靜態(tài)方法 (因為是特例所以你不需要顯式地聲明),它會將所請求實例所屬的類作為第一個參數(shù)。其余的參數(shù)會被傳遞給對象構(gòu)造器表達(dá)式 (對類的調(diào)用)。__new__() 的返回值應(yīng)為新對象實例 (通常是 cls 的實例)。
Typical implementations create a new instance of the class by invoking the superclass’s __new__() method using super().__new__(cls[, ...]) with appropriate arguments and then modifying the newly created instance as necessary before returning it.
如果 __new__() 在構(gòu)造對象期間被發(fā)起調(diào)用并且它返回了一個 cls 的實例,則新實例的 __init__() 方法將以 __init__(self[, ...]) 的形式被發(fā)起調(diào)用,其中 self 為新實例而其余的參數(shù)與被傳給對象構(gòu)造器的參數(shù)相同。
如果 __new__() 未返回一個 cls 的實例,則新實例的 __init__() 方法就不會被執(zhí)行。
__new__() 的目的主要是允許不可變類型的子類 (例如 int, str 或 tuple) 定制實例創(chuàng)建過程。它也常會在自定義元類中被重載以便定制類創(chuàng)建過程。
object.__init__(self[, …])
在實例 (通過 __new__()) 被創(chuàng)建之后,返回調(diào)用者之前調(diào)用。其參數(shù)與傳遞給類構(gòu)造器表達(dá)式的參數(shù)相同。一個基類如果有 __init__() 方法,則其所派生的類如果也有 __init__() 方法,就必須顯式地調(diào)用它以確保實例基類部分的正確初始化;例如: super().__init__([args...]).
因為對象是由 __new__() 和 __init__() 協(xié)作構(gòu)造完成的 (由 __new__() 創(chuàng)建,并由 __init__() 定制),所以 __init__() 返回的值只能是 None,否則會在運行時引發(fā) TypeError。
object.__del__(self)
在實例將被銷毀時調(diào)用。 這還被稱為終結(jié)器或析構(gòu)器(不適當(dāng))。 如果一個基類具有 __del__() 方法,則其所派生的類如果也有 __del__() 方法,就必須顯式地調(diào)用它以確保實例基類部分的正確清除。
__del__() 方法可以 (但不推薦!) 通過創(chuàng)建一個該實例的新引用來推遲其銷毀。這被稱為對象 重生。__del__() 是否會在重生的對象將被銷毀時再次被調(diào)用是由具體實現(xiàn)決定的 ;當(dāng)前的 CPython 實現(xiàn)只會調(diào)用一次。
當(dāng)解釋器退出時不會確保為仍然存在的對象調(diào)用 __del__() 方法。
備注
del x 并不直接調(diào)用 x.__del__() —- 前者會將 x 的引用計數(shù)減一,而后者僅會在 x 的引用計數(shù)變?yōu)榱銜r被調(diào)用。
CPython 實現(xiàn)細(xì)節(jié): 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.
參見
gc 模塊的文檔。
警告
由于調(diào)用 __del__() 方法時周邊狀況已不確定,在其執(zhí)行期間發(fā)生的異常將被忽略,改為打印一個警告到 sys.stderr。特別地:
__del__() 可在任意代碼被執(zhí)行時啟用,包括來自任意線程的代碼。如果 __del__() 需要接受鎖或啟用其他阻塞資源,可能會發(fā)生死鎖,例如該資源已被為執(zhí)行 __del__() 而中斷的代碼所獲取。
__del__() 可以在解釋器關(guān)閉階段被執(zhí)行。因此,它需要訪問的全局變量(包含其他模塊)可能已被刪除或設(shè)為 None。Python 會保證先刪除模塊中名稱以單個下劃線打頭的全局變量再刪除其他全局變量;如果已不存在其他對此類全局變量的引用,這有助于確保導(dǎo)入的模塊在 __del__() 方法被調(diào)用時仍然可用。
object.__repr__(self)
由 repr() 內(nèi)置函數(shù)調(diào)用以輸出一個對象的“官方”字符串表示。如果可能,這應(yīng)類似一個有效的 Python 表達(dá)式,能被用來重建具有相同取值的對象(只要有適當(dāng)?shù)沫h(huán)境)。如果這不可能,則應(yīng)返回形式如 <...some useful description...> 的字符串。返回值必須是一個字符串對象。如果一個類定義了 __repr__() 但未定義 __str__(),則在需要該類的實例的“非正式”字符串表示時也會使用 __repr__()。
此方法通常被用于調(diào)試,因此確保其表示的內(nèi)容包含豐富信息且無歧義是很重要的。
object.__str__(self)
通過 str(object) 以及內(nèi)置函數(shù) format() 和 print() 調(diào)用以生成一個對象的“非正式”或格式良好的字符串表示。返回值必須為一個 字符串 對象。
此方法與 object.__repr__() 的不同點在于 __str__() 并不預(yù)期返回一個有效的 Python 表達(dá)式:可以使用更方便或更準(zhǔn)確的描述信息。
內(nèi)置類型 object 所定義的默認(rèn)實現(xiàn)會調(diào)用 object.__repr__()。
object.__bytes__(self)
通過 bytes 調(diào)用以生成一個對象的字節(jié)串表示。這應(yīng)該返回一個 bytes 對象。
object.__format__(self, format_spec)
通過 format() 內(nèi)置函數(shù)、擴展、格式化字符串字面值 的求值以及 str.format() 方法調(diào)用以生成一個對象的“格式化”字符串表示。 format_spec 參數(shù)為包含所需格式選項描述的字符串。 format_spec 參數(shù)的解讀是由實現(xiàn) __format__() 的類型決定的,不過大多數(shù)類或是將格式化委托給某個內(nèi)置類型,或是使用相似的格式化選項語法。
請參看 格式規(guī)格迷你語言 了解標(biāo)準(zhǔn)格式化語法的描述。
返回值必須為一個字符串對象。
在 3.4 版更改: object 本身的 __format__ 方法如果被傳入任何非空字符,將會引發(fā)一個 TypeError。
在 3.7 版更改: object.__format__(x, '') 現(xiàn)在等同于 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)
以上這些被稱為“富比較”方法。運算符號與方法名稱的對應(yīng)關(guān)系如下:xx.__lt__(y)、x<=y 調(diào)用 x.__le__(y)、x==y 調(diào)用 x.__eq__(y)、x!=y 調(diào)用 x.__ne__(y)、x>y 調(diào)用 x.__gt__(y)、x>=y 調(diào)用 x.__ge__(y)。
如果指定的參數(shù)對沒有相應(yīng)的實現(xiàn),富比較方法可能會返回單例對象 NotImplemented。按照慣例,成功的比較會返回 False 或 True。不過實際上這些方法可以返回任意值,因此如果比較運算符是要用于布爾值判斷(例如作為 if 語句的條件),Python 會對返回值調(diào)用 bool() 以確定結(jié)果為真還是假。
在默認(rèn)情況下,object 通過使用 is 來實現(xiàn) __eq__(),并在比較結(jié)果為假值時返回 NotImplemented: True if x is y else NotImplemented。 對于 __ne__(),默認(rèn)會委托給 __eq__() 并對結(jié)果取反,除非結(jié)果為 NotImplemented。 比較運算符之間沒有其他隱含關(guān)系或默認(rèn)實現(xiàn);例如,(xx<=y。 要根據(jù)單根運算自動生成排序操作,請參看 functools.total_ordering()。
請查看 __hash__() 的相關(guān)段落,了解創(chuàng)建可支持自定義比較運算并可用作字典鍵的 hashable 對象時要注意的一些事項。
這些方法并沒有對調(diào)參數(shù)版本(在左邊參數(shù)不支持該操作但右邊參數(shù)支持時使用);而是 __lt__() 和 __gt__() 互為對方的反射, __le__() 和 __ge__() 互為對方的反射,而 __eq__() 和 __ne__() 則是它們自己的反射。如果兩個操作數(shù)的類型不同,且右操作數(shù)類型是左操作數(shù)類型的直接或間接子類,則優(yōu)先選擇右操作數(shù)的反射方法,否則優(yōu)先選擇左操作數(shù)的方法。虛擬子類不會被考慮。
object.__hash__(self)
通過內(nèi)置函數(shù) hash() 調(diào)用以對哈希集的成員進行操作,屬于哈希集的類型包括 set、frozenset 以及 dict。__hash__() 應(yīng)該返回一個整數(shù)。對象比較結(jié)果相同所需的唯一特征屬性是其具有相同的哈希值;建議的做法是把參與比較的對象全部組件的哈希值混在一起,即將它們打包為一個元組并對該元組做哈希運算。例如:
def __hash__(self):return hash((self.name, self.nick, self.color))
備注
hash() 會從一個對象自定義的 __hash__() 方法返回值中截斷為 Py_ssize_t 的大小。通常對 64 位構(gòu)建為 8 字節(jié),對 32 位構(gòu)建為 4 字節(jié)。如果一個對象的 __hash__() 必須在不同位大小的構(gòu)建上進行互操作,請確保檢查全部所支持構(gòu)建的寬度。做到這一點的簡單方法是使用 python -c "import sys; print(sys.hash_info.width)"。
如果一個類沒有定義 __eq__() 方法,那么也不應(yīng)該定義 __hash__() 操作;如果它定義了 __eq__() 但沒有定義 __hash__(),則其實例將不可被用作可哈希集的項。如果一個類定義了可變對象并實現(xiàn)了 __eq__() 方法,則不應(yīng)該實現(xiàn) __hash__(),因為可哈希集的實現(xiàn)要求鍵的哈希集是不可變的(如果對象的哈希值發(fā)生改變,它將處于錯誤的哈希桶中)。
用戶定義的類默認(rèn)帶有 __eq__() 和 __hash__() 方法;使用它們與任何對象(自己除外)比較必定不相等,并且 x.__hash__() 會返回一個恰當(dāng)?shù)闹狄源_保 x == y 同時意味著 x is y 且 hash(x) == hash(y)。
一個類如果重載了 __eq__() 且沒有定義 __hash__() 則會將其 __hash__() 隱式地設(shè)為 None。當(dāng)一個類的 __hash__() 方法為 None 時,該類的實例將在一個程序嘗試獲取其哈希值時正確地引發(fā) TypeError,并會在檢測 isinstance(obj, collections.abc.Hashable) 時被正確地識別為不可哈希對象。
如果一個重載了 __eq__() 的類需要保留來自父類的 __hash__() 實現(xiàn),則必須通過設(shè)置 __hash__ = 來顯式地告知解釋器。
如果一個沒有重載 __eq__() 的類需要去掉哈希支持,則應(yīng)該在類定義中包含 __hash__ = None。一個自定義了 __hash__() 以顯式地引發(fā) TypeError 的類會被 isinstance(obj, collections.abc.Hashable) 調(diào)用錯誤地識別為可哈希對象。
備注
在默認(rèn)情況下,str 和 bytes 對象的 __hash__() 值會使用一個不可預(yù)知的隨機值“加鹽”。 雖然它們在一個單獨 Python 進程中會保持不變,但它們的值在重復(fù)運行的 Python 間是不可預(yù)測的。
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.
改變哈希值會影響集合的迭代次序。Python 也從不保證這個次序不會被改變(通常它在 32 位和 64 位構(gòu)建上是不一致的)。
另見 PYTHONHASHSEED.
在 3.3 版更改: 默認(rèn)啟用哈希隨機化。
object.__bool__(self)
調(diào)用此方法以實現(xiàn)真值檢測以及內(nèi)置的 bool() 操作;應(yīng)該返回 False 或 True。如果未定義此方法,則會查找并調(diào)用 __len__() 并在其返回非零值時視對象的邏輯值為真。如果一個類既未定義 __len__() 也未定義 __bool__() 則視其所有實例的邏輯值為真。
可以定義下列方法來自定義對類實例屬性訪問(x.name 的使用、賦值或刪除)的具體含義.
object.__getattr__(self, name)
當(dāng)默認(rèn)屬性訪問因引發(fā) AttributeError 而失敗時被調(diào)用 (可能是調(diào)用 __getattribute__() 時由于 name 不是一個實例屬性或 self 的類關(guān)系樹中的屬性而引發(fā)了 AttributeError;或者是對 name 特性屬性調(diào)用 __get__() 時引發(fā)了 AttributeError)。此方法應(yīng)當(dāng)返回(找到的)屬性值或是引發(fā)一個 AttributeError 異常。
請注意如果屬性是通過正常機制找到的,__getattr__() 就不會被調(diào)用。(這是在 __getattr__() 和 __setattr__() 之間故意設(shè)置的不對稱性。)這既是出于效率理由也是因為不這樣設(shè)置的話 __getattr__() 將無法訪問實例的其他屬性。要注意至少對于實例變量來說,你不必在實例屬性字典中插入任何值(而是通過插入到其他對象)就可以模擬對它的完全控制。請參閱下面的 __getattribute__() 方法了解真正獲取對屬性訪問的完全控制權(quán)的辦法。
object.__getattribute__(self, name)
此方法會無條件地被調(diào)用以實現(xiàn)對類實例屬性的訪問。如果類還定義了 __getattr__(),則后者不會被調(diào)用,除非 __getattribute__() 顯式地調(diào)用它或是引發(fā)了 AttributeError。此方法應(yīng)當(dāng)返回(找到的)屬性值或是引發(fā)一個 AttributeError 異常。為了避免此方法中的無限遞歸,其實現(xiàn)應(yīng)該總是調(diào)用具有相同名稱的基類方法來訪問它所需要的任何屬性,例如 object.__getattribute__(self, name)。
備注
此方法在作為通過特定語法或內(nèi)置函數(shù)隱式地調(diào)用的結(jié)果的情況下查找特殊方法時仍可能會被跳過。參見 特殊方法查找。
引發(fā)一個 審計事件 object.__getattr__,附帶參數(shù) obj, name。
object.__setattr__(self, name, value)
此方法在一個屬性被嘗試賦值時被調(diào)用。這個調(diào)用會取代正常機制(即將值保存到實例字典)。 name 為屬性名稱, value 為要賦給屬性的值。
如果 __setattr__() 想要賦值給一個實例屬性,它應(yīng)該調(diào)用同名的基類方法,例如 object.__setattr__(self, name, value)。
引發(fā)一個 審計事件 object.__setattr__,附帶參數(shù) obj, name, value。
object.__delattr__(self, name)
類似于 __setattr__() 但其作用為刪除而非賦值。此方法應(yīng)該僅在 del obj.name 對于該對象有意義時才被實現(xiàn)。
引發(fā)一個 審計事件 object.__delattr__,附帶參數(shù) obj, name。
object.__dir__(self)
此方法會在對相應(yīng)對象調(diào)用 dir() 時被調(diào)用。返回值必須為一個序列。 dir() 會把返回的序列轉(zhuǎn)換為列表并對其排序。
特殊名稱 __getattr__ 和 __dir__ 還可被用來自定義對模塊屬性的訪問。模塊層級的 __getattr__ 函數(shù)應(yīng)當(dāng)接受一個參數(shù),其名稱為一個屬性名,并返回計算結(jié)果值或引發(fā)一個 AttributeError。如果通過正常查找即 object.__getattribute__() 未在模塊對象中找到某個屬性,則 __getattr__ 會在模塊的 __dict__ 中查找,未找到時會引發(fā)一個 AttributeError。如果找到,它會以屬性名被調(diào)用并返回結(jié)果值。
__dir__ 函數(shù)應(yīng)當(dāng)不接受任何參數(shù),并且返回一個表示模塊中可訪問名稱的字符串序列。 此函數(shù)如果存在,將會重載一個模塊中的標(biāo)準(zhǔn) dir() 查找。
想要更細(xì)致地自定義模塊的行為(設(shè)置屬性和特性屬性等待),可以將模塊對象的 __class__ 屬性設(shè)置為一個 types.ModuleType 的子類。例如:
import sysfrom types import ModuleTypeclass 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__ 和設(shè)置模塊的 __class__ 只會影響使用屬性訪問語法進行的查找 — 直接訪問模塊全局變量(不論是通過模塊內(nèi)的代碼還是通過對模塊全局字典的引用)是不受影響的。
在 3.5 版更改: __class__ 模塊屬性改為可寫。
3.7 新版功能: __getattr__ 和 __dir__ 模塊屬性。
參見
PEP 562 - 模塊 __getattr__ 和 __dir__
描述用于模塊的 __getattr__ 和 __dir__ 函數(shù)。
以下方法僅當(dāng)一個包含該方法的類(稱為 描述器 類)的實例出現(xiàn)于一個 所有者 類中的時候才會起作用(該描述器必須在所有者類或其某個上級類的字典中)。在以下示例中,“屬性”指的是名稱為所有者類 __dict__ 中的特征屬性的鍵名的屬性。
object.__get__(self, instance, owner=None)
調(diào)用此方法以獲取所有者類的屬性(類屬性訪問)或該類的實例的屬性(實例屬性訪問)。 可選的 owner 參數(shù)是所有者類而 instance 是被用來訪問屬性的實例,如果通過 owner 來訪問屬性則返回 None。
此方法應(yīng)當(dāng)返回計算得到的屬性值或是引發(fā) AttributeError 異常。
PEP 252 指明 __get__() 為帶有一至二個參數(shù)的可調(diào)用對象。 Python 自身內(nèi)置的描述器支持此規(guī)格定義;但是,某些第三方工具可能要求必須帶兩個參數(shù)。 Python 自身的 __getattribute__() 實現(xiàn)總是會傳入兩個參數(shù),無論它們是否被要求提供。
object.__set__(self, instance, value)
調(diào)用此方法以設(shè)置 instance 指定的所有者類的實例的屬性為新值 value。
請注意,添加 __set__() 或 __delete__() 會將描述器變成“數(shù)據(jù)描述器”。 更多細(xì)節(jié)請參閱 調(diào)用描述器。
object.__delete__(self, instance)
調(diào)用此方法以刪除 instance 指定的所有者類的實例的屬性。
屬性 __objclass__ 會被 inspect 模塊解讀為指定此對象定義所在的類(正確設(shè)置此屬性有助于動態(tài)類屬性的運行時內(nèi)?。τ诳烧{(diào)用對象來說,它可以指明預(yù)期或要求提供一個特定類型(或子類)的實例作為第一個位置參數(shù)(例如,CPython 會為實現(xiàn)于 C 中的未綁定方法設(shè)置此屬性)。
總的說來,描述器就是具有“綁定行為”的對象屬性,其屬性訪問已被描述器協(xié)議中的方法所重載: __get__(), __set__() 和 __delete__()。 如果一個對象定義了以上方法中的任意一個,它就被稱為描述器。
屬性訪問的默認(rèn)行為是從一個對象的字典中獲取、設(shè)置或刪除屬性。例如,a.x 的查找順序會從 a.__dict__['x'] 開始,然后是 type(a).__dict__['x'],接下來依次查找 type(a) 的上級基類,不包括元類。
但是,如果找到的值是定義了某個描述器方法的對象,則 Python 可能會重載默認(rèn)行為并轉(zhuǎn)而發(fā)起調(diào)用描述器方法。這具體發(fā)生在優(yōu)先級鏈的哪個環(huán)節(jié)則要根據(jù)所定義的描述器方法及其被調(diào)用的方式來決定。
描述器發(fā)起調(diào)用的開始點是一個綁定 a.x。參數(shù)的組合方式依 a 而定:
直接調(diào)用
最簡單但最不常見的調(diào)用方式是用戶代碼直接發(fā)起調(diào)用一個描述器方法: x.__get__(a)。
實例綁定
如果綁定到一個對象實例,a.x 會被轉(zhuǎn)換為調(diào)用: type(a).__dict__['x'].__get__(a, type(a))。
類綁定
如果綁定到一個類,A.x 會被轉(zhuǎn)換為調(diào)用: A.__dict__['x'].__get__(None, A)。
超綁定
A dotted lookup such as super(A, a).x searches a.__class__.__mro__ for a base class B following A and then returns B.__dict__['x'].__get__(a, A). If not a descriptor, x is returned unchanged.
對于實例綁定,發(fā)起描述器調(diào)用的優(yōu)先級取決于定義了哪些描述器方法。 一個描述器可以定義 __get__(), __set__() 和 __delete__() 的任意組合。 如果它沒有定義 __get__(),則訪問屬性將返回描述器對象自身,除非對象的實例字典中有相應(yīng)的屬性值。 如果描述器定義了 __set__() 和/或 __delete__(),則它是一個數(shù)據(jù)描述器;如果以上兩個都未定義,則它是一個非數(shù)據(jù)描述器。 通常,數(shù)據(jù)描述器會同時定義 __get__() 和 __set__(),而非數(shù)據(jù)描述器則只有 __get__() 方法。 定義了 __get__() 和 __set__() (和/或 __delete__()) 的數(shù)據(jù)描述器總是會重載實例字典中的定義。 與之相對地,非數(shù)據(jù)描述器則可被實例所重載。
Python 方法(包括用 @staticmethod 和 @classmethod 裝飾的方法)都是作為非數(shù)據(jù)描述器來實現(xiàn)的。 因而,實例可以重定義和重載方法。 這允許單個實例獲得與相同類的其他實例不一樣的行為。
property() 函數(shù)是作為數(shù)據(jù)描述器來實現(xiàn)的。因此實例不能重載特性屬性的行為。
__slots__ 允許我們顯式地聲明數(shù)據(jù)成員(如特征屬性)并禁
本文題目:創(chuàng)新互聯(lián)Python教程:3. 數(shù)據(jù)模型
瀏覽路徑:http://uogjgqi.cn/article/cohhhes.html

我們在微信上24小時期待你的聲音
解答本文疑問/技術(shù)咨詢/運營咨詢/技術(shù)建議/互聯(lián)網(wǎng)交流