讀古今文學網 > 父與子的編程之旅:與小卡特一起學Python > 14.5 創建對像 >

14.5 創建對像

Python 中創建對像包括兩步。

第一步是定義對像看上去什麼樣,會做什麼,也就是它的屬性和方法。但是創建這個描述並不會真正創建一個對象。這有點像一個房子的藍圖。藍圖可以告訴你房子看上去怎麼樣,但是藍圖本身並不是一個房子。你不可能住在一個藍圖裡。只能用它來建造真正的房子。實際上,可以使用藍圖蓋很多的房子。

在 Python 中,對象的描述或藍圖稱為一個類(class)。

第二步是使用類來建立一個真正的對象。這個對象稱為這個類的一個實例(instance)。

下面來看一個建立類和實例的例子。代碼清單 14-1 顯示了一個簡單的 Ball 類的類定義。

代碼清單 14-1 創建一個簡單的 Ball

代碼清單 14-1 是一個球的類定義,其中只有一個方法 bounce。不過,屬性呢?嗯,屬性並不屬於類,它們屬於各個實例。因為每個實例可以有不同的屬性。

設置實例屬性有兩種方法。後面的小節中我們會分別瞭解這兩種方法。

創建一個對像實例

前面提到過,類定義並不是一個對象。這只是藍圖。現在來蓋真正的房子。

如果想創建 Ball 的一個實例,可以這樣做:

myBall = Ball  

這個球還沒有任何屬性,所以下面給它提供一些屬性:

myBall.direction = \"down\"myBall.color = \"green\"myBall.size = \"small\"  

這是為對像定義屬性的一種方法。下一節還會學習另一種方法。

現在來試試它的方法。我們要這樣使用 bounce 方法:

myBall.bounce  

下面把這些都放在一個程序裡,增加一些 print 語句來看發生了什麼。程序見代碼清單 14-2。

代碼清單 14-2 使用 Ball

運行這個程序,可以看到下面的結果:

注意,調用 bounce 方法會把球的方向(direction)從下(down)改為上(up),這正是 bounce 方法中的代碼所要做的。

初始化對像

創建球對像時,並沒有在 sizecolordirection 中填入任何內容。必須在創建對像之後填充這些內容。不過有一種方法可以在創建對像時設置屬性。這稱為初始化對象。

術語箱

初始化(initializing)表示「開始時做好準備」。在軟件中對某個東西初始化時,就是把它設置成一種我們希望的狀態或條件,以備使用。

創建類定義時,可以定義一個特定的方法,名為 __init__,只要創建這個類的一個新實例,就會運行這個方法。可以向 __init__ 方法傳遞參數,這樣創建實例時就會把屬性設置為你希望的值。代碼清單 14-3 顯示了這是如何實現的。

代碼清單 14-3 增加一個 __init__ 方法

如果這個程序,得到的輸出應該與代碼清單 14-2 的相同。區別在於,代碼清單 14-3 使用了 __init__方法來設置屬性。

謝謝你的提醒,卡特。在下一節中,我們將會瞭解這些「魔法」方法到底是什麼。

「魔法」方法 : str

就像卡特說的,Python 中的對象有一些「魔法」方法,當然它們並不是真的有魔法!這些只是在你創建類時 Python 自動包含的一些方法。Python 程序員通常把它們叫做特殊方法(special method)。

我們已經知道, __init__ 方法會在對像創建時完成初始化。每個對象都內置有一個 __init__ 方法。如果你在類定義中沒有加入自己的 __init__ 方法,就會有這樣一個內置方法接管,它的工作就是創建對象。

另一個特殊方法是 __str__,它會告訴 Python 打印(print)一個對像時具體顯示什麼內容。Python 會默認以下內容。

  • 實例在哪裡定義(卡特的例子中,就是在 __main__中,這是程序的主部分)。

  • 類名(Ball)。

  • 存儲實例的內存位置(0x00BB83A0 部分)。

不過,如果你希望 print 為對像顯示其他的內容,可以定義自己的 __str__,這會覆蓋內置的 __str__ 方法。代碼清單 14-4 舉了個例子。

代碼清單 14-4 使用 __str__ 改變打印對象的方式

現在運行這個程序,可以得到下面的結果:

>>> ================= RESTART =================>>>Hi, I\'m a small red ball!  

這看起來比 <__main__.Ball instance at 0x00BB83A0> 好多了,你認為呢?所有「魔法」方法都在方法名稱前後各使用兩條下劃線。

什麼是 self

你可能已經注意到,在類屬性和方法定義中多處出現了「self」,比如:

def bounce(self):  

self 是什麼意思?嗯,我們說過,可以使用藍圖蓋很多個房子,還記得吧?使用一個類也可以創建多個對象實例,例如:

調用其中一個實例的方法時,像這樣:

warrensBall.bounce  

方法必須知道是哪個實例調用了它。是 cartersBall 需要反彈嗎?還是 warrens Ballself 參數會告訴方法哪個對象調用它。這稱為實例引用(instance reference)。

不過先等等!調用方法時,warrensBall.bounce 的括號裡沒有參數,但是方法裡卻有一個 self 參數。既然我們並沒有傳入任何東西,這個 self 參數從哪裡來的?這是 Python 處理對象的另外一個「魔法」。調用一個類方法時,究竟是哪個實例調用了這個方法?這個信息(也就是實例引用)會自動傳遞給方法。

這就像寫成:

Ball.bounce(warrensBall)  

在這種情況下,我們告訴了 bounce 方法哪個球要反彈。實際上,這個代碼也能正常工作,因為寫成 warrensBall.bounce 時,Python 在後台確實也是這麼做的。

順便說一句,self 這個名字在 Python 中沒有任何特殊的含義。只不過所有人都使用這個實例引用名。這也是讓代碼更易讀的一個約定。也可以把這個實例變量命名為你想要的任何名字,不過強烈建議你遵循這個約定,因為使用 self 能減少混亂。

我們在第 11 章建立了一個熱狗程序。現在作為使用對象的例子,我們來為熱狗建立一個類。