面向對象的python編程
例:
>>> class Wallet:
"Where does my money go?"
walletCnt = 0
def __init__(self,balance = 0):
self.balance = balance
Wallet.walletCnt += 1
def getPaid(self,amnt):
self.balance += amnt
self.displayBalance()
def spend(self,amnt):
self.balance -= amnt
self.displayBalance()
def displayBalance(self):
print 'new balance:$%.2f'%self.balance
>>>
一、定義一個新類
class語句創建了一個名為Wallet的新類定義(它本身也是一個對象)。這個類包含一個文檔字符串(使用Wallet__doc__可以訪問該字符串)、已存在的所有皮夾數目以及3個方法。
對于方法,可以像常規函數一樣進行聲明,只是每個方法的第一個參量都為self,這是對象實例的常規Python名(它與java中的this對象或c++中的this指針具有相同的作用)。Python把self參量添加到你的列表中:當調用方法時,不需要引入它。第一個方法時特殊的構造函數或初始化方法(當你創建這個類的一個新實例時,python會調用它)。注意,它會接受初始余額來作為可選參數。另外兩個方法將在皮夾當前余額的基礎上進行運算。
(所有方法一定要在對象的實例上進行運算,如果是從c++中轉過來的,則沒有“靜態方法”)。
對象可以包含兩種類型的數據成員:WalletCnt,位于類的方法之外,而且是類變量,意味著類的所有實例將共享它。在一個實例中(或在類定義中)更改它的值就表明在所有地方都更改了它,所以某些皮夾可以使用WalletCnt查看已經創建的皮夾數:
>>> myWallet = Wallet()
>>> yourWallet = Wallet()
>>> print myWallet.walletCnt,yourWallet.walletCnt
4 4
另一種類型的數據成員是實例變量,它是在方法內進行定義的,而且只屬于對象的當前實例,Wallet的balance成員是一個實例變量。一定要使用self參數引用它的屬性,而不管它們是方法還是數據成員。
創建類的實例對象并訪問
>>> w = Wallet(50.00)
>>> w.getPaid(100.00)
new balance:$150.00
>>> w.spend(25.00)
new balance:$125.00
>>> w.balance
125.0
>>>
類的實例使用詞典(名為__dict__)保存屬性和該實例特定的值。這樣,object.attribute與object.__dict__['attribute']相同。另外,每個對象和類都包含幾個其他的特殊成員:
>>> Wallet.__name__ # Class name
'Wallet'
>>> Wallet.__module__ # Module in which class was defined
'__main__'
>>> w.__class__ #Class definition
>>> w.__doc__ #Doc string
'Where does my money go?'
>>>
有關訪問屬性的更多信息
任何時候都可以添加,刪除或修改類的屬性和對象
>>> w.owner = 'Dave'
>>> w.owner
'Dave'
>>>
修改類定義會影響類的所有實例
>>> Wallet.Color = 'Blue'
>>> w.Color
'Blue'
當某個實例在沒有命名的情況下修改類變量時,它只創建一個新的實例屬性并修改它:
>>> w.Color = 'red'
>>> Wallet.Color
'Blue'
>>> w.Color
'red'
>>>
代替使用常規語句訪問屬性,可以使用getattr(obj.name[,default]),hasattr(obj.name),setattr(obj.name,value)和delattr(obj.name)函數:
>>> hasattr(w,'Color')
True
>>> getattr(w,"Color")
'red'
>>> setattr(w,'size',10)
>>> getattr(w,'size')
10
>>> delattr(w,'size')
>>> getattr(w,'size')
Traceback (most recent call last):
File "", line 1, in -toplevel-
getattr(w,'size')
AttributeError: Wallet instance has no attribute 'size'
>>>
與函數一樣,方法也可以包含數據屬性。
>>> class SomeClass:
def deleteFiles(self,mask):
cs.destroyFiles(mask)
deleteFiles.htmldoc = 'use with care!'
>>> hasattr(SomeClass.deleteFiles,'htmldoc')
True
>>> SomeClass.deleteFiles.htmldoc
'use with care!'
>>>
從其他類中創建新類,在新類名之后用圓括號列出父類
>>> class GetAwayVehicle:
topSpeed = 200
def engageSmokeScreen(self):
print ''
def fire(self):
print 'Bang!'
>>> class SupperMotorcycle(GetAwayVehicle):
topSpeed = 250
def engageOilSlick(self):
print "Enemies destroyed."
def fire(self):
GetAwayVehicle.fire(self)
print "kapow!"
>>> mybike = SupperMotorcycle()
>>> mybike.engageOilSlick()
Enemies destroyed.
>>> mybike.engageSmokeScreen()
>>> mybike.fire()
Bang!
kapow!
>>>
多繼承
>>> class Glider:
def extendWings(self):
print 'wings ready!'
def fire(self):
print 'bombs away!'
>>> class FlyingBike(Glider,SupperMotorcycle):
pass
>>> c = FlyingBike()
>>> c.fire()
bombs away!
>>> c.extendWings()
wings ready!
>>> getattr(c,"topSpeed")
250
>>>
使用類定義對象的__bases__成員,可以得到一列基類:
>>> for base in FlyingBike.__bases__:
print base
__main__.Glider
__main__.SupperMotorcycle
>>>
創建定制的列表類
>>> import UserList,whrandom
>>> from whrandom import randint
>>> class MangleList(UserList.UserList):
def mangle(self):
data = self.data
count = len(data)
for i in range(count):
data.insert(randint(0,count - 1),data.pop())
>>> z = MangleList([1,2,3,4,5])
>>> z.mangle();print z
[4, 1, 2, 3, 5]
>>> z.mangle();print z
[5, 4, 1, 3, 2]
>>>
隱藏私有數據
采用雙下劃線前綴命名屬性,旁觀者不能查看這些屬性。
Python通過內部更改包括類名的名字來保護這些成員。通過使用已損壞的名字
__className__attrName來引用屬性,就能夠偷偷摸摸地阻礙這個約定(進行這種操作的正當理由很少見):
>>> class FooCounter:
__secretCount = 0
def foo(self):
self.__secretCount += 1
print self.__secretCount
>>> foo = FooCounter()
>>> foo.foo()
1
>>> foo.foo()
2
>>> foo.foo()
3
>>> foo.__secretCount
Traceback (most recent call last):
File "", line 1, in -toplevel-
foo.__secretCount
AttributeError: FooCounter instance has no attribute '__secretCount'
>>> foo._FooCounter__secretCount
3
>>>
識別類成員
>>> class Tree:
pass
>>> class Oak(Tree):
pass
>>> seedling = Oak()
>>> type(seedling);type(Oak)
由于類型是實例或類,因此,所有的類定義都具有相同的類型,而且所有的實例對象都具有相同的類型。如果想查看某個對象是否是特殊類的一個實例,則可以使用isinstance(obj,class)函數
>>> isinstance(seedling,Oak)
True
>>> isinstance(seedling,Tree)
True
>>>
issubclass(class,class)進行檢查,以查看一個類是否是另一個類的后繼:
>>> issubclass(Oak,Tree)
True
>>> issubclass(Tree,Oak)
False
>>>
也可以使用__name__成員檢索類的字符串:
>>> seedling.__class__.__name__
'Oak'
>>> seedling.__class__.__bases__[0].__name__
'Tree'
>>>
重載
>>> class Vector:
def __init__(self,a,b):
self.a = a
self.b = b
def __str__(self):
return 'Vector(%d,%d)' %(self.a,self.b)
def __add__(self,cther):
return Vector(self.a + cther.a,self.b + cther.b)
>>> v1 = Vector(2,10);v2 = Vector(5,-2)
>>> print v1,v2
Vector(2,10) Vector(5,-2)
>>> print v1 + v2
Vector(7,8)
>>>
基重載方法
注意,采用del語句,如果對象的引用計數最后變為0,Python就不會調用__del__方法。
當有人把你的對象的實例當作函數對待時,Python就會調用__call__方法。使用callable(obj)函數,用戶可以測試“調用能力”.該函數試圖確定這個對象是否是可調用的(callable)可以返回真,而且是錯誤的,如果它返回丁假,該對象確實是不可調用的)
python只在通過實例詞典搜索之后調用__getattr__函數,而且基類會發生空處理,這時實現應該返回想要的屬性,或者產生AttributeError異常情況。如果__setattr__需要給實例變量賦值,則應確保它賦值給實例詞典而不是(self.__dict__[name] = val).以防止遞歸調用__setattr__。如果你自己的類包含__setattr__方法。則python總是會調用它設置成員變量值。即使實例詞典已經包含要設置的變里也一樣。
hash函數和cmp函數是密切相關:如果沒有實現__cmp__.則也不能夠實現__hash__.但沒有提供__hash__,則對象的實例就不能擔當詞典鍵(如果你的對象是可變的,這就是正確的)。散列位是32儀整型數.而且被認為相等的兩個實例也應該返回同一個散列值。
nonzefo函數完成了真值測試以便你的實現能夠返回0或1。如果沒有實現它python就會查找__len__實現,以便使用,如果還是沒有找到,則對象的所有實例都會被看作“真”值。
使用__it__,__gt__和其他方法,就能夠實現對rich comparisons的支持,對于這種比較,可以在不同類型的比較之間更完全地控制對象的行為。如果存在的話,python會在查找__cmp__方法之前調用其中的某些方法。
重載數字運算符
>>> class Add:
def __init__(self,val):
self.val = val
def __add__(self,obj):
print "add",obj
return self.val + obj
def __radd__(self,obj):
print "radd",obj
return self.val + obj
>>> a = Add(2)
>>> a
<__main__.Add instance at 0x00AB8AA8>
>>> a +5
add 5
7
>>> 5 + a
radd 5
7
>>>
數字的運算符方法
重載序列和詞典運算符
參量to__getitem__可以是整型,也可以是切片對象。切片對象具有start,stop和step屬性,所以你的類能夠支持示例中給出的擴展切片。
>>> class Stepper:
def __init__(self,step):
self.step = step
def __getitem__(self,index):
if index > 5:
raise IndexError
return self.step * index
>>> s = Stepper(30)
>>> for i in s:
print i
0
30
60
90
120
150
>>>
重載按位運算符
重載類型轉換
使用弱引用
通過調用weakref模塊內的ref(obj[,callback]),就可以創建弱引用,其中obj是想要對它進行弱引用的對象,而callback是一個可選函數,當Python將要撤銷對象(由于不存在強壯的引用)時會調用該函數;回調函數只獲取一個參量,即弱引用對象。
一旦擁有了對象的弱引用.就可以通過調用弱引用,來檢索引用的對象;下面的示例創建了對套接字對象的弱引用: