面向物件
OOP: The Big Picture
Why Use Classes?
程式就是“用一些東西來做事情”,而類就是一種定義新種類的東西的方式,它反映了在程式領域中的真實物件。
類的三個獨特性質:
Multiple instances (多重例項)
類本質上是生成一個或多個物件的工廠。每次呼叫類時, 都會生成一個具有獨特名稱空間的新物件。從類生成的每個物件都可以訪問類的屬性, 併為每個物件的不同資料獲取其自己的名稱空間。
Customization via inheritance (通過繼承進行定製)
類還支援 OOP 繼承概念;我們可以通過在編碼為子類的新軟體元件中重新定義類本身的屬性來擴充套件類。通常, 類可以建立名稱空間層次結構, 定義由層次結構中的類建立的物件所使用的名稱。這比其他工具更直接支援多個可自定義的行為。
Operator overloading(運算子過載)
通過提供特殊的協議方法, 類可以定義響應我們在內建型別的工作中看到的操作型別的物件。例如, 可以對使用類進行的物件進行切片、串聯、索引等。Python 提供了類可用於攔截和實現任何內建型別操作的掛鉤。
在它的基礎上, OOP 在 Python 中的機制主要只是 two bits of magic: 函式中的特殊第一個引數 (接收呼叫的物件) 和繼承屬性搜尋 (支援通過自定義程式設計)。除了這一點之外, 模型基本上只是最終處理內建型別的函式。雖然不完全是新的, 但 OOP 添加了額外的結構層, 支援比平面程式模型更好的程式設計。
*** OOP is as much an experience as a technology.***
Attribute Inheritance Search (屬性繼承搜尋)
大多數 OOP 均可使用下面的式子來表達:
object.attribute
class
產生類時, 表示式在 Python 中啟動搜尋-它搜尋連線物件的樹, 查詢它可以找到的首次出現的屬性。當涉及類時, 前面的 Python 表示式有效地轉換為自然語言中的以下內容:
- 通過查詢物件, 然後在它上面的所有類中, 從下到上, 從左到右查詢屬性的第一個匹配項。
換言之, 屬性提取只是樹搜尋。由於樹中較低的物件繼承附加到該樹中較高物件的屬性, 因此應用了術語 繼承 。當搜尋從底部向上進行時, 從某種意義上說, 連結到樹中的物件是所有樹父級中定義的所有屬性的聯合, 所有這些特性都達到樹的頂端。
我們用程式碼構建連結物件的樹, 而 Python 在每次使用物件時都會在執行時通過 object.attribute
表示式“爬樹”去搜索屬性。
- Classes
- Serve as instance factories. Their attributes provide behavior—data and functions —that is inherited by all the instances generated from them (e.g., a function to compute an employee’s salary from pay and hours).
- Instances
- Represent the concrete items in a program’s domain. Their attributes record data that varies per specific object (e.g., an employee’s Social Security number).
類物件提供預設的行為
類語句建立類物件併為其分配名稱。與函式 def
語句一樣, Python class
語句是可執行語句。執行時, 它將生成一個新的類物件, 並將其分配給類標頭中的名稱。此外, 與 def
一樣, 類語句通常在第一次匯入它們所編碼的檔案時執行。
class
語句內的賦值建立類屬性 。就像在模組檔案中一樣, 類語句中的頂層賦值 (不巢狀在 def
中) 在類物件中生成屬性。從技術上講, 類語句定義了一個區域性作用域, 它會變成類物件的屬性名稱空間, 就像模組的全域性作用域一樣。執行類語句後, 將按名稱限定: object.name
來訪問類屬性。
類屬性提供物件狀態和行為。類物件的屬性記錄狀態資訊和要由類建立的所有例項共享的行為;巢狀在類中的函式 def
語句生成處理例項的 方法 。
Instance Objects Are Concrete Items
例項物件是具體的元素:
- 呼叫類物件 (如函式) 會產生一個新的例項物件 。每次呼叫類時, 它都會建立並返回一個新的例項物件。例項表示程式域中的具體項。
- 每個例項物件都繼承類屬性並獲取其自己的名稱空間 。從類建立的例項物件是新的名稱空間;它們開始為空, 但繼承在從中生成它們的類物件中的屬性。
- 在方法中對
self
屬性的賦值使每例項屬性 。在類的方法函式中, 第一個引數 (一般約定為self
) 引用正在處理的例項物件;對自身屬性的賦值在例項中建立或更改資料, 而不是類。
最終的結果是類定義公共的、共享的資料和行為, 並生成例項。例項反映具體的應用程式實體, 並記錄每個物件可能有所不同的每例項資料。
詳細內容見:類與物件
模組與類的區別
- 模組反映了整個 檔案
- 類只是檔案內的 語句
運算子過載
class FirstClass: def setdata(self, value): self.data = value def display(self): print('當前的值:', self.data) class SecondClass(FirstClass): def __init__(self, value): ''' 建構函式 ''' self.data = value def __add__(self, other): ''' 過載:+ ''' return SecondClass(other + self.data) def __str__(self): ''' 過載:print ''' return '[SecondClass: %s]' % self.data def mul(self, other): self.data *= other
a = SecondClass('abc') a.display()
當前的值: abc
print(a)
[SecondClass: abc]
b = a + 'xyz' print(b)
[SecondClass: xyzabc]
a.mul(3) print(a)
[SecondClass: abcabcabc]
類與字典
class rec: pass
為 rec
類新增屬性:
rec.name = 'Bob' rec.age = 40
print(rec.name)
Bob
x = rec() y = rec()
x.name, y.name
('Bob', 'Bob')
x.name = 'Sue' rec.name, x.name, y.name
('Bob', 'Sue', 'Bob')
名稱空間物件的屬性通常都是以字典的形式實現的,而類繼承樹(一般而言)只是連線至其他字典的字典而已。例如, __dict__
屬性是針對大多數基於類的物件的名稱空間字典 (一些類也可能在 __slots__
中定義屬性)。
rec.__dict__.keys()
dict_keys(['__module__', '__dict__', '__weakref__', '__doc__', 'name', 'age'])
list(x.__dict__.keys())
['name']
list(y.__dict__.keys())
[]
使用 __class__
獲取例項的繼承:
x.__class__
__main__.rec
使用 __bases__
獲取類的超類:
rec.__bases__
(object,)
Python 的類模型是相當動態:類和例項只是名稱空間物件,屬性是通過賦值語句動態建立的。
類中的函式 ( def
語句)一般稱作 方法 ,代表類的邏輯。