<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??一站式輕松地調用各大LLM模型接口,支持GPT4、智譜、豆包、星火、月之暗面及文生圖、文生視頻 廣告
                ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](executionmodel.xhtml "4. 執行模型") | - [上一頁](lexical_analysis.xhtml "2. 詞法分析") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 語言參考](index.xhtml) ? - $('.inline-search').show(0); | # 3. 數據模型 ## 3.1. 對象、值與類型 *對象* 是 Python 中對數據的抽象。Python 程序中的所有數據都是由對象或對象間關系來表示的。(從某種意義上說,按照馮·諾依曼的 “存儲程序計算機” 模型,代碼本身也是由對象來表示的。) 每個對象都有各自的編號、類型和值。一個對象被創建后,它的 *編號* 就絕不會改變;你可以將其理解為該對象在內存中的地址。 '[`is`](expressions.xhtml#is)' 運算符可以比較兩個對象的編號是否相同;[`id()`](../library/functions.xhtml#id "id") 函數能返回一個代表其編號的整型數。 **CPython implementation detail:** 在 CPython 中,`id(x)` 就是存放 `x` 的內存的地址。 對象的類型決定該對象所支持的操作 (例如 "對象是否有長度屬性?") 并且定義了該類型的對象可能的取值。[`type()`](../library/functions.xhtml#type "type") 函數能返回一個對象的類型 (類型本身也是對象)。與編號一樣,一個對象的 *類型* 也是不可改變的。[1](#id8) 有些對象的 *值* 可以改變。值可以改變的對象被稱為 *可變的*;值不可以改變的對象就被稱為 *不可變的*。(一個不可變容器對象如果包含對可變對象的引用,當后者的值改變時,前者的值也會改變;但是該容器仍屬于不可變對象,因為它所包含的對象集是不會改變的。因此,不可變并不嚴格等同于值不能改變,實際含義要更微妙。) 一個對象的可變性是由其類型決定的;例如,數字、字符串和元組是不可變的,而字典和列表是可變的。 對象絕不會被顯式地銷毀;然而,當無法訪問時它們可能會被作為垃圾回收。允許具體的實現推遲垃圾回收或完全省略此機制 --- 如何實現垃圾回收是實現的質量問題,只要可訪問的對象不會被回收即可。 **CPython implementation detail:** CPython 目前使用帶有 (可選) 延遲檢測循環鏈接垃圾的引用計數方案,會在對象不可訪問時立即回收其中的大部分,但不保證回收包含循環引用的垃圾。請查看 [`gc`](../library/gc.xhtml#module-gc "gc: Interface to the cycle-detecting garbage collector.") 模塊的文檔了解如何控制循環垃圾的收集相關信息。其他實現會有不同的行為方式,CPython 現有方式也可能改變。不要依賴不可訪問對象的立即終結機制 (所以你應當總是顯式地關閉文件)。 注意:使用實現的跟蹤或調試功能可能令正常情況下會被回收的對象繼續存活。還要注意通過 '[`try`](compound_stmts.xhtml#try)...[`except`](compound_stmts.xhtml#except)' 語句捕捉異常也可能令對象保持存活。 有些對象包含對 "外部" 資源的引用,例如打開文件或窗口。當對象被作為垃圾回收時這些資源也應該會被釋放,但由于垃圾回收并不確保發生,這些對象還提供了明確地釋放外部資源的操作,通常為一個 `close()` 方法。強烈推薦在程序中顯式關閉此類對象。'[`try`](compound_stmts.xhtml#try)...[`finally`](compound_stmts.xhtml#finally)' 語句和 '[`with`](compound_stmts.xhtml#with)' 語句提供了進行此種操作的更便捷方式。 有些對象包含對其他對象的引用;它們被稱為 *容器*。容器的例子有元組、列表和字典等。這些引用是容器對象值的組成部分。在多數情況下,當談論一個容器的值時,我們是指所包含對象的值而不是其編號;但是,當我們談論一個容器的可變性時,則僅指其直接包含的對象的編號。因此,如果一個不可變容器 (例如元組) 包含對一個可變對象的引用,則當該可變對象被改變時容器的值也會改變。 類型會影響對象行為的幾乎所有方面。甚至對象編號的重要性也在某種程度上受到影響: 對于不可變類型,會得出新值的運算實際上會返回對相同類型和取值的任一現有對象的引用,而對于可變類型來說這是不允許的。例如在 `a = 1; b = 1` 之后,`a` 和 `b` 可能會也可能不會指向同一個值為一的對象,這取決于具體實現,但是在 `c = []; d = []` 之后,`c` 和 `d` 保證會指向兩個不同、單獨的新建空列表。(請注意 `c = d = []` 則是將同一個對象賦值給 `c` 和 `d`。) ## 3.2. 標準類型層級結構 以下是 Python 內置類型的列表。擴展模塊 (具體實現會以 C, Java 或其他語言編寫) 可以定義更多的類型。未來版本的 Python 可能會加入更多的類型 (例如有理數、高效存儲的整型數組等等),不過新增類型往往都是通過標準庫來提供的。 以下部分類型的描述中包含有 '特殊屬性列表' 段落。這些屬性提供對具體實現的訪問而非通常使用。它們的定義在未來可能會改變。 None此類型只有一種取值。是一個具有此值的單獨對象。此對象通過內置名稱 `None` 訪問。在許多情況下它被用來表示空值,例如未顯式指明返回值的函數將返回 None。它的邏輯值為假。 NotImplemented此類型只有一種取值。是一個具有此值的單獨對象。此對象通過內置名稱 `NotImplemented` 訪問。數值方法和豐富比較方法如未實現指定運算符表示的運算則應返回此值。(解釋器會根據指定運算符繼續嘗試反向運算或其他回退操作)。它的邏輯值為真。 詳情參見 [Implementing the arithmetic operations](../library/numbers.xhtml#implementing-the-arithmetic-operations)。 Ellipsis此類型只有一種取值。是一個具有此值的單獨對象。此對象通過字面值 `...` 或內置名稱 `Ellipsis` 訪問。它的邏輯值為真。 [`numbers.Number`](../library/numbers.xhtml#numbers.Number "numbers.Number")此類對象由數字字面值創建,并會被作為算術運算符和算術內置函數的返回結果。數字對象是不可變的;一旦創建其值就不再改變。Python 中的數字當然非常類似數學中的數字,但也受限于計算機中的數字表示方法。 Python 區分整型數、浮點型數和復數: [`numbers.Integral`](../library/numbers.xhtml#numbers.Integral "numbers.Integral")此類對象表示數學中整數集合的成員 (包括正數和負數)。 整型數可細分為兩種類型: 整型 ([`int`](../library/functions.xhtml#int "int")) > 此類對象表示任意大小的數字,僅受限于可用的內存 (包括虛擬內存)。在變換和掩碼運算中會以二進制表示,負數會以 2 的補碼表示,看起來像是符號位向左延伸補滿空位。 布爾型 ([`bool`](../library/functions.xhtml#bool "bool"))此類對象表示邏輯值 False 和 True。代表 `False` 和 `True` 值的兩個對象是唯二的布爾對象。布爾類型是整型的子類型,兩個布爾值在各種場合的行為分別類似于數值 0 和 1,例外情況只有在轉換為字符串時分別返回字符串 `"False"` 或 `"True"`。 整型數表示規則的目的是在涉及負整型數的變換和掩碼運算時提供最為合理的解釋。 [`numbers.Real`](../library/numbers.xhtml#numbers.Real "numbers.Real") ([`float`](../library/functions.xhtml#float "float"))此類對象表示機器級的雙精度浮點數。其所接受的取值范圍和溢出處理將受制于底層的機器架構 (以及 C 或 Java 實現)。Python 不支持單精度浮點數;支持后者通常的理由是節省處理器和內存消耗,但這點節省相對于在 Python 中使用對象的開銷來說太過微不足道,因此沒有理由包含兩種浮點數而令該語言變得復雜。 [`numbers.Complex`](../library/numbers.xhtml#numbers.Complex "numbers.Complex") ([`complex`](../library/functions.xhtml#complex "complex"))此類對象以一對機器級的雙精度浮點數來表示復數值。有關浮點數的附帶規則對其同樣有效。一個復數值 `z` 的實部和虛部可通過只讀屬性 `z.real` 和 `z.imag` 來獲取。 序列此類對象表示以非負整數作為索引的有限有序集。內置函數 [`len()`](../library/functions.xhtml#len "len") 可返回一個序列的條目數量。當一個序列的長度為 *n* 時,索引集包含數字 0, 1, ..., *n*-1。序列 *a* 的條目 *i* 可通過 `a[i]` 選擇。 序列還支持切片: `a[i:j]` 選擇索引號為 *k* 的所有條目,*i*`<=` *k*`<` *j*。當用作表達式時,序列的切片就是一個與序列類型相同的新序列。新序列的索引還是從 0 開始。 有些序列還支持帶有第三個 "step" 形參的 "擴展切片": `a[i:j:k]` 選擇 *a* 中索引號為 *x* 的所有條目,`x = i + n*k`, *n*`>=``0` 且 *i*`<=` *x*`<` *j*。 序列可根據其可變性來加以區分: 不可變序列不可變序列類型的對象一旦創建就不能再改變。(如果對象包含對其他對象的引用,其中的可變對象就是可以改變的;但是,一個不可變對象所直接引用的對象集是不能改變的。) 以下類型屬于不可變對象: 字符串字符串是由 Unicode 碼位值組成的序列。范圍在 `U+0000 - U+10FFFF` 之內的所有碼位值都可在字符串中使用。Python 沒有 `char` 類型;而是將字符串中的每個碼位表示為一個長度為 `1` 的字符串對象。內置函數 [`ord()`](../library/functions.xhtml#ord "ord") 可將一個碼位由字符串形式轉換成一個范圍在 `0 - 10FFFF` 之內的整型數;[`chr()`](../library/functions.xhtml#chr "chr") 可將一個范圍在 `0 - 10FFFF` 之內的整型數轉換為長度為 `1` 的對應字符串對象。[`str.encode()`](../library/stdtypes.xhtml#str.encode "str.encode") 可以使用指定的文本編碼將 [`str`](../library/stdtypes.xhtml#str "str") 轉換為 [`bytes`](../library/stdtypes.xhtml#bytes "bytes"),而 [`bytes.decode()`](../library/stdtypes.xhtml#bytes.decode "bytes.decode") 則可以實現反向的解碼。 元組一個元組中的條目可以是任意 Python 對象。包含兩個或以上條目的元組由逗號分隔的表達式構成。只有一個條目的元組 ('單項元組') 可通過在表達式后加一個逗號來構成 (一個表達式本身不能創建為元組,因為圓括號要用來設置表達式分組)。一個空元組可通過一對內容為空的圓括號創建。 字節串字節串對象是不可變的數組。其中每個條目都是一個 8 位字節,以取值范圍 0 <= x < 256 的整型數表示。字節串字面值 (例如 `b'abc'`) 和內置的 [`bytes()`](../library/stdtypes.xhtml#bytes "bytes") 構造器可被用來創建字節串對象。字節串對象還可以通過 [`decode()`](../library/stdtypes.xhtml#bytes.decode "bytes.decode") 方法解碼為字符串。 可變序列可變序列在被創建后仍可被改變。下標和切片標注可被用作賦值和 [`del`](simple_stmts.xhtml#del) (刪除) 語句的目標。 目前有兩種內生可變序列類型: 列表列表中的條目可以是任意 Python 對象。列表由用方括號括起并由逗號分隔的多個表達式構成。(注意創建長度為 0 或 1 的列表無需使用特殊規則。) 字節數組字節數組對象屬于可變數組。可以通過內置的 [`bytearray()`](../library/stdtypes.xhtml#bytearray "bytearray") 構造器來創建。除了是可變的 (因而也是不可哈希的),在其他方面字節數組提供的接口和功能都于不可變的 [`bytes`](../library/stdtypes.xhtml#bytes "bytes") 對象一致。 擴展模塊 [`array`](../library/array.xhtml#module-array "array: Space efficient arrays of uniformly typed numeric values.") 提供了一個額外的可變序列類型示例,[`collections`](../library/collections.xhtml#module-collections "collections: Container datatypes") 模塊也是如此。 集合類型此類對象表示由不重復且不可變對象組成的無序且有限的集合。因此它們不能通過下標來索引。但是它們可被迭代,也可用內置函數 [`len()`](../library/functions.xhtml#len "len") 返回集合中的條目數。集合常見的用處是快速成員檢測,去除序列中的重復項,以及進行交、并、差和對稱差等數學運算。 對于集合元素所采用的不可變規則與字典的鍵相同。注意數字類型遵循正常的數字比較規則: 如果兩個數字相等 (例如 `1` 和 `1.0`),則同一集合中只能包含其中一個。 目前有兩種內生集合類型: 集合此類對象表示可變集合。它們可通過內置的 [`set()`](../library/stdtypes.xhtml#set "set") 構造器創建,并且創建之后可以通過方法進行修改,例如 `add()`。 凍結集合此類對象表示不可變集合。它們可通過內置的 [`frozenset()`](../library/stdtypes.xhtml#frozenset "frozenset") 構造器創建。由于 frozenset 對象不可變且 [hashable](../glossary.xhtml#term-hashable),它可以被用作另一個集合的元素或是字典的鍵。 映射此類對象表示由任意索引集合所索引的對象的集合。通過下標 `a[k]` 可在映射 `a` 中選擇索引為 `k` 的條目;這可以在表達式中使用,也可作為賦值或 [`del`](simple_stmts.xhtml#del) 語句的目標。內置函數 [`len()`](../library/functions.xhtml#len "len") 可返回一個映射中的條目數。 目前只有一種內生映射類型: 字典此類對象表示由幾乎任意值作為索引的有限個對象的集合。不可作為鍵的值類型只有包含列表或字典或其他可變類型,通過值而非對象編號進行比較的值,其原因在于高效的字典實現需要使用鍵的哈希值以保持一致性。用作鍵的數字類型遵循正常的數字比較規則: 如果兩個數字相等 (例如 `1` 和 `1.0`) 則它們均可來用來索引同一個字典條目。 字典是可變的;它們可通過 `{...}` 標注來創建 (參見 [字典顯示](expressions.xhtml#dict) 小節)。 擴展模塊 [`dbm.ndbm`](../library/dbm.xhtml#module-dbm.ndbm "dbm.ndbm: The standard "database" interface, based on ndbm. (Unix)") 和 [`dbm.gnu`](../library/dbm.xhtml#module-dbm.gnu "dbm.gnu: GNU's reinterpretation of dbm. (Unix)") 提供了額外的映射類型示例,[`collections`](../library/collections.xhtml#module-collections "collections: Container datatypes") 模塊也是如此。 可調用類型此類型可以被應用于函數調用操作 (參見 [調用](expressions.xhtml#calls) 小節): 用戶定義函數用戶定義函數對象可通過函數定義來創建 (參見 [函數定義](compound_stmts.xhtml#function) 小節)。它被調用時應附帶一個參數列表,其中包含的條目應與函數所定義的形參列表一致。 特殊屬性: 屬性 意義 `__doc__` 該函數的文檔字符串,沒有則為 `None`;不會被子類繼承。 可寫 [`__name__`](../library/stdtypes.xhtml#definition.__name__ "definition.__name__") 該函數的名稱。 可寫 [`__qualname__`](../library/stdtypes.xhtml#definition.__qualname__ "definition.__qualname__") 該函數的 [qualified name](../glossary.xhtml#term-qualified-name)。 3\.3 新版功能. 可寫 `__module__` 該函數所屬模塊的名稱,沒有則為 `None`。 可寫 `__defaults__` 由具有默認值的參數的默認參數值組成的元組,如無任何參數具有默認值則為 `None`。 可寫 `__code__` 表示編譯后的函數體的代碼對象。 可寫 `__globals__` 對存放該函數中全局變量的字典的引用 --- 函數所屬模塊的全局命名空間。 只讀 [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 命名空間支持的函數屬性。 可寫 `__closure__` `None` 或包含該函數可用變量的綁定的單元的元組。有關 `cell_contents` 屬性的詳情見下。 只讀 `__annotations__` 包含參數標注的字典。字典的鍵是參數名,如存在返回標注則為 `'return'`。 可寫 `__kwdefaults__` 僅包含關鍵字參數默認值的字典。 可寫 大部分標有 "Writable" 的屬性均會檢查賦值的類型。 函數對象也支持獲取和設置任意屬性,例如這可以被用來給函數附加元數據。使用正規的屬性點號標注獲取和設置此類屬性。*注意當前實現僅支持用戶定義函數屬性。未來可能會增加支持內置函數屬性。* 單元對象具有 `cell_contents` 屬性。這可被用來獲取以及設置單元的值。 有關函數定義的額外信息可以從其代碼對象中提取;參見下文對內部類型的描述。 實例方法實例方法用于結合類、類實例和任何可調用對象 (通常為用戶定義函數)。 特殊的只讀屬性: `__self__` 為類實例對象本身,`__func__` 為函數對象;`__doc__` 為方法的文檔 (與 `__func__.__doc__` 作用相同);[`__name__`](../library/stdtypes.xhtml#definition.__name__ "definition.__name__") 為方法名稱 (與 `__func__.__name__` 作用相同);`__module__` 為方法所屬模塊的名稱,沒有則為 `None`。 方法還支持獲取 (但不能設置) 下層函數對象的任意函數屬性。 用戶定義方法對象可在獲取一個類的屬性時被創建 (也可能通過該類的一個實例),如果該屬性為用戶定義函數對象或類方法對象。 當通過從類實例獲取一個用戶定義函數對象的方式創建一個實例方法對象時,類實例對象的 `__self__` 屬性即為該實例,并會綁定方法對象。該新建方法的 `__func__` 屬性就是原來的函數對象。 當通過從類或實例獲取另一個方法對象的方式創建一個用戶定義方法對象時,其行為將等同于一個函數對象,例外的只有新實例的 `__func__` 屬性將不是原來的方法對象,而是其 `__func__` 屬性。 當通過從類或實例獲取一個類方法對象的方式創建一個實例對象時,實例對象的 `__self__` 屬性為該類本身,其 `__func__` 屬性為類方法對應的下層函數對象。 當一個實例方法對象被調用時,會調用對應的下層函數 (`__func__`),并將類實例 (`__self__`) 插入參數列表的開頭。例如,當 `C` 是一個包含了 `f()` 函數定義的類,而 `x` 是 `C` 的一個實例,則調用 `x.f(1)` 就等同于調用 `C.f(x, 1)`。 當一個實例方法對象是衍生自一個類方法對象時,保存在 `__self__` 中的 "類實例" 實際上會是該類本身,因此無論是調用 `x.f(1)` 還是 `C.f(1)` 都等同于調用 `f(C,1)`,其中 `f` 為對應的下層函數。 請注意從函數對象到實例方法對象的變換會在每一次從實例獲取屬性時發生。在某些情況下,一種高效的優化方式是將屬性賦值給一個本地變量并調用該本地變量。還要注意這樣的變換只發生于用戶定義函數;其他可調用對象 (以及所有不可調用對象) 在被獲取時都不會發生變換。還有一個需要關注的要點是作為一個類實例屬性的用戶定義函數不會被轉換為綁定方法;這樣的變換 *僅當* 函數是類屬性時才會發生。 生成器函數一個使用 [`yield`](simple_stmts.xhtml#yield) 語句 (見 [yield 語句](simple_stmts.xhtml#yield) 章節)的函數或方法被稱作一個 *生成器函數*。利益個函數,當調用時,總是返回一個可以執行函數體的迭代器對象:調用該迭代器的 [`iterator.__next__()`](../library/stdtypes.xhtml#iterator.__next__ "iterator.__next__") 方法將會導致這個函數一直運行直到它使用 `yield` 語句提供了一個值為止。當這個函數執行 [`return`](simple_stmts.xhtml#return) 語句或者最后停止, 一個 [`StopIteration`](../library/exceptions.xhtml#StopIteration "StopIteration") 異常被拋出并且這個迭代器將會到達將被返回的值的集合的末尾。 協程函數使用 [`async def`](compound_stmts.xhtml#async-def) 來定義的函數或方法就被稱為 *協程函數*。這樣的函數在被調用時會返回一個 [coroutine](../glossary.xhtml#term-coroutine) 對象。它可能包含 [`await`](expressions.xhtml#await) 表達式以及 [`async with`](compound_stmts.xhtml#async-with) 和 [`async for`](compound_stmts.xhtml#async-for) 語句。詳情可參見 [協程對象](#coroutine-objects) 一節。 異步生成器函數使用 [`async def`](compound_stmts.xhtml#async-def) 來定義并包含 [`yield`](simple_stmts.xhtml#yield) 語句的函數或方法就被稱為 *異步生成器函數*。這樣的函數在被調用時會返回一個異步迭代器對象,該對象可在 [`async for`](compound_stmts.xhtml#async-for) 語句中用來執行函數體。 調用異步迭代器的 `aiterator.__anext__()` 方法將會返回一個 [awaitable](../glossary.xhtml#term-awaitable),此對象會在被等待時執行直到使用 [`yield`](simple_stmts.xhtml#yield) 表達式輸出一個值。當函數執行時到空的 [`return`](simple_stmts.xhtml#return) 語句或是最后一條語句時,將會引發 [`StopAsyncIteration`](../library/exceptions.xhtml#StopAsyncIteration "StopAsyncIteration") 異常,異步迭代器也會到達要輸出的值集合的末尾。 內置函數內置函數對象是對于 C 函數的外部封裝。內置函數的例子包括 [`len()`](../library/functions.xhtml#len "len") 和 [`math.sin()`](../library/math.xhtml#math.sin "math.sin") ([`math`](../library/math.xhtml#module-math "math: Mathematical functions (sin() etc.).") 是一個標準內置模塊)。內置函數參數的數量和類型由 C 函數決定。特殊的只讀屬性: `__doc__` 是函數的文檔字符串,如果沒有則為 `None`; [`__name__`](../library/stdtypes.xhtml#definition.__name__ "definition.__name__") 是函數的名稱; `__self__` 設定為 `None` (參見下一條目); `__module__` 是函數所屬模塊的名稱,如果沒有則為 `None`。 內置方法此類型實際上是內置函數的另一種形式,只不過還包含了一個傳入 C 函數的對象作為隱式的額外參數。內置方法的一個例子是 `alist.append()`,其中 *alist* 為一個列表對象。在此示例中,特殊的只讀屬性 `__self__` 會被設為 *alist* 所標記的對象。 類類是可調用的。此種對象通常是作為“工廠”來創建自身的實例,類也可以有重載 [`__new__()`](#object.__new__ "object.__new__") 的變體類型。調用的參數會傳給 [`__new__()`](#object.__new__ "object.__new__"),而且通常也會傳給 [`__init__()`](#object.__init__ "object.__init__") 來初始化新的實例。 類實例任意類的實例通過在所屬類中定義 [`__call__()`](#object.__call__ "object.__call__") 方法即能成為可調用的對象。 模塊模塊是 Python 代碼的基本組織單元,由 [導入系統](import.xhtml#importsystem) 創建,由 [`import`](simple_stmts.xhtml#import) 語句發起調用,或者通過 [`importlib.import_module()`](../library/importlib.xhtml#importlib.import_module "importlib.import_module") 和內置的 [`__import__()`](../library/functions.xhtml#__import__ "__import__") 等函數發起調用。 模塊對象具有由字典對象實現的命名空間(這是被模塊中定義的函數的 `__globals__` 屬性引用的字典)。 屬性引用被轉換為該字典中的查找,例如 `m.x` 相當于 `m.__dict__["x"]`。 模塊對象不包含用于初始化模塊的代碼對象(因為初始化完成后不需要它)。 屬性賦值會更新模塊的命名空間字典,例如 `m.x = 1` 等同于 `m.__dict__["x"] = 1`。 預定義的 (可寫) 屬性: [`__name__`](import.xhtml#__name__ "__name__") 為模塊的名稱; `__doc__` 為模塊的文檔字符串,如果沒有則為 `None`; `__annotations__` (可選) 為一個包含 [變量標注](../glossary.xhtml#term-variable-annotation) 的字典,它是在模塊體執行時獲取的; [`__file__`](import.xhtml#__file__ "__file__") 是模塊對應的被加載文件的路徑名,如果它是加載自一個文件的話。某些類型的模塊可能沒有 [`__file__`](import.xhtml#__file__ "__file__") 屬性,例如 C 模塊是靜態鏈接到解釋器內部的; 對于從一個共享庫動態加載的擴展模塊來說該屬性為該共享庫文件的路徑名。 特殊的只讀屬性: [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 為以字典對象表示的模塊命名空間。 **CPython implementation detail:** 由于 CPython 清理模塊字典的設定,當模塊離開作用域時模塊字典將會被清理,即使該字典還有活動的引用。想避免此問題,可復制該字典或保持模塊狀態以直接使用其字典。 自定義類自定義類這種類型一般通過類定義來創建 (參見 [類定義](compound_stmts.xhtml#class) 一節)。每個類都有通過一個字典對象實現的獨立命名空間。類屬性引用會被轉化為在此字典中查找,例如 `C.x` 會被轉化為 `C.__dict__["x"]` (不過也存在一些鉤子對象以允許其他定位屬性的方式)。當未在其中發現某個屬性名稱時,會繼續在基類中查找。這種基類查找使用 C3 方法解析順序,即使存在 '鉆石形' 繼承結構即有多條繼承路徑連到一個共同祖先也能保持正確的行為。有關 Python 使用的 C3 MRO 的詳情可查看配合 2.3 版發布的文檔 <https://www.python.org/download/releases/2.3/mro/>. 當一個類屬性引用 (假設類名為 `C`) 會產生一個類方法對象時,它將轉化為一個 `__self__` 屬性為 `C` 的實例方法對象。當其會產生一個靜態方法對象時,它將轉化為該靜態方法對象所封裝的對象。從類的 [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 所包含內容以外獲取屬性的其他方式請參看 [實現描述器](#descriptors) 一節。 類屬性賦值會更新類的字典,但不會更新基類的字典。 類對象可被調用 (見上文) 以產生一個類實例 (見下文)。 特殊屬性: [`__name__`](../library/stdtypes.xhtml#definition.__name__ "definition.__name__") 為類的名稱; `__module__` 為類所在模塊的名稱; [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 為包含類命名空間的字典; [`__bases__`](../library/stdtypes.xhtml#class.__bases__ "class.__bases__") 為包含基類的元組,按其在基類列表中的出現順序排列; `__doc__` 為類的文檔字符串,如果沒有則為 `None`; `__annotations__` (可選) 為一個包含 [變量標注](../glossary.xhtml#term-variable-annotation) 的字典,它是在類體執行時獲取的。 類實例類實例可通過調用類對象來創建 (見上文)。每個類實例都有通過一個字典對象實現的獨立命名空間,屬性引用會首先在此字典中查找。當未在其中發現某個屬性,而實例對應的類中有該屬性時,會繼續在類屬性中查找。如果找到的類屬性為一個用戶定義函數對象,它會被轉化為實例方法對象,其 `__self__` 屬性即該實例。靜態方法和類方法對象也會被轉化;參見上文 "Classes" 一節。要了解其他通過類實例來獲取相應類屬性的方式可參見 [實現描述器](#descriptors) 一節,這樣得到的屬性可能與實際存放于類的 [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 中的對象不同。如果未找到類屬性,而對象對應的類具有 [`__getattr__()`](#object.__getattr__ "object.__getattr__") 方法,則會調用該方法來滿足查找要求。 屬性賦值和刪除會更新實例的字典,但不會更新對應類的字典。如果類具有 [`__setattr__()`](#object.__setattr__ "object.__setattr__") 或 [`__delattr__()`](#object.__delattr__ "object.__delattr__") 方法,則將調用方法而不再直接更新實例的字典。 如果類實例具有某些特殊名稱的方法,就可以偽裝為數字、序列或映射。參見 [特殊方法名稱](#specialnames) 一節。 特殊屬性: [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 為屬性字典; [`__class__`](../library/stdtypes.xhtml#instance.__class__ "instance.__class__") 為實例對應的類。 I/O 對象 (或稱文件對象)[file object](../glossary.xhtml#term-file-object) 表示一個打開的文件。有多種快捷方式可用來創建文件對象: [`open()`](../library/functions.xhtml#open "open") 內置函數,以及 [`os.popen()`](../library/os.xhtml#os.popen "os.popen"), [`os.fdopen()`](../library/os.xhtml#os.fdopen "os.fdopen") 和 socket 對象的 [`makefile()`](../library/socket.xhtml#socket.socket.makefile "socket.socket.makefile") 方法 (還可能使用某些擴展模塊所提供的其他函數或方法)。 `sys.stdin`, `sys.stdout` 和 `sys.stderr` 會初始化為對應于解釋器標準輸入、輸出和錯誤流的文件對象;它們都會以文本模式打開,因此都遵循 [`io.TextIOBase`](../library/io.xhtml#io.TextIOBase "io.TextIOBase") 抽象類所定義的接口。 內部類型某些由解釋器內部使用的類型也被暴露給用戶。它們的定義可能隨未來解釋器版本的更新而變化,為內容完整起見在此處一并介紹。 代碼對象代碼對象表示 *編譯為字節的* 可執行 Python 代碼,或稱 [bytecode](../glossary.xhtml#term-bytecode)。代碼對象和函數對象的區別在于函數對象包含對函數全局對象 (函數所屬的模塊) 的顯式引用,而代碼對象不包含上下文;而且默認參數值會存放于函數對象而不是代碼對象內 (因為它們表示在運行時算出的值)。與函數對象不同,代碼對象不可變,也不包含對可變對象的引用 (不論是直接還是間接)。 特殊的只讀屬性: `co_name` 為函數名稱; `co_argcount` 為位置參數的數量 (包括有默認值的參數); `co_nlocals` 為函數使用的本地變量數量 (包括參數); `co_varnames` 為一個包含本地變量名稱的元組 (以參數名打頭); `co_cellvars` 為一個包含被嵌套函數所引用的本地變量名稱的元組; `co_freevars` 為一個包含自由變量的元組; `co_code` 為一個表示字節碼指令序列的字符串; `co_consts` 為一個包含字節碼所使用的字面值的元組; `co_names` 為一個包含字節碼所使用的名稱的元組; `co_filename` 為被編譯代碼所在的文件名; `co_firstlineno` 為函數首行的行號; `co_lnotab` 為一個以編碼表示的從字節碼偏移量到行號的映射的字符串 (詳情參見解釋器的源碼); `co_stacksize` 為要求的棧大小 (包括本地變量); `co_flags` 為一個以編碼表示的多個解釋器所用標志的整型數。 以下是可用于 `co_flags` 的標志位定義:如果函數使用 `*arguments` 語法來接受任意數量的位置參數,則 `0x04` 位被設置;如果函數使用 `**keywords` 語法來接受任意數量的關鍵字參數,則 `0x08` 位被設置;如果函數是一個生成器,則 `0x20` 位被設置。 未來特性聲明 (`from __future__ import division`) 也使用 `co_flags` 中的標志位來指明代碼對象的編譯是否啟用特定的特性: 如果函數編譯時啟用未來除法特性則設置 `0x2000` 位; 在更早的 Python 版本中則使用 `0x10` 和 `0x1000` 位。 `co_flags` 中的其他位被保留為內部使用。 如果代碼對象表示一個函數,`co_consts` 中的第一項將是函數的文檔字符串,如果未定義則為 `None`。 幀對象幀對象表示執行幀。它們可能出現在回溯對象中 (見下文),還會被傳遞給注冊跟蹤函數。 特殊的只讀屬性: `f_back` 為前一堆棧幀 (指向調用者),如是最底層堆棧幀則為 `None`; `f_code` 為此幀中所執行的代碼對象; `f_locals` 為用于查找本地變量的字典; `f_globals` 則用于查找全局變量; `f_builtins` 用于查找內置 (固有) 名稱; `f_lasti` 給出精確指令 (這是代碼對象的字節碼字符串的一個索引)。 特殊的可寫屬性: `f_trace`,如果不為 `None`,則是在代碼執行期間調用各類事件的函數 (由調試器使用)。通常每個新源碼行會觸發一個事件 - 這可以通過將 `f_trace_lines` 設為 [`False`](../library/constants.xhtml#False "False") 來禁用。 具體的實現 *可能* 會通過將 `f_trace_opcodes` 設為 [`True`](../library/constants.xhtml#True "True") 來允許按操作碼請求事件。請注意如果跟蹤函數引發的異常逃逸到被跟蹤的函數中,這可能會導致未定義的解釋器行為。 `f_lineno` 為幀的當前行號 --- 在這里寫入從一個跟蹤函數內部跳轉的指定行 (僅用于最底層的幀)。調試器可以通過寫入 f\_lineno 實現一個 Jump 命令 (即設置下一語句)。 幀對象支持一個方法: `frame.``clear`()此方法清除該幀持有的全部對本地變量的引用。而且如果該幀屬于一個生成器,生成器會被完成。這有助于打破包含幀對象的循環引用 (例如當捕獲一個異常并保存其回溯在之后使用)。 如果該幀當前正在執行則會引發 [`RuntimeError`](../library/exceptions.xhtml#RuntimeError "RuntimeError")。 3\.4 新版功能. 回溯對象回溯對象表示一個異常的棧跟蹤記錄。當異常發生時會隱式地創建一個回溯對象,也可能通過調用 [`types.TracebackType`](../library/types.xhtml#types.TracebackType "types.TracebackType") 顯式地創建。 對于隱式地創建的回溯對象,當查找異常句柄使得執行棧展開時,會在每個展開層級的當前回溯之前插入一個回溯對象。當進入一個異常句柄時,棧跟蹤將對程序啟用。(參見 [try 語句](compound_stmts.xhtml#try) 一節。) 它可作為 `sys.exc_info()` 所返回的元組的第三項,以及所捕獲異常的 `__traceback__` 屬性被獲取。 當程序不包含可用的句柄時,棧跟蹤會 (以良好的格式) 寫入標準錯誤流;如果解釋器處于交互模式,它也可作為 `sys.last_traceback` 對用戶啟用。 對于顯式創建的回溯對象,則由回溯對象的創建者來決定應該如何鏈接 `tb_next` 屬性來構成完整的棧跟蹤。 特殊的只讀屬性: `tb_frame` 指向當前層級的執行幀; `tb_lineno` 給出發生異常所在的行號; `tb_lasti` 標示具體指令。如果異常發生于沒有匹配的 except 子句或有 finally 子句的 [`try`](compound_stmts.xhtml#try) 語句中,回溯對象中的行號和最后指令可能與相應幀對象中行號不同。 特殊的可寫屬性: `tb_next` 為棧跟蹤中的下一層級 (通往發生異常的幀),如果沒有下一層級則為 `None`。 在 3.7 版更改: 回溯對象現在可以使用 Python 代碼顯式地實例化,現有實例的 `tb_next` 屬性可以被更新。 切片對象切片對象用來表示 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 方法得到的切片。該對象也可使用內置的 [`slice()`](../library/functions.xhtml#slice "slice") 函數來創建。 特殊的只讀屬性: `start` 為下界; `stop` 為上界; `step` 為步長值; 各值如省略則為 `None`。這些屬性可具有任意類型。 切片對象支持一個方法: `slice.``indices`(*self*, *length*)此方法接受一個整型參數 *length* 并計算在切片對象被應用到 *length* 指定長度的條目序列時切片的相關信息應如何描述。其返回值為三個整型數組成的元組;這些數分別為切片的 *start* 和 *stop* 索引號以及 *step* 步長值。索引號缺失或越界則按照正規連續切片的方式處理。 靜態方法對象靜態方法對象提供了一種避免上文所述將函數對象轉換為方法對象的方式。靜態方法對象為對任意其他對象的封裝,通常用來封裝用戶定義方法對象。當從類或類實例獲取一個靜態方法對象時,實際返回的對象是封裝的對象,它不會被進一步轉換。靜態方法對象自身不是可調用的,但它們所封裝的對象通常都是可調用的。靜態方法對象可通過內置的 [`staticmethod()`](../library/functions.xhtml#staticmethod "staticmethod") 構造器來創建。 類方法對象類方法對象和靜態方法一樣是對其他對象的封裝,會改變從類或類實例獲取該對象的方式。類方法對象在此類獲取操作中的行為已在上文 "用戶定義方法" 一節中描述。類方法對象可通過內置的 [`classmethod()`](../library/functions.xhtml#classmethod "classmethod") 構造器來創建。 ## 3.3. 特殊方法名稱 一個類可以通過定義具有特殊名稱的方法來實現由特殊語法所引發的特定操作 (例如算術運算或下標與切片)。這是 Python 實現 *操作符重載* 的方式,允許每個類自行定義基于操作符的特定行為。例如,如果一個類定義了名為 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 的方法,并且 `x` 為該類的一個實例,則 `x[i]` 基本就等同于 `type(x).__getitem__(x, i)`。除非有說明例外情況,在沒有定義適當方法的情況下嘗試執行一種操作將引發一個異常 (通常為 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError") 或 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError"))。 將一個特殊方法設為 `None` 表示對應的操作不可用。例如,如果一個類將 [`__iter__()`](#object.__iter__ "object.__iter__") 設為 `None`,則該類就是不可迭代的,因此對其實例調用 [`iter()`](../library/functions.xhtml#iter "iter") 將引發一個 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError") (而不會回退至 [`__getitem__()`](#object.__getitem__ "object.__getitem__")). [2](#id9) 在實現模擬任何內置類型的類時,很重要的一點是模擬的實現程度對于被模擬對象來說應當是有意義的。例如,提取單個元素的操作對于某些序列來說是適宜的,但提取切片可能就沒有意義。(這種情況的一個實例是 W3C 的文檔對象模型中的 `NodeList` 接口。) ### 3.3.1. 基本定制 `object.``__new__`(*cls*\[, *...*\])調用以創建一個 *cls* 類的新實例。[`__new__()`](#object.__new__ "object.__new__") 是一個靜態方法 (因為是特例所以你不需要顯式地聲明),它會將所請求實例所屬的類作為第一個參數。其余的參數會被傳遞給對象構造器表達式 (對類的調用)。[`__new__()`](#object.__new__ "object.__new__") 的返回值應為新對象實例 (通常是 *cls* 的實例)。 典型的實現會附帶適宜的參數使用 `super().__new__(cls[, ...])`,通過超類的 [`__new__()`](#object.__new__ "object.__new__") 方法來創建一個類的新實例,然后根據需要修改新創建的實例再將其返回。 如果 [`__new__()`](#object.__new__ "object.__new__") 返回一個 *cls* 的實例,則新實例的 [`__init__()`](#object.__init__ "object.__init__") 方法會在之后被執行,例如 `__init__(self[, ...])`,其中 *self* 為新實例,其余的參數與被傳遞給 [`__new__()`](#object.__new__ "object.__new__") 的相同。 如果 [`__new__()`](#object.__new__ "object.__new__") 未返回一個 *cls* 的實例,則新實例的 [`__init__()`](#object.__init__ "object.__init__") 方法就不會被執行。 [`__new__()`](#object.__new__ "object.__new__") 的目的主要是允許不可變類型的子類 (例如 int, str 或 tuple) 定制實例創建過程。它也常會在自定義元類中被重載以便定制類創建過程。 `object.``__init__`(*self*\[, *...*\])在實例 (通過 [`__new__()`](#object.__new__ "object.__new__")) 被創建之后,返回調用者之前調用。其參數與傳遞給類構造器表達式的參數相同。一個基類如果有 [`__init__()`](#object.__init__ "object.__init__") 方法,則其所派生的類如果也有 [`__init__()`](#object.__init__ "object.__init__") 方法,就必須顯式地調用它以確保實例基類部分的正確初始化;例如: `super().__init__([args...])`. 因為對象是由 [`__new__()`](#object.__new__ "object.__new__") 和 [`__init__()`](#object.__init__ "object.__init__") 協作構造完成的 (由 [`__new__()`](#object.__new__ "object.__new__") 創建,并由 [`__init__()`](#object.__init__ "object.__init__") 定制),所以 [`__init__()`](#object.__init__ "object.__init__") 返回的值只能是 `None`,否則會在運行時引發 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError")。 `object.``__del__`(*self*)在實例將被銷毀時調用。這還會調用終結器或析構器 (不適當)。如果一個基類具有 [`__del__()`](#object.__del__ "object.__del__") 方法,則其所派生的類如果也有 [`__del__()`](#object.__del__ "object.__del__") 方法,就必須顯式地調用它以確保實例基類部分的正確清除。 [`__del__()`](#object.__del__ "object.__del__") 方法可以 (但不推薦!) 通過創建一個該實例的新引用來推遲其銷毀。這被稱為對象 *重生*。[`__del__()`](#object.__del__ "object.__del__") 是否會在重生的對象將被銷毀時再次被調用是由具體實現決定的 ;當前的 [CPython](../glossary.xhtml#term-cpython) 實現只會調用一次。 當解釋器退出時不會確保為仍然存在的對象調用 [`__del__()`](#object.__del__ "object.__del__") 方法。 注解 `del x` 并不直接調用 `x.__del__()` --- 前者會將 `x` 的引用計數減一,而后者僅會在 `x` 的引用計數變為零時被調用。 **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](../glossary.xhtml#term-garbage-collection). 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`](../library/gc.xhtml#module-gc "gc: Interface to the cycle-detecting garbage collector.") 模塊的文檔。 警告 由于調用 [`__del__()`](#object.__del__ "object.__del__") 方法時周邊狀況已不確定,在其執行期間發生的異常將被忽略,改為打印一個警告到 `sys.stderr`。特別地: - [`__del__()`](#object.__del__ "object.__del__") 可在任意代碼被執行時啟用,包括來自任意線程的代碼。如果 [`__del__()`](#object.__del__ "object.__del__") 需要接受鎖或啟用其他阻塞資源,可能會發生死鎖,例如該資源已被為執行 [`__del__()`](#object.__del__ "object.__del__") 而中斷的代碼所獲取。 - [`__del__()`](#object.__del__ "object.__del__") 可以在解釋器關閉階段被執行。因此,它需要訪問的全局變量(包含其他模塊)可能已被刪除或設為 `None`。Python 會保證先刪除模塊中名稱以單個下劃線打頭的全局變量再刪除其他全局變量;如果已不存在其他對此類全局變量的引用,這有助于確保導入的模塊在 [`__del__()`](#object.__del__ "object.__del__") 方法被調用時仍然可用。 `object.``__repr__`(*self*)由 [`repr()`](../library/functions.xhtml#repr "repr") 內置函數調用以輸出一個對象的“官方”字符串表示。如果可能,這應類似一個有效的 Python 表達式,能被用來重建具有相同取值的對象(只要有適當的環境)。如果這不可能,則應返回形式如 `<...some useful description...>` 的字符串。返回值必須是一個字符串對象。如果一個類定義了 [`__repr__()`](#object.__repr__ "object.__repr__") 但未定義 [`__str__()`](#object.__str__ "object.__str__"),則在需要該類的實例的“非正式”字符串表示時也會使用 [`__repr__()`](#object.__repr__ "object.__repr__")。 此方法通常被用于調試,因此確保其表示的內容包含豐富信息且無歧義是很重要的。 `object.``__str__`(*self*)通過 [`str(object)`](../library/stdtypes.xhtml#str "str") 以及內置函數 [`format()`](../library/functions.xhtml#format "format") 和 [`print()`](../library/functions.xhtml#print "print") 調用以生成一個對象的“非正式”或格式良好的字符串表示。返回值必須為一個 [字符串](../library/stdtypes.xhtml#textseq) 對象。 此方法與 [`object.__repr__()`](#object.__repr__ "object.__repr__") 的不同點在于 [`__str__()`](#object.__str__ "object.__str__") 并不預期返回一個有效的 Python 表達式:可以使用更方便或更準確的描述信息。 內置類型 [`object`](../library/functions.xhtml#object "object") 所定義的默認實現會調用 [`object.__repr__()`](#object.__repr__ "object.__repr__")。 `object.``__bytes__`(*self*)通過 [bytes](../library/functions.xhtml#func-bytes) 調用以生成一個對象的字節串表示。這應該返回一個 [`bytes`](../library/stdtypes.xhtml#bytes "bytes") 對象。 `object.``__format__`(*self*, *format\_spec*)通過 [`format()`](../library/functions.xhtml#format "format") 內置函數、擴展、[格式化字符串字面值](lexical_analysis.xhtml#f-strings) 的求值以及 [`str.format()`](../library/stdtypes.xhtml#str.format "str.format") 方法調用以生成一個對象的“格式化”字符串表示。 *format\_spec* 參數為包含所需格式選項描述的字符串。 *format\_spec* 參數的解讀是由實現 [`__format__()`](#object.__format__ "object.__format__") 的類型決定的,不過大多數類或是將格式化委托給某個內置類型,或是使用相似的格式化選項語法。 請參看 [Format Specification Mini-Language](../library/string.xhtml#formatspec) 了解標準格式化語法的描述。 返回值必須為一個字符串對象。 在 3.4 版更改: `object` 本身的 \_\_format\_\_ 方法如果被傳入任何非空字符,將會引發一個 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError")。 在 3.7 版更改: `object.__format__(x, '')` 現在等同于 `str(x)` 而不再是 `format(str(self), '')`。 `object.``__lt__`(*self*, *other*)`object.``__le__`(*self*, *other*)`object.``__eq__`(*self*, *other*)`object.``__ne__`(*self*, *other*)`object.``__gt__`(*self*, *other*)`object.``__ge__`(*self*, *other*)以上這些被稱為“富比較”方法。運算符號與方法名稱的對應關系如下:`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)`。 如果指定的參數對沒有相應的實現,富比較方法可能會返回單例對象 `NotImplemented`。按照慣例,成功的比較會返回 `False` 或 `True`。不過實際上這些方法可以返回任意值,因此如果比較運算符是要用于布爾值判斷(例如作為 `if` 語句的條件),Python 會對返回值調用 [`bool()`](../library/functions.xhtml#bool "bool") 以確定結果為真還是假。 在默認情況下 [`__ne__()`](#object.__ne__ "object.__ne__") 會委托給 [`__eq__()`](#object.__eq__ "object.__eq__") 并將結果取反,除非結果為 `NotImplemented`。比較運算符之間沒有其他隱含關系,例如 `(x<y or x==y)` 為真并不意味著 `x<=y`。要根據單根運算自動生成排序操作,請參看 [`functools.total_ordering()`](../library/functools.xhtml#functools.total_ordering "functools.total_ordering")。 請查看 [`__hash__()`](#object.__hash__ "object.__hash__") 的相關段落,了解創建可支持自定義比較運算并可用作字典鍵的 [hashable](../glossary.xhtml#term-hashable) 對象時要注意的一些事項。 這些方法并沒有對調參數版本(在左邊參數不支持該操作但右邊參數支持時使用);而是 [`__lt__()`](#object.__lt__ "object.__lt__") 和 [`__gt__()`](#object.__gt__ "object.__gt__") 互為對方的反射, [`__le__()`](#object.__le__ "object.__le__") 和 [`__ge__()`](#object.__ge__ "object.__ge__") 互為對方的反射,而 [`__eq__()`](#object.__eq__ "object.__eq__") 和 [`__ne__()`](#object.__ne__ "object.__ne__") 則是它們自己的反射。如果兩個操作數的類型不同,且右操作數類型是左操作數類型的直接或間接子類,則優先選擇右操作數的反射方法,否則優先選擇左操作數的方法。虛擬子類不會被考慮。 `object.``__hash__`(*self*)通過內置函數 [`hash()`](../library/functions.xhtml#hash "hash") 調用以對哈希集的成員進行操作,屬于哈希集的類型包括 [`set`](../library/stdtypes.xhtml#set "set")、[`frozenset`](../library/stdtypes.xhtml#frozenset "frozenset") 以及 [`dict`](../library/stdtypes.xhtml#dict "dict")。[`__hash__()`](#object.__hash__ "object.__hash__") 應該返回一個整數。對象比較結果相同所需的唯一特征屬性是其具有相同的哈希值;建議的做法是把參與比較的對象全部組件的哈希值混在一起,即將它們打包為一個元組并對該元組做哈希運算。例如: ``` def __hash__(self): return hash((self.name, self.nick, self.color)) ``` 注解 [`hash()`](../library/functions.xhtml#hash "hash") 會從一個對象自定義的 [`__hash__()`](#object.__hash__ "object.__hash__") 方法返回值中截斷為 `Py_ssize_t` 的大小。通常對 64 位構建為 8 字節,對 32 位構建為 4 字節。如果一個對象的 [`__hash__()`](#object.__hash__ "object.__hash__") 必須在不同位大小的構建上進行互操作,請確保檢查全部所支持構建的寬度。做到這一點的簡單方法是使用 `python -c "import sys; print(sys.hash_info.width)"`。 如果一個類沒有定義 [`__eq__()`](#object.__eq__ "object.__eq__") 方法,那么也不應該定義 [`__hash__()`](#object.__hash__ "object.__hash__") 操作;如果它定義了 [`__eq__()`](#object.__eq__ "object.__eq__") 但沒有定義 [`__hash__()`](#object.__hash__ "object.__hash__"),則其實例將不可被用作可哈希集的項。如果一個類定義了可變對象并實現了 [`__eq__()`](#object.__eq__ "object.__eq__") 方法,則不應該實現 [`__hash__()`](#object.__hash__ "object.__hash__"),因為可哈希集的實現要求鍵的哈希集是不可變的(如果對象的哈希值發生改變,它將處于錯誤的哈希桶中)。 用戶定義的類默認帶有 [`__eq__()`](#object.__eq__ "object.__eq__") 和 [`__hash__()`](#object.__hash__ "object.__hash__") 方法;使用它們與任何對象(自己除外)比較必定不相等,并且 `x.__hash__()` 會返回一個恰當的值以確保 `x == y` 同時意味著 `x is y` 且 `hash(x) == hash(y)`。 一個類如果重載了 [`__eq__()`](#object.__eq__ "object.__eq__") 且沒有定義 [`__hash__()`](#object.__hash__ "object.__hash__") 則會將其 [`__hash__()`](#object.__hash__ "object.__hash__") 隱式地設為 `None`。當一個類的 [`__hash__()`](#object.__hash__ "object.__hash__") 方法為 `None` 時,該類的實例將在一個程序嘗試獲取其哈希值時正確地引發 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError"),并會在檢測 `isinstance(obj, collections.abc.Hashable)` 時被正確地識別為不可哈希對象。 如果一個重載了 [`__eq__()`](#object.__eq__ "object.__eq__") 的類需要保留來自父類的 [`__hash__()`](#object.__hash__ "object.__hash__") 實現,則必須通過設置 `__hash__ = <ParentClass>.__hash__` 來顯式地告知解釋器。 如果一個沒有重載 [`__eq__()`](#object.__eq__ "object.__eq__") 的類需要去掉哈希支持,則應該在類定義中包含 `__hash__ = None`。一個自定義了 [`__hash__()`](#object.__hash__ "object.__hash__") 以顯式地引發 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError") 的類會被 `isinstance(obj, collections.abc.Hashable)` 調用錯誤地識別為可哈希對象。 注解 在默認情況下,str、bytes 和 datetime 對象的 [`__hash__()`](#object.__hash__ "object.__hash__") 值會使用一個不可預知的隨機值“加鹽”。雖然它們會在一個單獨 Python 進程中保持不變,它們的哈希值在重復運行的 Python 之間是不可預測的。 這種做法是為了防止以下形式的拒絕服務攻擊:通過仔細選擇輸入來利用字典插入操作在最壞情況下的執行效率即 O(n^2) 復雜度。詳情見 <http://www.ocert.org/advisories/ocert-2011-003.html> 改變哈希值會影響集合的迭代次序。Python 也從不保證這個次序不會被改變(通常它在 32 位和 64 位構建上是不一致的)。 另見 [`PYTHONHASHSEED`](../using/cmdline.xhtml#envvar-PYTHONHASHSEED). 在 3.3 版更改: 默認啟用哈希隨機化。 `object.``__bool__`(*self*)調用此方法以實現真值檢測以及內置的 `bool()` 操作;應該返回 `False` 或 `True`。如果未定義此方法,則會查找并調用 [`__len__()`](#object.__len__ "object.__len__") 并在其返回非零值時視對象的邏輯值為真。如果一個類既未定義 [`__len__()`](#object.__len__ "object.__len__") 也未定義 [`__bool__()`](#object.__bool__ "object.__bool__") 則視其所有實例的邏輯值為真。 ### 3.3.2. 自定義屬性訪問 可以定義下列方法來自定義對類實例屬性訪問(`x.name` 的使用、賦值或刪除)的具體含義. `object.``__getattr__`(*self*, *name*)當默認屬性訪問因引發 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError") 而失敗時被調用 (可能是調用 [`__getattribute__()`](#object.__getattribute__ "object.__getattribute__") 時由于 *name* 不是一個實例屬性或 `self` 的類關系樹中的屬性而引發了 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError");或者是對 *name* 特性屬性調用 [`__get__()`](#object.__get__ "object.__get__") 時引發了 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError"))。此方法應當返回(找到的)屬性值或是引發一個 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError") 異常。 請注意如果屬性是通過正常機制找到的,[`__getattr__()`](#object.__getattr__ "object.__getattr__") 就不會被調用。(這是在 [`__getattr__()`](#object.__getattr__ "object.__getattr__") 和 [`__setattr__()`](#object.__setattr__ "object.__setattr__") 之間故意設置的不對稱性。)這既是出于效率理由也是因為不這樣設置的話 [`__getattr__()`](#object.__getattr__ "object.__getattr__") 將無法訪問實例的其他屬性。要注意至少對于實例變量來說,你不必在實例屬性字典中插入任何值(而是通過插入到其他對象)就可以模擬對它的完全控制。請參閱下面的 [`__getattribute__()`](#object.__getattribute__ "object.__getattribute__") 方法了解真正獲取對屬性訪問的完全控制權的辦法。 `object.``__getattribute__`(*self*, *name*)此方法會無條件地被調用以實現對類實例屬性的訪問。如果類還定義了 [`__getattr__()`](#object.__getattr__ "object.__getattr__"),則后者不會被調用,除非 [`__getattribute__()`](#object.__getattribute__ "object.__getattribute__") 顯式地調用它或是引發了 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError")。此方法應當返回(找到的)屬性值或是引發一個 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError") 異常。為了避免此方法中的無限遞歸,其實現應該總是調用具有相同名稱的基類方法來訪問它所需要的任何屬性,例如 `object.__getattribute__(self, name)`。 注解 此方法在作為通過特定語法或內置函數隱式地調用的結果的情況下查找特殊方法時仍可能會被跳過。參見 [特殊方法查找](#special-lookup)。 `object.``__setattr__`(*self*, *name*, *value*)此方法在一個屬性被嘗試賦值時被調用。這個調用會取代正常機制(即將值保存到實例字典)。 *name* 為屬性名稱, *value* 為要賦給屬性的值。 如果 [`__setattr__()`](#object.__setattr__ "object.__setattr__") 想要賦值給一個實例屬性,它應該調用同名的基類方法,例如 `object.__setattr__(self, name, value)`。 `object.``__delattr__`(*self*, *name*)類似于 [`__setattr__()`](#object.__setattr__ "object.__setattr__") 但其作用為刪除而非賦值。此方法應該僅在 `del obj.name` 對于該對象有意義時才被實現。 `object.``__dir__`(*self*)此方法會在對相應對象調用 [`dir()`](../library/functions.xhtml#dir "dir") 時被調用。返回值必須為一個序列。 [`dir()`](../library/functions.xhtml#dir "dir") 會把返回的序列轉換為列表并對其排序。 #### 3.3.2.1. 自定義模塊屬性訪問 特殊名稱 `__getattr__` 和 `__dir__` 還可被用來自定義對模塊屬性的訪問。模塊層級的 `__getattr__` 函數應當接受一個參數,其名稱為一個屬性名,并返回計算結果值或引發一個 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError")。如果通過正常查找即 [`object.__getattribute__()`](#object.__getattribute__ "object.__getattribute__") 未在模塊對象中找到某個屬性,則 `__getattr__` 會在模塊的 `__dict__` 中查找,未找到時會引發一個 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError")。如果找到,它會以屬性名被調用并返回結果值。 `__dir__` 函數應該不接受參數,返回值為一個表示模塊中可訪問名稱的字符串列表。此函數如果存在,將會重載一個模塊中的標準 [`dir()`](../library/functions.xhtml#dir "dir") 查找。 想要更細致地自定義模塊的行為(設置屬性和特性屬性等待),可以將模塊對象的 `__class__` 屬性設置為一個 [`types.ModuleType`](../library/types.xhtml#types.ModuleType "types.ModuleType") 的子類。例如: ``` 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__` 只會影響使用屬性訪問語法進行的查找 -- 直接訪問模塊全局變量(不論是通過模塊內的代碼還是通過對模塊全局字典的引用)是不受影響的。 在 3.5 版更改: `__class__` 模塊屬性改為可寫。 3\.7 新版功能: `__getattr__` 和 `__dir__` 模塊屬性。 參見 [**PEP 562**](https://www.python.org/dev/peps/pep-0562) \[https://www.python.org/dev/peps/pep-0562\] - 模塊 \_\_getattr\_\_ 和 \_\_dir\_\_描述用于模塊的 `__getattr__` 和 `__dir__` 函數。 #### 3.3.2.2. 實現描述器 以下方法僅當一個包含該方法的類(稱為 *描述器* 類)的實例出現于一個 *所有者* 類中的時候才會起作用(該描述器必須在所有者類或其某個上級類的字典中)。在以下示例中,“屬性”指的是名稱為所有者類 [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 中的特征屬性的鍵名的屬性。 `object.``__get__`(*self*, *instance*, *owner*)調用此方法以獲取所有者類的屬性(類屬性訪問)或該類的實例的屬性(實例屬性訪問)。*所有者* 是指所有者類,而 *實例* 是指被用來訪問屬性的實例,如果是 *所有者* 被用來訪問屬性時則為 `None`。此方法應當返回(計算出的)屬性值或是引發一個 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError") 異常。 `object.``__set__`(*self*, *instance*, *value*)調用此方法以設置 *instance* 指定的所有者類的實例的屬性為新值 *value*。 `object.``__delete__`(*self*, *instance*)調用此方法以刪除 *instance* 指定的所有者類的實例的屬性。 `object.``__set_name__`(*self*, *owner*, *name*)在所有者類 *owner* 創建時被調用。描述器會被賦值給 *name*。 3\.6 新版功能. 屬性 `__objclass__` 會被 [`inspect`](../library/inspect.xhtml#module-inspect "inspect: Extract information and source code from live objects.") 模塊解讀為指定此對象定義所在的類(正確設置此屬性有助于動態類屬性的運行時內省)。對于可調用對象來說,它可以指明預期或要求提供一個特定類型(或子類)的實例作為第一個位置參數(例如,CPython 會為實現于 C 中的未綁定方法設置此屬性)。 #### 3.3.2.3. 發起調用描述器 總的說來,描述器就是具有“綁定行為”的對象屬性,其屬性訪問已被描述器協議中的方法所重載,包括 [`__get__()`](#object.__get__ "object.__get__"), [`__set__()`](#object.__set__ "object.__set__") 和 [`__delete__()`](#object.__delete__ "object.__delete__")。如果一個對象定義了以上方法中的任意一個,它就被稱為描述器。 屬性訪問的默認行為是從一個對象的字典中獲取、設置或刪除屬性。例如,`a.x` 的查找順序會從 `a.__dict__['x']` 開始,然后是 `type(a).__dict__['x']`,接下來依次查找 `type(a)` 的上級基類,不包括元類。 但是,如果找到的值是定義了某個描述器方法的對象,則 Python 可能會重載默認行為并轉而發起調用描述器方法。這具體發生在優先級鏈的哪個環節則要根據所定義的描述器方法及其被調用的方式來決定。 描述器發起調用的開始點是一個綁定 `a.x`。參數的組合方式依 `a` 而定: 直接調用最簡單但最不常見的調用方式是用戶代碼直接發起調用一個描述器方法: `x.__get__(a)`。 實例綁定如果綁定到一個對象實例,`a.x` 會被轉換為調用: `type(a).__dict__['x'].__get__(a, type(a))`。 類綁定如果綁定到一個類,`A.x` 會被轉換為調用: `A.__dict__['x'].__get__(None, A)`。 超綁定如果 `a` 是 [`super`](../library/functions.xhtml#super "super") 的一個實例,則綁定 `super(B, obj).m()` 會在 `obj.__class__.__mro__` 中搜索 `B` 的直接上級基類 `A` 然后通過以下調用發起調用描述器: `A.__dict__['m'].__get__(obj, obj.__class__)`。 對于實例綁定,發起描述器調用的優先級取決于定義了哪些描述器方法。一個描述器可以定義 [`__get__()`](#object.__get__ "object.__get__")、[`__set__()`](#object.__set__ "object.__set__") 和 [`__delete__()`](#object.__delete__ "object.__delete__") 的任意組合。如果它沒有定義 [`__get__()`](#object.__get__ "object.__get__"),則訪問屬性會返回描述器對象自身,除非對象的實例字典中有相應屬性值。如果描述器定義了 [`__set__()`](#object.__set__ "object.__set__") 和/或 [`__delete__()`](#object.__delete__ "object.__delete__"),則它是一個數據描述器;如果以上兩個都未定義,則它是一個非數據描述器。通常,數據描述器會同時定義 [`__get__()`](#object.__get__ "object.__get__") 和 [`__set__()`](#object.__set__ "object.__set__"),而非數據描述器只有 [`__get__()`](#object.__get__ "object.__get__") 方法。定義了 [`__set__()`](#object.__set__ "object.__set__") 和 [`__get__()`](#object.__get__ "object.__get__") 的數據描述器總是會重載實例字典中的定義。與之相對的,非數據描述器可被實例所重載。 Python 方法 (包括 [`staticmethod()`](../library/functions.xhtml#staticmethod "staticmethod") 和 [`classmethod()`](../library/functions.xhtml#classmethod "classmethod")) 都是作為非描述器來實現的。因此實例可以重定義并重載方法。這允許單個實例獲得與相同類的其他實例不一樣的行為。 [`property()`](../library/functions.xhtml#property "property") 函數是作為數據描述器來實現的。因此實例不能重載特性屬性的行為。 #### 3.3.2.4. \_\_slots\_\_ *\_\_slots\_\_* 允許我們顯式地聲明數據成員(例如特征屬性)并禁止創建 *\_\_dict\_\_* 和 *\_\_weakref\_\_* (除非是在 *\_\_slots\_\_* 中顯式地聲明或是在父類中可用。) 相比使用 *\_\_dict\_\_* 此方式可以顯著地節省空間。 屬性查找速度也可得到顯著的提升。 `object.``__slots__`這個類變量可賦值為字符串、可迭代對象或由實例使用的變量名構成的字符串序列。 *\_\_slots\_\_* 會為已聲明的變量保留空間,并阻止自動為每個實例創建 *\_\_dict\_\_* 和 *\_\_weakref\_\_*。 ##### 3.3.2.4.1. 使用 *\_\_slots\_\_* 的注意事項 - 當繼承自一個未定義 *\_\_slots\_\_* 的類時,實例的 *\_\_dict\_\_* 和 *\_\_weakref\_\_* 屬性將總是可訪問。 - 沒有 *\_\_dict\_\_* 變量,實例就不能給未在 *\_\_slots\_\_* 定義中列出的新變量賦值。嘗試給一個未列出的變量名賦值將引發 [`AttributeError`](../library/exceptions.xhtml#AttributeError "AttributeError")。新變量需要動態賦值,就要將 `'__dict__'` 加入到 *\_\_slots\_\_* 聲明的字符串序列中。 - 如果未給每個實例設置 *\_\_weakref\_\_* 變量,定義了 *\_\_slots\_\_* 的類就不支持對其實際的弱引用。如果需要弱引用支持,就要將 `'__weakref__'` 加入到 *\_\_slots\_\_* 聲明的字符串序列中。 - *\_\_slots\_\_* 是通過為每個變量名創建描述器 ([實現描述器](#descriptors)) 在類層級上實現的。因此,類屬性不能被用來為通過 *\_\_slots\_\_* 定義的實例變量設置默認值;否則,類屬性就會覆蓋描述器賦值。 - *\_\_slots\_\_* 聲明的作用不只限于定義它的類。在父類中聲明的 *\_\_slots\_\_* 在其子類中同樣可用。不過,子類將會獲得 *\_\_dict\_\_* 和 *\_\_weakref\_\_* 除非它們也定義了 *\_\_slots\_\_* (其中應該僅包含對任何 *額外* 名稱的聲明位置)。 - 如果一個類定義的位置在某個基類中也有定義,則由基類位置定義的實例變量將不可訪問(除非通過直接從基類獲取其描述器的方式)。這會使得程序的含義變成未定義。未來可能會添加一個防止此情況的檢查。 - 非空的 *\_\_slots\_\_* 不適用于派生自“可變長度”內置類型例如 [`int`](../library/functions.xhtml#int "int")、[`bytes`](../library/stdtypes.xhtml#bytes "bytes") 和 [`tuple`](../library/stdtypes.xhtml#tuple "tuple") 的派生類。 - 任何非字符串可迭代對象都可以被賦值給 *\_\_slots\_\_*。映射也可以被使用;不過,未來可能會分別賦給每個鍵具有特殊含義的值。 - *\_\_class\_\_* 賦值僅在兩個類具有相同的 *\_\_slots\_\_* 時才會起作用。 - 帶有多個父類聲明位置的多重繼承也是可用的,但僅允許一個父類具有由聲明位置創建的屬性(其他基類必須具有空的位置布局) —— 違反規則將引發 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError")。 ### 3.3.3. 自定義類創建 當一個類繼承其他類時,那個類的 *\_\_init\_subclass\_\_* 會被調用。這樣就可以編寫能夠改變子類行為的類。這與類裝飾器有緊密的關聯,但是類裝飾器是影響它們所應用的特定類,而 `__init_subclass__` 則只作用于定義了該方法的類所派生的子類。 *classmethod* `object.``__init_subclass__`(*cls*)當所在類派生子類時此方法就會被調用。*cls* 將指向新的子類。如果定義為一個普通實例方法,此方法將被隱式地轉換為類方法。 傳入一個新類的關鍵字參數會被傳給父類的 `__init_subclass__`。為了與其他使用 `__init_subclass__` 的類兼容,應當根據需要去掉部分關鍵字參數再將其余的傳給基類,例如: ``` 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__` 的默認實現什么都不做,只在帶任意參數調用時引發一個錯誤。 注解 元類提示 `metaclass` 將被其它類型機制消耗掉,并不會被傳給 `__init_subclass__` 的實現。實際的元類(而非顯式的提示)可通過 `type(cls)` 訪問。 3\.6 新版功能. #### 3.3.3.1. 元類 默認情況下,類是使用 [`type()`](../library/functions.xhtml#type "type") 來構建的。類體會在一個新的命名空間內執行,類名會被局部綁定到 `type(name, bases, namespace)` 的結果。 類創建過程可通過在定義行傳入 `metaclass` 關鍵字參數,或是通過繼承一個包含此參數的現有類來進行定制。在以下示例中,`MyClass` 和 `MySubclass` 都是 `Meta` 的實例: ``` class Meta(type): pass class MyClass(metaclass=Meta): pass class MySubclass(MyClass): pass ``` 在類定義內指定的任何其他關鍵字參數都會在下面所描述的所有元類操作中進行傳遞。 當一個類定義被執行時,將發生以下步驟: - 解析 MRO 條目; - 確定適當的元類; - 準備類命名空間; - 執行類主體; - 創建類對象。 #### 3.3.3.2. 解析 MRO 條目 如果在類定義中出現的基類不是 [`type`](../library/functions.xhtml#type "type") 的實例,則使用 `__mro_entries__` 方法對其進行搜索,當找到結果時,它會以原始基類元組做參數進行調用。此方法必須返回類的元組以替代此基類被使用。元組可以為空,在此情況下原始基類將被忽略。 參見 [**PEP 560**](https://www.python.org/dev/peps/pep-0560) \[https://www.python.org/dev/peps/pep-0560\] - 對 typing 模塊和泛型類型的核心支持 #### 3.3.3.3. 確定適當的元類 為一個類定義確定適當的元類是根據以下規則: - 如果沒有基類且沒有顯式指定元類,則使用 [`type()`](../library/functions.xhtml#type "type"); - 如果給出一個顯式元類而且 *不是* [`type()`](../library/functions.xhtml#type "type") 的實例,則其會被直接用作元類; - 如果給出一個 [`type()`](../library/functions.xhtml#type "type") 的實例作為顯式元類,或是定義了基類,則使用最近派生的元類。 最近派生的元類會從顯式指定的元類(如果有)以及所有指定的基類的元類(即 `type(cls)`)中選取。最近派生的元類應為 *所有* 這些候選元類的一個子類型。如果沒有一個候選元類符合該條件,則類定義將失敗并拋出 `TypeError`。 #### 3.3.3.4. 準備類命名空間 一旦適當的元類被確定,則類命名空間將會準備好。如果元類具有 `__prepare__` 屬性,它會以 `namespace = metaclass.__prepare__(name, bases, **kwds)` 的形式被調用(其中如果有附加的關鍵字參數,應來自類定義)。 如果元類沒有 `__prepare__` 屬性,則類命名空間將初始化為一個空的有序映射。 參見 [**PEP 3115**](https://www.python.org/dev/peps/pep-3115) \[https://www.python.org/dev/peps/pep-3115\] - Python 3000 中的元類引入 `__prepare__` 命名空間鉤子 #### 3.3.3.5. 執行類主體 類主體會以(類似于) `exec(body, globals(), namespace)` 的形式被執行。普通調用與 [`exec()`](../library/functions.xhtml#exec "exec") 的關鍵區別在于當類定義發生于函數內部時,詞法作用域允許類主體(包括任何方法)引用來自當前和外部作用域的名稱。 但是,即使當類定義發生于函數內部時,在類內部定義的方法仍然無法看到在類作用域層次上定義的名稱。類變量必須通過實例的第一個形參或類方法來訪問,或者是通過下一節中描述的隱式詞法作用域的 `__class__` 引用。 #### 3.3.3.6. 創建類對象 一旦執行類主體完成填充類命名空間,將通過調用 `metaclass(name, bases, namespace, **kwds)` 創建類對象(此處的附加關鍵字參數與傳入 `__prepare__` 的相同)。 如果類主體中有任何方法引用了 `__class__` 或 `super`,這個類對象會通過零參數形式的 [`super()`](../library/functions.xhtml#super "super"). `__class__` 所引用,這是由編譯器所創建的隱式閉包引用。這使用零參數形式的 [`super()`](../library/functions.xhtml#super "super") 能夠正確標識正在基于詞法作用域來定義的類,而被用于進行當前調用的類或實例則是基于傳遞給方法的第一個參數來標識的。 **CPython implementation detail:** 在 CPython 3.6 及之后的版本中,`__class__` 單元會被作為類命名空間中的 `__classcell__` 一項傳遞給元類。如果存在,這必須被向上傳播給 `type.__new__` 調用,以便能正確地初始化該類。如果不這樣做,在 Python 3.6 中將導致 [`DeprecationWarning`](../library/exceptions.xhtml#DeprecationWarning "DeprecationWarning"),而在 Python 3.8 中將引發 [`RuntimeError`](../library/exceptions.xhtml#RuntimeError "RuntimeError")。 當使用默認的元類 [`type`](../library/functions.xhtml#type "type") 或者任何最終會調用 `type.__new__` 的元類時,以下額外的自定義步驟將在創建類對象之后被發起調用: - 首先,`type.__new__` 將收集類命名空間中所有定義了 [`__set_name__()`](#object.__set_name__ "object.__set_name__") 方法的描述器; - 接下來,所有這些 `__set_name__` 方法將使用所定義的類和特定描述器所賦的名稱進行調用; - 最后,將在新類根據方法解析順序所確定的直接父類上調用 [`__init_subclass__()`](#object.__init_subclass__ "object.__init_subclass__") 鉤子。 在類對象創建之后,它會被傳給包含在類定義中的類裝飾器(如果有的話),得到的對象將作為已定義的類綁定到局部命名空間。 當通過 `type.__new__` 創建一個新類時,提供以作為命名空間形參的對象會被復制到一個新的有序映射并丟棄原對象。這個新副本包裝于一個只讀代理中,后者則成為類對象的 [`__dict__`](../library/stdtypes.xhtml#object.__dict__ "object.__dict__") 屬性。 參見 [**PEP 3135**](https://www.python.org/dev/peps/pep-3135) \[https://www.python.org/dev/peps/pep-3135\] - 新的超類型描述隱式的 `__class__` 閉包引用 #### 3.3.3.7. 元類的作用 元類的潛在作用非常廣泛。已經過嘗試的設想包括枚舉、日志、接口檢查、自動委托、自動特征屬性創建、代理、框架以及自動資源鎖定/同步等等。 ### 3.3.4. 自定義實例及子類檢查 以下方法被用來重載 [`isinstance()`](../library/functions.xhtml#isinstance "isinstance") 和 [`issubclass()`](../library/functions.xhtml#issubclass "issubclass") 內置函數的默認行為。 特別地,元類 [`abc.ABCMeta`](../library/abc.xhtml#abc.ABCMeta "abc.ABCMeta") 實現了這些方法以便允許將抽象基類(ABC)作為“虛擬基類”添加到任何類或類型(包括內置類型),包括其他 ABC 之中。 `class.``__instancecheck__`(*self*, *instance*)如果 *instance* 應被視為 *class* 的一個(直接或間接)實例則返回真值。如果定義了此方法,則會被調用以實現 `isinstance(instance, class)`。 `class.``__subclasscheck__`(*self*, *subclass*)Return true 如果 *subclass* 應被視為 *class* 的一個(直接或間接)子類則返回真值。如果定義了此方法,則會被調用以實現 `issubclass(subclass, class)`。 請注意這些方法的查找是基于類的類型(元類)。它們不能作為類方法在實際的類中被定義。這與基于實例被調用的特殊方法的查找是一致的,只有在此情況下實例本身被當作是類。 參見 [**PEP 3119**](https://www.python.org/dev/peps/pep-3119) \[https://www.python.org/dev/peps/pep-3119\] - 引入抽象基類新增功能描述,通過 [`__instancecheck__()`](#class.__instancecheck__ "class.__instancecheck__") 和 [`__subclasscheck__()`](#class.__subclasscheck__ "class.__subclasscheck__") 來定制 [`isinstance()`](../library/functions.xhtml#isinstance "isinstance") 和 [`issubclass()`](../library/functions.xhtml#issubclass "issubclass") 行為,加入此功能的動機是出于向該語言添加抽象基類的內容(參見 [`abc`](../library/abc.xhtml#module-abc "abc: Abstract base classes according to PEP 3119.") 模塊)。 ### 3.3.5. 模擬泛型類型 通過定義一個特殊方法,可以實現由 [**PEP 484**](https://www.python.org/dev/peps/pep-0484) \[https://www.python.org/dev/peps/pep-0484\] 所規定的泛型類語法 (例如 `List[int]`): *classmethod* `object.``__class_getitem__`(*cls*, *key*)按照 *key* 參數指定的類型返回一個表示泛型類的專門化對象。 此方法的查找會基于對象自身,并且當定義于類體內部時,此方法將隱式地成為類方法。請注意,此機制主要是被保留用于靜態類型提示,不鼓勵在其他場合使用。 參見 [**PEP 560**](https://www.python.org/dev/peps/pep-0560) \[https://www.python.org/dev/peps/pep-0560\] - 對 typing 模塊和泛型類型的核心支持 ### 3.3.6. 模擬可調用對象 `object.``__call__`(*self*\[, *args...*\])此方法會在實例作為一個函數被“調用”時被調用;如果定義了此方法,則 `x(arg1, arg2, ...)` 就相當于 `x.__call__(arg1, arg2, ...)` 的快捷方式。 ### 3.3.7. 模擬容器類型 可以定義以下方法來實現容器對象。容器通常屬于序列(如列表或元組)或映射(如字典),但也存在其他形式的容器。前幾個方法集被用于模擬序列或是模擬映射;兩者的不同之處在于序列允許的鍵應為整數 *k* 且 `0 <= k < N` 其中 *N* 是序列或定義指定區間的項的切片對象的長度。此外還建議讓映射提供 `keys()`, `values()`, `items()`, `get()`, `clear()`, `setdefault()`, `pop()`, `popitem()`, `copy()` 以及 `update()` 等方法,它們的行為應與 Python 標準字典對象相應方法類似。此外 [`collections.abc`](../library/collections.abc.xhtml#module-collections.abc "collections.abc: Abstract base classes for containers") 模塊提供了一個 [`MutableMapping`](../library/collections.abc.xhtml#collections.abc.MutableMapping "collections.abc.MutableMapping") 抽象基類,以更方便地根據一個基本集 [`__getitem__()`](#object.__getitem__ "object.__getitem__"), [`__setitem__()`](#object.__setitem__ "object.__setitem__"), [`__delitem__()`](#object.__delitem__ "object.__delitem__") 和 `keys()` 來創建所需方法。可變序列還應該如 Python 標準列表對象那樣提供 `append()`, `count()`, `index()`, `extend()`, `insert()`, `pop()`, `remove()`, `reverse()` 和 `sort()` 等方法。最后,序列類型還應該通過定義下文描述的 [`__add__()`](#object.__add__ "object.__add__"), [`__radd__()`](#object.__radd__ "object.__radd__"), [`__iadd__()`](#object.__iadd__ "object.__iadd__"), [`__mul__()`](#object.__mul__ "object.__mul__"), [`__rmul__()`](#object.__rmul__ "object.__rmul__") 和 [`__imul__()`](#object.__imul__ "object.__imul__") 等方法來實現加法(指拼接)和乘法(指重復);它們不應定義其他數值運算符。此外也建議映射和序列都實現 [`__contains__()`](#object.__contains__ "object.__contains__") 方法以允許高效地使用 `in` 運算符;對于映射,`in` 應該搜索映射的鍵;對于序列,則應該搜索其中的值。此外還建議映射和序列都實現 [`__iter__()`](#object.__iter__ "object.__iter__") 方法以允許高效地對容器中的條目進行迭代;對于映射,[`__iter__()`](#object.__iter__ "object.__iter__") 應與 `keys()` 相同;對于序列,則應該迭代其中的值。 `object.``__len__`(*self*)調用此方法以實現內置函數 [`len()`](../library/functions.xhtml#len "len")。應該返回對象的長度,以一個 `>=` 0 的整數表示。此外,如果一個對象未定義 [`__bool__()`](#object.__bool__ "object.__bool__") 方法而其 [`__len__()`](#object.__len__ "object.__len__") 方法返回值為零,則在布爾運算中會被視為假值。 **CPython implementation detail:** 在 CPython 中,要求長度最大為 [`sys.maxsize`](../library/sys.xhtml#sys.maxsize "sys.maxsize")。如果長度大于 `sys.maxsize` 則某些特性 (例如 [`len()`](../library/functions.xhtml#len "len")) 可能會引發 [`OverflowError`](../library/exceptions.xhtml#OverflowError "OverflowError")。要通過真值檢測來防止引發 `OverflowError`,對象必須定義 [`__bool__()`](#object.__bool__ "object.__bool__") 方法。 `object.``__length_hint__`(*self*)調用此方法以實現 [`operator.length_hint()`](../library/operator.xhtml#operator.length_hint "operator.length_hint")。應該返回對象長度的估計值(可能大于或小于實際長度)。此長度應為一個 `>=` 的整數。此方法純粹是為了優化性能,并不要求正確無誤。 3\.4 新版功能. 注解 切片是通過下述三個專門方法完成的。以下形式的調用 ``` a[1:2] = b ``` 會為轉寫為 ``` a[slice(1, 2, None)] = b ``` 其他形式以此類推。略去的切片項總是以 `None` 補全。 `object.``__getitem__`(*self*, *key*)調用此方法以實現 `self[key]` 的求值。對于序列類型,接受的鍵應為整數和切片對象。請注意負數索引(如果類想要模擬序列類型)的特殊解讀是取決于 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 方法。如果 *key* 的類型不正確則會引發 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError") 異常;如果為序列索引集范圍以外的值(在進行任何負數索引的特殊解讀之后)則應引發 [`IndexError`](../library/exceptions.xhtml#IndexError "IndexError") 異常。對于映射類型,如果 *key* 找不到(不在容器中)則應引發 [`KeyError`](../library/exceptions.xhtml#KeyError "KeyError") 異常。 注解 [`for`](compound_stmts.xhtml#for) 循環在有不合法索引時會期待捕獲 [`IndexError`](../library/exceptions.xhtml#IndexError "IndexError") 以便正確地檢測到序列的結束。 `object.``__setitem__`(*self*, *key*, *value*)調用此方法以實現向 `self[key]` 賦值。注意事項與 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 相同。為對象實現此方法應該僅限于需要映射允許基于鍵修改值或添加鍵,或是序列允許元素被替換時。不正確的 *key* 值所引發的異常應與 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 方法的情況相同。 `object.``__delitem__`(*self*, *key*)調用此方法以實現 `self[key]` 的刪除。注意事項與 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 相同。為對象實現此方法應該權限于需要映射允許移除鍵,或是序列允許移除元素時。不正確的 *key* 值所引發的異常應與 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 方法的情況相同。 `object.``__missing__`(*self*, *key*)此方法由 [`dict`](../library/stdtypes.xhtml#dict "dict").[`__getitem__()`](#object.__getitem__ "object.__getitem__") 在找不到字典中的鍵時調用以實現 dict 子類的 `self[key]`。 `object.``__iter__`(*self*)此方法在需要為容器創建迭代器時被調用。此方法應該返回一個新的迭代器對象,它能夠逐個迭代容器中的所有對象。對于映射,它應該逐個迭代容器中的鍵。 迭代器對象也需要實現此方法;它們需要返回對象自身。有關迭代器對象的詳情請參看 [迭代器類型](../library/stdtypes.xhtml#typeiter) 一節。 `object.``__reversed__`(*self*)此方法(如果存在)會被 [`reversed()`](../library/functions.xhtml#reversed "reversed") 內置函數調用以實現逆向迭代。它應當返回一個新的以逆序逐個迭代容器內所有對象的迭代器對象。 如果未提供 [`__reversed__()`](#object.__reversed__ "object.__reversed__") 方法,則 [`reversed()`](../library/functions.xhtml#reversed "reversed") 內置函數將回退到使用序列協議 ([`__len__()`](#object.__len__ "object.__len__") 和 [`__getitem__()`](#object.__getitem__ "object.__getitem__"))。支持序列協議的對象應當僅在能夠提供比 [`reversed()`](../library/functions.xhtml#reversed "reversed") 所提供的實現更高效的實現時才提供 [`__reversed__()`](#object.__reversed__ "object.__reversed__") 方法。 成員檢測運算符 ([`in`](expressions.xhtml#in) 和 [`not in`](expressions.xhtml#not-in)) 通常以在序列中逐個迭代的方式來實現。不過,容器對象可以提供以下特殊方法并采用更有效率的實現,這樣也不要求對象必須屬于序列。 `object.``__contains__`(*self*, *item*)調用此方法以實現成員檢測運算符。如果 *item* 是 *self* 的成員則應返回真,否則返回假。對于映射類型,此檢測應基于映射的鍵而不是值或者鍵值對。 對于未定義 [`__contains__()`](#object.__contains__ "object.__contains__") 的對象,成員檢測將首先嘗試通過 [`__iter__()`](#object.__iter__ "object.__iter__") 進行迭代,然后再使用 [`__getitem__()`](#object.__getitem__ "object.__getitem__") 的舊式序列迭代協議,參看 [語言參考中的相應部分](expressions.xhtml#membership-test-details)。 ### 3.3.8. 模擬數字類型 定義以下方法即可模擬數字類型。特定種類的數字不支持的運算(例如非整數不能進行位運算)所對應的方法應當保持未定義狀態。 `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*)調用這些方法來實現二進制算術運算 (`+`, `-`, `*`, `@`, `/`, `//`, `%`, [`divmod()`](../library/functions.xhtml#divmod "divmod"), [`pow()`](../library/functions.xhtml#pow "pow"), `**`, `<<`, `>>`, `&`, `^`, `|`)。例如,求表達式 `x + y` 的值,其中 *x* 是具有 [`__add__()`](#object.__add__ "object.__add__") 方法的類的一個實例,則會調用 `x.__add__(y)`。[`__divmod__()`](#object.__divmod__ "object.__divmod__") 方法應該等價于使用 [`__floordiv__()`](#object.__floordiv__ "object.__floordiv__") 和 [`__mod__()`](#object.__mod__ "object.__mod__"),它不應該被關聯到 [`__truediv__()`](#object.__truediv__ "object.__truediv__")。請注意如果要支持三元版本的內置 [`pow()`](../library/functions.xhtml#pow "pow") 函數,則 [`__pow__()`](#object.__pow__ "object.__pow__") 的定義應該接受可選的第三個參數。 如果這些方法中的某一個不支持與所提供參數進行運算,它應該返回 `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*)`object.``__rlshift__`(*self*, *other*)`object.``__rrshift__`(*self*, *other*)`object.``__rand__`(*self*, *other*)`object.``__rxor__`(*self*, *other*)`object.``__ror__`(*self*, *other*)調用這些方法來實現具有反射(交換)操作數的二進制算術運算 (`+`, `-`, `*`, `@`, `/`, `//`, `%`, [`divmod()`](../library/functions.xhtml#divmod "divmod"), [`pow()`](../library/functions.xhtml#pow "pow"), `**`, `<<`, `>>`, `&`, `^`, `|`)。這些成員函數僅會在左操作數不支持相應運算 [3](#id10) 且兩個操作數類型不同時被調用。[4](#id11) 例如,求表達式 `x - y` 的值,其中 *y* 是具有 [`__rsub__()`](#object.__rsub__ "object.__rsub__") 方法的類的一個實例,則當 `x.__sub__(y)` 返回 *NotImplemented* 時會調用 `y.__rsub__(x)`。 請注意三元版的 [`pow()`](../library/functions.xhtml#pow "pow") 并不會嘗試調用 [`__rpow__()`](#object.__rpow__ "object.__rpow__") (因為強制轉換規則會太過復雜)。 注解 如果右操作數類型為左操作數類型的一個子類,且該子類提供了指定運算的反射方法,則此方法會先于左操作數的非反射方法被調用。此行為可允許子類重載其祖先類的運算符。 `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*)調用這些方法來實現擴展算術賦值 (`+=`, `-=`, `*=`, `@=`, `/=`, `//=`, `%=`, `**=`, `<<=`, `>>=`, `&=`, `^=`, `|=`)。這些方法應該嘗試進行自身操作 (修改 *self*) 并返回結果 (結果應該但并非必須為 *self*)。如果某個方法未被定義,相應的擴展算術賦值將回退到普通方法。例如,如果 *x* 是具有 [`__iadd__()`](#object.__iadd__ "object.__iadd__") 方法的類的一個實例,則 `x += y` 就等價于 `x = x.__iadd__(y)`。否則就如 `x + y` 的求值一樣選擇 `x.__add__(y)` 和 `y.__radd__(x)`。在某些情況下,擴展賦值可導致未預期的錯誤 (參見 [Why does a\_tuple\[i\] += \['item'\] raise an exception when the addition works?](../faq/programming.xhtml#faq-augmented-assignment-tuple-error)),但此行為實際上是數據模型的一個組成部分。 `object.``__neg__`(*self*)`object.``__pos__`(*self*)`object.``__abs__`(*self*)`object.``__invert__`(*self*)調用此方法以實現一元算術運算 (`-`, `+`, [`abs()`](../library/functions.xhtml#abs "abs") 和 `~`)。 `object.``__complex__`(*self*)`object.``__int__`(*self*)`object.``__float__`(*self*)調用這些方法以實現內置函數 [`complex()`](../library/functions.xhtml#complex "complex"), [`int()`](../library/functions.xhtml#int "int") 和 [`float()`](../library/functions.xhtml#float "float")。應當返回一個相應類型的值。 `object.``__index__`(*self*)調用此方法以實現 [`operator.index()`](../library/operator.xhtml#operator.index "operator.index") 以及 Python 需要無損地將數字對象轉換為整數對象的場合(例如切片或是內置的 [`bin()`](../library/functions.xhtml#bin "bin"), [`hex()`](../library/functions.xhtml#hex "hex") 和 [`oct()`](../library/functions.xhtml#oct "oct") 函數)。 存在此方法表明數字對象屬于整數類型。 必須返回一個整數。 注解 為了具有一致的整數類型類,當定義了 [`__index__()`](#object.__index__ "object.__index__") 的時候也應當定義 [`__int__()`](#object.__int__ "object.__int__"),兩者應當返回相同的值。 `object.``__round__`(*self*\[, *ndigits*\])`object.``__trunc__`(*self*)`object.``__floor__`(*self*)`object.``__ceil__`(*self*)調用這些方法以實現內置函數 [`round()`](../library/functions.xhtml#round "round") 以及 [`math`](../library/math.xhtml#module-math "math: Mathematical functions (sin() etc.).") 函數 [`trunc()`](../library/math.xhtml#math.trunc "math.trunc"), [`floor()`](../library/math.xhtml#math.floor "math.floor") 和 [`ceil()`](../library/math.xhtml#math.ceil "math.ceil")。 除了將 *ndigits* 傳給 `__round__()` 的情況之外這些方法的返回值都應當是原對象截斷為 [`Integral`](../library/numbers.xhtml#numbers.Integral "numbers.Integral") (通常為 [`int`](../library/functions.xhtml#int "int"))。 如果未定義 [`__int__()`](#object.__int__ "object.__int__") 則內置函數 [`int()`](../library/functions.xhtml#int "int") 會回退到 [`__trunc__()`](#object.__trunc__ "object.__trunc__")。 ### 3.3.9. with 語句上下文管理器 *上下文管理器* 是一個對象,它定義了在執行 [`with`](compound_stmts.xhtml#with) 語句時要建立的運行時上下文。 上下文管理器處理進入和退出所需運行時上下文以執行代碼塊。 通常使用 `with` 語句(在 [with 語句](compound_stmts.xhtml#with) 中描述),但是也可以通過直接調用它們的方法來使用。 上下文管理器的典型用法包括保存和恢復各種全局狀態,鎖定和解鎖資源,關閉打開的文件等等。 要了解上下文管理器的更多信息,請參閱 [上下文管理器類型](../library/stdtypes.xhtml#typecontextmanager)。 `object.``__enter__`(*self*)進入與此對象相關的運行時上下文。 [`with`](compound_stmts.xhtml#with) 語句將會綁定這個方法的返回值到 `as` 子句中指定的目標,如果有的話。 `object.``__exit__`(*self*, *exc\_type*, *exc\_value*, *traceback*)退出關聯到此對象的運行時上下文。 各個參數描述了導致上下文退出的異常。 如果上下文是無異常地退出的,三個參數都將為 [`None`](../library/constants.xhtml#None "None")。 如果提供了異常,并且希望方法屏蔽此異常(即避免其被傳播),則應當返回真值。 否則的話,異常將在退出此方法時按正常流程處理。 請注意 [`__exit__()`](#object.__exit__ "object.__exit__") 方法不應該重新引發被傳入的異常,這是調用者的責任。 參見 [**PEP 343**](https://www.python.org/dev/peps/pep-0343) \[https://www.python.org/dev/peps/pep-0343\] - "with" 語句Python [`with`](compound_stmts.xhtml#with) 語句的規范描述、背景和示例。 ### 3.3.10. 特殊方法查找 對于自定義類來說,特殊方法的隱式發起調用僅保證在其定義于對象類型中時能正確地發揮作用,而不能定義在對象實例字典中。 該行為就是以下代碼會引發異常的原因。: ``` >>> 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() ``` 此行為背后的原理在于包括類型對象在內的所有對象都會實現的幾個特殊方法,例如 [`__hash__()`](#object.__hash__ "object.__hash__") 和 [`__repr__()`](#object.__repr__ "object.__repr__")。 如果這些方法的隱式查找使用了傳統的查找過程,它們會在對類型對象本身發起調用時失敗: ``` >>> 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 ``` 以這種方式不正確地嘗試發起調用一個類的未綁定方法有時被稱為‘元類混淆’,可以通過在查找特殊方法時繞過實例的方式來避免: ``` >>> type(1).__hash__(1) == hash(1) True >>> type(int).__hash__(int) == hash(int) True ``` 除了為了正確性而繞過任何實例屬性之外,隱式特殊方法查找通常也會繞過 [`__getattribute__()`](#object.__getattribute__ "object.__getattribute__") 方法,甚至包括對象的元類: ``` >>> 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 ``` 以這種方式繞過 [`__getattribute__()`](#object.__getattribute__ "object.__getattribute__") 機制為解析器內部的速度優化提供了顯著的空間,其代價則是犧牲了處理特殊方法時的一些靈活性(特殊方法 *必須* 設置在類對象本身上以便始終一致地由解釋器發起調用)。 ## 3.4. 協程 ### 3.4.1. 可等待對象 [awaitable](../glossary.xhtml#term-awaitable) 對象主要實現了 [`__await__()`](#object.__await__ "object.__await__") 方法。 從 [`async def`](compound_stmts.xhtml#async-def) 函數返回的 [Coroutine](../glossary.xhtml#term-coroutine) 對象即屬于可等待對象。 注解 從帶有 [`types.coroutine()`](../library/types.xhtml#types.coroutine "types.coroutine") 或 [`asyncio.coroutine()`](../library/asyncio-task.xhtml#asyncio.coroutine "asyncio.coroutine") 裝飾器的生成器返回的 [generator iterator](../glossary.xhtml#term-generator-iterator) 對象也屬于可等待對象,但它們并未實現 [`__await__()`](#object.__await__ "object.__await__")。 `object.``__await__`(*self*)必須返回一個 [iterator](../glossary.xhtml#term-iterator)。 應當被用來實現 [awaitable](../glossary.xhtml#term-awaitable) 對象。 例如,[`asyncio.Future`](../library/asyncio-future.xhtml#asyncio.Future "asyncio.Future") 實現了此方法以與 [`await`](expressions.xhtml#await) 表達式相兼容。 3\.5 新版功能. 參見 [**PEP 492**](https://www.python.org/dev/peps/pep-0492) \[https://www.python.org/dev/peps/pep-0492\] 了解有關可等待對象的詳細信息。 ### 3.4.2. 協程對象 [Coroutine](../glossary.xhtml#term-coroutine) 對象屬于 [awaitable](../glossary.xhtml#term-awaitable) 對象。 協程的執行可通過調用 [`__await__()`](#object.__await__ "object.__await__") 并迭代其結果來進行控制。 當協程結束執行并返回時,迭代器會引發 [`StopIteration`](../library/exceptions.xhtml#StopIteration "StopIteration"),該異常的 `value` 屬性將指向返回值。 如果協程引發了異常,它會被迭代器所傳播。 協程不應該直接引發未處理的 [`StopIteration`](../library/exceptions.xhtml#StopIteration "StopIteration") 異常。 協程也具有下面列出的方法,它們類似于生成器的對應方法 (參見 [生成器-迭代器的方法](expressions.xhtml#generator-methods))。 但是,與生成器不同,協程并不直接支持迭代。 在 3.5.2 版更改: 等待一個協程超過一次將引發 [`RuntimeError`](../library/exceptions.xhtml#RuntimeError "RuntimeError")。 `coroutine.``send`(*value*)開始或恢復協程的執行。 如果 *value* 為 `None`,則這相當于前往 [`__await__()`](#object.__await__ "object.__await__") 所返回迭代器的下一項。 如果 *value* 不為 `None`,此方法將委托給導致協程掛起的迭代器的 [`send()`](expressions.xhtml#generator.send "generator.send") 方法。 其結果(返回值,[`StopIteration`](../library/exceptions.xhtml#StopIteration "StopIteration") 或是其他異常)將與上述對 [`__await__()`](#object.__await__ "object.__await__") 返回值進行迭代的結果相同。 `coroutine.``throw`(*type*\[, *value*\[, *traceback*\]\])在協程內引發指定的異常。 此方法將委托給導致協程掛起的迭代器的 [`throw()`](expressions.xhtml#generator.throw "generator.throw") 方法,如果存在該方法。 否則的話,異常會在掛起點被引發。 其結果(返回值,[`StopIteration`](../library/exceptions.xhtml#StopIteration "StopIteration") 或是其他異常)將與上述對 [`__await__()`](#object.__await__ "object.__await__") 返回值進行迭代的結果相同。 如果異常未在協程內被捕獲,則將回傳給調用者。 `coroutine.``close`()此方法會使得協程清理自身并退出。 如果協程被掛起,此方法會先委托給導致協程掛起的迭代器的 [`close()`](expressions.xhtml#generator.close "generator.close") 方法,如果存在該方法。 然后它會在掛起點引發 [`GeneratorExit`](../library/exceptions.xhtml#GeneratorExit "GeneratorExit"),使得協程立即清理自身。 最后,協程會被標記為已結束執行,即使它根本未被啟動。 當協程對象將要被銷毀時,會使用以上處理過程來自動關閉。 ### 3.4.3. 異步迭代器 *異步迭代器* 可以在其 `__anext__` 方法中調用異步代碼。 異步迭代器可在 [`async for`](compound_stmts.xhtml#async-for) 語句中使用。 `object.``__aiter__`(*self*)必須返回一個 *異步迭代器* 對象。 `object.``__anext__`(*self*)必須返回一個 *可迭代對象* 輸出迭代器的下一結果值。 當迭代結束時應該引發 [`StopAsyncIteration`](../library/exceptions.xhtml#StopAsyncIteration "StopAsyncIteration") 錯誤。 異步可迭代對象的一個示例: ``` 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 版更改: 在 Python 3.7 之前,`__aiter__` 可以返回一個 *可迭代對象* 并解析為 [異步迭代器](../glossary.xhtml#term-asynchronous-iterator)。 從 Python 3.7 開始,`__aiter__` 必須 返回一個異步迭代器對象。 返回任何其他對象都將導致 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError") 錯誤。 ### 3.4.4. 異步上下文管理器 *異步上下文管理器* 是 *上下文管理器* 的一種,它能夠在其 `__aenter__` 和 `__aexit__` 方法中暫停執行。 異步上下文管理器可在 [`async with`](compound_stmts.xhtml#async-with) 語句中使用。 `object.``__aenter__`(*self*)此方法在語義上類似于 [`__enter__()`](#object.__enter__ "object.__enter__"),僅有的區別是它必須返回一個 *可等待對象*。 `object.``__aexit__`(*self*, *exc\_type*, *exc\_value*, *traceback*)此方法在語義上類似于 [`__exit__()`](#object.__exit__ "object.__exit__"),僅有的區別是它必須返回一個 *可等待對象*。 異步上下文管理器類的一個示例: ``` 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](#id1)在某些情況下 *有可能* 基于可控的條件改變一個對象的類型。 但這通常不是個好主意,因為如果處理不當會導致一些非常怪異的行為。 [2](#id2)[`__hash__()`](#object.__hash__ "object.__hash__"), [`__iter__()`](#object.__iter__ "object.__iter__"), [`__reversed__()`](#object.__reversed__ "object.__reversed__") 以及 [`__contains__()`](#object.__contains__ "object.__contains__") 方法對此有特殊處理;其他方法仍會引發 [`TypeError`](../library/exceptions.xhtml#TypeError "TypeError"),但可能依靠 `None` 屬于不可調用對象的行為來做到這一點。 [3](#id5)這里的“不支持”是指該類無此方法,或方法返回 `NotImplemented`。 如果你想強制回退到右操作數的反射方法,請不要設置方法為 `None` — 那會造成顯式地 *阻塞* 此種回退的相反效果。 [4](#id6)對于相同類型的操作數,如果非反射方法 (例如 [`__add__()`](#object.__add__ "object.__add__")) 失敗則會認為相應運算不被支持,這就是反射方法未被調用的原因。 ### 導航 - [索引](../genindex.xhtml "總目錄") - [模塊](../py-modindex.xhtml "Python 模塊索引") | - [下一頁](executionmodel.xhtml "4. 執行模型") | - [上一頁](lexical_analysis.xhtml "2. 詞法分析") | - ![](https://box.kancloud.cn/a721fc7ec672275e257bbbfde49a4d4e_16x16.png) - [Python](https://www.python.org/) ? - zh\_CN 3.7.3 [文檔](../index.xhtml) ? - [Python 語言參考](index.xhtml) ? - $('.inline-search').show(0); | ? [版權所有](../copyright.xhtml) 2001-2019, Python Software Foundation. Python 軟件基金會是一個非盈利組織。 [請捐助。](https://www.python.org/psf/donations/) 最后更新于 5月 21, 2019. [發現了問題](../bugs.xhtml)? 使用[Sphinx](http://sphinx.pocoo.org/)1.8.4 創建。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看