構造方法
在Python中創建一個構造方法很容易。只要把init方法的名字從簡單的init修改為魔法版本__init__即可:
>>> class FooBar:
... def __init__(self):
... self.somevar=42
...
>>> f=FooBar()
>>> f.somevar
42
給構造方法傳幾個參數
>>> class FooBar:
... def __init__(self,value=42):
... self.somevar=value
...
>>> f=FooBar('this is a constructor argument')
>>> f.somevar
'this is a constructor argument'
重寫一般方法和特殊的構造方法
構造方法用來初始化新創建對象的狀態,大多數子類不僅要擁有自己的初始化代碼,還要擁有超類的初始化代碼。雖然重寫的機制對于所有方法來說都是一樣的,但是當處理構造方法比重寫普通方法時,更可能遇到特別的問題:如果一個類的構造方法被重寫,那么就需要調用超類(你所繼承的類)的構造方法,否則對象可能不會被正確地初始化。
>>> class Bird:
... def __init__(self):
... self.hungry=True
... def eat(self):
... if self.hungry:
鳥吃過了以后,它就不再饑餓。現在考慮子類SongBird,它添加了唱歌的行為:
>>> class SongBird(Bird):
... def __init__(self):
... self.sound='Squawk'
... def sing(self):
... print self.sound
...
>>> s=SongBird()
>>> s.sing()
Squawk
因為SongBird是Bird的一個子類,它繼承了eat方法,但如果調用eat方法,就會產生一個問題:
>>> s.eat()
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 5, in eat
AttributeError: SongBird instance has no attribute 'hungry'
錯誤:SongBird沒有hungry特性。原因是這樣的:在SongBird中,構造方法被重寫,但新的構造方法沒有任何關于初始化hungry特性的代碼。為了達到預期的效果,SongBird的構造方法必須調用其超類Bird的構造方法來確保進行基本的初始化。有兩種方法能達到這個目的:調用超類構造方法的未綁定版本,或者使用super函數。
調用未綁定的超類構造方法
>>> class SongBird(Bird):
... def __init__(self):
... Bird.__init__(self)
... self.sound='Squawk'
... def sing(self):
... print self.sound
...
>>> s=SongBird()
>>> s.eat()
aaah...
>>> s.eat()
no thanks
>>> s.sing()
Squawk
在調用一個實例的方法時,該方法的self參數會被自動綁定到實例上(這稱為綁定方法)。但如果直接調用類的方法(比如Bird.__init__),那么就沒有實例會被綁定。這樣就可以自由地提供需要的self參數。這樣的方法稱為未綁定(unbound)方法
使用super函數
當前的類和對象可以作為super函數的參數使用,調用函數返回的對象的任何方法都是調用超類的方法,而不是當前類的方法。
>>> __metaclass__=type
>>> class Bird:
... def __init__(self):
... self.hungry=True
... def eat(self):
... if self.hungry:
... print 'aaah...'
... self.hungry=False
... else:
... print 'no thanks'
...
>>> class SongBird(Bird):
... def __init__(self):
... super(SongBird,self).__init__()
... self.sound='Squawk'
... def sing(self):
... print self.sound
...
這個新式的版本的運行結果和舊式版本的一樣
>>> s=SongBird()
>>> s.sing()
Squawk
>>> s.eat()
aaah...
>>> s.eat()
no thanks
基本的序列和映射規則
序列和映射是對象的集合。為了實現它們基本的行為(規則),如果對象是不可變的,那么就需要使用兩個魔法方法,如果是可變的則需要使用4個。
__len__(self):這個方法應該返回集合中所含項目的數量。對于序列來說,這就是元素的個數。對于映射來說,則是鍵-值對的數量。
__getitem__(self,key):這個方法返回與所給鍵對應的值。對于一個序列,鍵應該是1個0~n-1的整數(或者像后面所說的負數),n是序列的長度;對于映射來說,可以使用任何種類的鍵。
__setitem__(self,key,value):這個方法應該按一定的方式存儲和key相關的value,該值隨后可使用__getitem__來獲取。當然,只能為可以修改的對象定義這個方法。
__delitem__(self,key):這個方法在對一部分對象使用del語句時被調用,同時必須刪除和元素相關的鍵。這個方法也是為可修改的對象定義的(并不是刪除全部的對象,而只刪除一些需要移除的元素)。
>>> def checkIndex(key):
... if not isinstance(key,(int,long)):raise TypeError
... if key<0:raise IndexError
...
>>> class ArithmeticSequence:
... def __init__(self,start=0,step=1):
... self.start=start
... self.step=step
... self.changed={}
... def __getitem__(self,key):
... checkIndex(key)
... try:return self.changed[key]
... except KeyError:
... return self.start+key*self.step
... def __setitem__(self,key,value):
... checkIndex(key)
... self.changed[key]=value
...
>>> s=ArithmeticSequence(1,2)
>>> s[4]
9
>>> s[4]=2
>>> s[4]
2
>>> s[5]
11
沒有實現__del__方法的原因是希望刪除元素是非法的:
>>> del s[4]
Traceback (most recent call last):
File "<input>", line 1, in <module>
AttributeError: ArithmeticSequence instance has no attribute '__delitem__'
這個類沒有__len__方法,因為它是無限長的。
如果使用了一個非法類型的索引,就會引發TypeError異常,如果索引的類型是正確的但超出了范圍(在本例中為負數),則會引發IndexError異常:
>>> s[four]
Traceback (most recent call last):
File "<input>", line 1, in <module>
NameError: name 'four' is not defined
>>> s[-4]
Traceback (most recent call last):
File "<input>", line 1, in <module>
File "<input>", line 7, in __getitem__
File "<input>", line 3, in checkIndex
IndexError
子類化列表,字典和字符串
例子----帶有訪問計數的列表:
>>> class CounterList(list):
... def __init__(self,*args):
... super(CounterList,self).__init__(*args)
... self.counter=0
... def __getitem__(self,index):
... self.counter +=1
... return super(CounterList,self).__getitem__(index)
...
CounterList類嚴重依賴于它的子類化超類(list)的行為CounterList類沒有重寫任何的方法(和append extend, index一樣)都能被直接使用。在兩個被重寫的方法中,super方法被用來調用相應的超類的方法,只在__init__中添加了所需的初始化counter特性的行為,并在__getitem__中更新了counter特性。
>>> c1=CounterList(range(10))
>>> c1
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> c1.reverse()
>>> c1
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
>>> del c1[3:6]
>>> c1
[9, 8, 7, 3, 2, 1, 0]
>>> c1[4]+c1[2]
9
>>> c1.counter
2
CounterList在很多方面和列表的作用一樣,但它有一個counter特性(被初始化為0),每次列表元素被訪問時,它都會自增,所以在執行加法c1[4]+c1[2〕后,這個值自增兩次,變為2.

新聞熱點
疑難解答