天天看點

Python 進階_OOP 面向對象程式設計_類屬性和方法目錄類屬性類方法

<a href="#%E7%9B%AE%E5%BD%95">目錄</a>

<a href="#%E7%B1%BB%E5%B1%9E%E6%80%A7">類屬性</a>

<a href="#%E8%B0%83%E7%94%A8%E7%B1%BB%E5%B1%9E%E6%80%A7">調用類屬性</a>

<a href="#%E6%9F%A5%E7%9C%8B%E7%B1%BB%E5%B1%9E%E6%80%A7">檢視類屬性</a>

<a href="#%E7%89%B9%E6%AE%8A%E7%9A%84%E7%B1%BB%E5%B1%9E%E6%80%A7">特殊的類屬性</a>

<a href="#%E7%B1%BB%E6%96%B9%E6%B3%95">類方法</a>

<a href="#%E7%9C%9F%E6%9E%84%E9%80%A0%E5%99%A8-new">真構造器 __new__</a>

在了解類屬性之前要先搞清楚 執行個體屬性 和 函數屬性 之間的差別:

1. 執行個體屬性:指的是執行個體化類對象的屬性,需要在類中使用 self 關鍵字來将其和執行個體化對象綁定的屬性。

2. 函數屬性:指的是定義在函數體内的屬性,其可以是執行個體屬性,也可以是類屬性。

3. 類屬性:是一個與執行個體無關的屬性,比起執行個體屬性而言,它更加的 靜态,當定義在類方法中時,并不會因為方法調用的完畢而被回收。類屬性,在類定義中直接指定,無須 self 關鍵字,是以也隻能在類中使用。是以類屬性隻能通過類的成員方法或類調用來更新。

靜态:表示一個對所有執行個體而言都是相對固定的值

NOTE:類屬型也稱之為 靜态屬性,當我們定義一個類靜态屬性時,無須執行個體化對象,直接可以通過類來調用該屬性,直到這個類被回收為止。如果在 Java 中,你需要使用 static 來指定。當然類的執行個體化對象也可以通過句點辨別符來調用和更改,但此時的更改并不會影響原來的類靜态屬性。

EXAMPLE:

通過這個例子可以看出類屬性的調用可以完全無需執行個體化一個類對象。

注意:在類定義的函數體中調用類屬性,需要通過 類名結合句點辨別符 的方式來調用,否則會出發 NameError

Python 為此提供了兩個方法:

通過 dir() 來檢視類屬性

<code>class.__dict__</code> 來檢視類屬性,等效于<code>vars(AClass)</code>

兩者的差別在于:前者僅能檢視類屬性的清單,後者可以檢視類屬性的鍵值對字典。

從上述的例子可以看出類中處理我們定義的 LOG 屬性之外還有很多以雙下劃線 “__” 開頭和結尾的屬性,這些屬性都是 Python 的特殊屬性。

特殊屬性

作用

C.name

類的名字(String)

C.doc

類的文檔(String)

C.bases

子類的父類元組(Tuple)

C.dict

類的屬性字典(Dict)

C.module

類所有的子產品名稱

instance.class

類執行個體對象的類名稱

NOTE:其中 <code>__dict__</code> 是一個包含了類屬性的字典,方 Python 解析器通路一個類屬性時,就會在這個字典中搜尋。如果在該類的字典中沒有搜尋到,那麼就會到該類的父類的屬性字典中搜尋。這樣的話就能夠将不同類之間的屬性名隔離開來,在子類中對屬性字典的修改并不會影響到父類的屬性字典。

類方法就最基本的特征就是需要傳遞一個 class 對象作為方式的實參。

與 <code>__init__()</code> 相比 <code>__new__()</code> 才是真正的構造器,實際上,在 Python 解析器中是先調用了 <code>__new__()</code> 生成一個執行個體,再将該執行個體對象傳入 <code>__init__()</code> 實作初始化操作。但 <code>__new__()</code> 很少需要我們去重載,一般隻有在派生了不可變類型的子類後需要重載,EG. 派生 String/Int/Tuple 等

為什麼說 <code>__new__()</code> 是真·構造器呢?

因為這個特殊的類方法是真的傳回了一個類的執行個體對象,而不像 <code>__init__()</code> 是傳入了一個執行個體化對象。

EXAMPLE:不可表類型的派生

類 RoundFloat 是類 float 的子類,我們通過重載父類的 <code>__new__()</code> 構造器來定制一個新的不可變類型(Python 2.2之後将類和類型統一了,是以可以繼承 Python 的内置資料類型)。當執行個體化 RoundFloat 的對象時,實際上是執行個體化了Python 内置資料類型 Float 的對象,并對這個對象做了一些定制化的操作(round(val, 2))。

NOTE:即便我們也可以通過重載 <code>__init__()</code> 來實作這個結果,但這裡卻不能這麼做。因為如果 <code>__new__()</code> 沒有被重載的話,仍會預設調用父類 Float 的構造器,建立 Float 類型的對象,而不是建立現在的 RoundFloat 類型對象。這也是兩者的本質差別。