簡介:
Python中也有類的概念,且與所有面向對象語言類似(更類似于java,而不是C++),隻是沒有public, private, protected關鍵字。Python使用自己的方法支援這些關鍵字的功能,但需要使用者自己遵守,因為并不是嚴格支援。
首先,從一個簡單的例子學習Python中類的構成:(Python3.3)
class Dog:
def __init__(self):
self.nr=1# self.nr+=1 is wrong
#Dog.nr=111
def __del__(self):
pass
class Cat:
nr=0
def __init__(self):
self.nr=9# or self.nr+=9
Cat.nr+=1
dog1=Dog()
print(dog1.nr)
#print(Dog.nr)
cat1=Cat()
print("cat1.nr=",cat1.nr,", Cat.nr=",Cat.nr,sep='')
cat2=Cat()
print("cat2.nr=%d, Cat.nr=%d"%(cat2.nr,Cat.nr))
上例中,定義了兩個類Dog與Cat,并分别定義了兩個函數__init__(), __del__(),這兩個函數是系統定義的函數(形如__func__的均是系統定義的函數,前後各兩個下劃線),分别表示構造函數與析構函數,且均可以省略不寫。定義類方法時,第一個參數必須寫,建議寫self。
關于類中出現的的變量,簡單的來說,比如在Cat類中,有self.nr與Cat.nr兩種,他們的差別是self.nr是類執行個體的變量,而Cat.nr是類的變量。而在Dog類中由于沒有給Dog.nr賦過值,即沒有Dog.nr,則在類外面不能使用Dog.nr。同時,另一點需要注意的是:init函數中,如果self.nr是出現在=右邊,則要保證其已經被賦過值,或者類名.nr這個變量有值。因為,當遇到+=等操作需要使用self.nr時,如果在函數内未定義過self.nr(即未使用=對self.nr賦過值),則會到函數外面的類變量中進行尋找,如果找到則将類的nr變量的值視為執行個體自己的nr變量的初值,然後再對類執行個體自己的nr指派。以下Dog1是正确的,而Dog2錯誤:
class Dog1:
def __init__(self):
Dog.nr=111
self.nr+=1
class Dog2:
def __init__(self):
self.nr+=1
Dog.nr=111
實際上,類變量的這種情況在繼承中也有展現:如果子類中某一變量未被使用=賦過值,則會往上尋找到父類中調用這一變量。
繼承,多态:
class Animal:
nr=0
def __init__(self):
self.nr+=1
Animal.nr+=1
def __del__(self):
pass
def act(self):
print("Act.")
def sleep(self):
print("Sleep.")
class Bird(Animal):
def __init__(self):
self.nr+=1
Bird.nr+=1
def act(self):
print("Fly.")
bird1=Bird()
print(bird1.nr,Bird.nr)
print(bird1.act())
bird1.sleep()
bird2=Bird()
print(bird2.nr)
print(bird1.nr,bird2.nr,Animal.nr,Bird.nr)
animal1=Animal()
print("Animal.nr=",Animal.nr)
Bird是Animal的子類,使用形如SubClass(Class)來定義。子類可繼承父類的所有公共的資料(包括變量與方法),并且可以使用同名的方法覆寫(overrid)父類的方法(即多态)。上例中,Bird繼承了Animal的nr變量(當然Bird.nr與Animal.nr的值需要接下來詳細讨論一下),及所有方法,但又自己重寫了初始化函數與act()函數。是以當運作bird1.act()時,調用的是Bird類中的act(),而在bird1.sleep()中,調用的卻是Animal.sleep()函數。
在Bird的init()中,Bird.nr+=1實際上等價于Bird.nr=Animal.nr+1,self.in+=1也等價于self.nr=Animal.nr+1,因為之前未對Bird.nr賦過值,是以在Bird類中找不到nr變量時,會在其父類中查找,如果仍找不到才報錯,self.nr同理,隻是一個是類的變量,一個是類執行個體的變量。一旦給Bird.nr賦過值後,Bird.nr就有了自己的值,而不會是Animal.nr。下面這個Bird類,由于始終未對Bird.nr指派,隻是使用了其值,是以Bird.nr實際上一直是Animal.nr,并沒有新配置設定記憶體來存,可以在改變Animal.nr後檢視Animal.nr與Bird.nr進行驗證。
class Bird(Animal):
def __init__(self):
Animal.__init__(self)
self.nr=Bird.nr+1
def act(self):
print("Fly.",Bird.nr)
另外,Python不支援諸如C++, Java的根據參數類型與數目的不同而進行的重載(overload),即隻以函數名字做為函數身份的判斷,不會依據參數。而且如果出現多個同名函數(不論參數是否數目相同),則以最後一個為準(即後出現的函數将之前的同名函數覆寫)。
私有成員:
Python并沒有public, private, protected這些關鍵字,那麼Python如何實作這些功能呢?
實際上,Python使用了自己獨特的方法實作的,如果函數名如下任意一種形式,則表示會具有特殊的含義:
_func: 相當于protected func,但隻有在某一函數寫在類的外面的時候,才不能通過from module import *而被其他子產品得到,其他情況均可以被得到。
__func__: 表示系統定義的函數,是以盡量避免使用這種前後各兩個下劃線的方法定義使用者自己的函數。
__func: 相當于private func,但并非絕對的private,會通過下面一個例子解釋其原理。
class Parent:
def __init__(self):
# print('a')
self.__act()
self.sleep()
def __act(self):
print("Parent acts.")
def sleep(self):
print("Parent sleeps.")
class Child(Parent):
def __act(self):
print("Child acts.")
def sleep(self):
print("Child sleeps.")
c=Child()
運作結果為:
Parent acts.
Child sleeps.
可以看到,這裡Parent.__act()函數并沒有被覆寫,這是因為在Python中,對形如__開頭的函數會做name mangling,即将__func()變為_ClassName__func(),是以被處理之後的self.__act()變為了self._Parent__act(),而且def __act(self)變為了def _Parent__act(self),可以通過改變init函數來驗證:将self.__act()顯式的改為self._Parent__act(),不用改變函數定義。
是以,雖然Python提供了一些類似這些關鍵字的技術,但并非絕對安全,主要還是需要使用者自己遵守,不去破壞。