__init__()方法意義重大的原因有兩個。第一個原因是在對象生命周期中初始化是最重要的一步;每個對象必須正確初始化后才能正常工作。第二個原因是__init__()參數值可以有多種形式。
因為有很多種方式為__init__()提供參數值,對于對象創建有大量的用例,我們可以看看其中的幾個。我們想盡可能的弄清楚,因此我們需要定義一個初始化來正確的描述問題區域。
在我們接觸__init__()方法之前,無論如何,我們都需要粗略、簡單地看看在Python中隱含的object類的層次結構。
在這一章,我們看看不同形式的簡單對象的初始化(例如:打牌)。在這之后,我們還可以看看更復雜的對象,就像包含集合的hands對象以及包含策略和狀態的players。
隱含的超類——object
每一個Python類都隱含了一個超類:object。它是一個非常簡單的類定義,幾乎不做任何事情。我們可以創建object的實例,但是我們不能用它做太多,因為許多特殊的方法容易拋出異常。
當我們自定義一個類,object則為超類。下面是一個類定義示例,它使用新的名稱簡單的繼承了object:
class X: pass
下面是和自定義類的一些交互:
>>> X.__class__<class 'type'>>>> X.__class__.__base__<class 'object'>
我們可以看到該類是type類的一個對象,且它的基類為object。
就像在每個方法中看到的那樣,我們也看看從object繼承的默認行為。在某些情況下,超類特殊方法的行為是我們所想要的。在其他情況下,我們需要覆蓋這個特殊方法。
基類對象的init()方法
對象生命周期的基礎是創建、初始化和銷毀。我們將創建和銷毀的高級特殊方法推遲到后面的章節中,目前只關注初始化。
所有類的超類object,有一個默認包含pass的__init__()實現,我們不需要去實現__init__()。如果不實現它,則在對象創建后就不會創建實例變量。在某些情況下,這種默認行為是可以接受的。
我們總是給對象添加屬性,該對象為基類object的子類。思考以下類,需要兩個實例變量但不初始化它們:
class Rectangle: def area(self): return self.length * self.width
Rectangle類有一個使用兩個屬性來返回一個值的方法。這些屬性沒有初始化。這是合法的Python代碼。它可以有效的避免專門設置屬性,雖然感覺有點奇怪,但是有效。
下面是于Rectangle類的交互:
>>> r = Rectangle()>>> r.length, r.width = 13, 8>>> r.area()104
顯然這是合法的,但也是容易混淆的根源,所以也是我們需要避免的原因。
無論如何,這個設計給予了很大的靈活性,這樣有時候我們不用在__init__()方法中設置所有屬性。至此我們走的很順利。一個可選屬性其實就是一個子類,只是沒有真正的正式聲明為子類。我們創建多態在某種程度上可能會引起混亂以及if語句的不恰當使用所造成的盤繞。雖然未初始化的屬性可能是有用的,但很有可能是糟糕設計的前兆。
新聞熱點
疑難解答