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
方法中的代碼所要做的。
初始化對像
創建球對像時,並沒有在 size
、color
或 direction
中填入任何內容。必須在創建對像之後填充這些內容。不過有一種方法可以在創建對像時設置屬性。這稱為初始化對象。
術語箱
初始化(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 Ball
?self
參數會告訴方法哪個對象調用它。這稱為實例引用(instance reference)。
不過先等等!調用方法時,warrensBall.bounce
的括號裡沒有參數,但是方法裡卻有一個 self
參數。既然我們並沒有傳入任何東西,這個 self
參數從哪裡來的?這是 Python 處理對象的另外一個「魔法」。調用一個類方法時,究竟是哪個實例調用了這個方法?這個信息(也就是實例引用)會自動傳遞給方法。
這就像寫成:
Ball.bounce(warrensBall)
在這種情況下,我們告訴了 bounce
方法哪個球要反彈。實際上,這個代碼也能正常工作,因為寫成 warrensBall.bounce
時,Python 在後台確實也是這麼做的。
順便說一句,self 這個名字在 Python 中沒有任何特殊的含義。只不過所有人都使用這個實例引用名。這也是讓代碼更易讀的一個約定。也可以把這個實例變量命名為你想要的任何名字,不過強烈建議你遵循這個約定,因為使用 self 能減少混亂。
我們在第 11 章建立了一個熱狗程序。現在作為使用對象的例子,我們來為熱狗建立一個類。