訪問限制
在Class
內(nèi)部,可以有屬性和方法,外部代碼可以通過直接調(diào)用實例變量的方法來操作數(shù)據(jù)效五。隱藏了內(nèi)部的復(fù)雜邏輯。
但是炉峰,外部代碼還是可以自由的修改一個實例的屬性畏妖。若要讓內(nèi)部屬性不被外部訪問,在屬性的名稱前加上__
讲冠,實例的變量名若以__
開頭瓜客,就編程了一個私有變量,只有內(nèi)部可以訪問竿开,外部不能訪問:
class Student(object):
def __init__(self, name, score):
self.__name = name
self.__score = score
def print_score(self):
print('%s: %s' % (self.__name, self.__score))
外部訪問時谱仪,實例變量.__name
和實例變量.__score
無法被訪問。確保了外部代碼不能隨意修改內(nèi)部的狀態(tài)否彩。
新增方法疯攒,給外部代碼訪問的讀取權(quán)限。
class Student(object):
...
def get_name(self):
return self.__name
def get_score(self):
return self.__score
新增發(fā)發(fā)列荔,給外部代碼訪問的寫權(quán)限敬尺。
class Student(object):
...
def set_name(self, name):
self.__name = name
def set_score(self, score):
self.__score = score
注意:在Python中,變量名類似__xx__
的贴浙,也就是雙下劃線開頭及結(jié)尾的砂吞,是特殊變量,可以直接訪問崎溃,不是private變量蜻直。
有時,會有單下劃線開頭的實例變量名,是可以直接訪問的概而,但當看到這樣的變量時呼巷,雖然可以被訪問,但是赎瑰,請視為私有變量王悍,不要隨意訪問。
雙下劃線開頭的實例變量也可以直接訪問餐曼,不能直接訪問的原因是因為Python解釋器對外把__xx
變量改成了_Class__xx
压储,所有,仍然可以通過_Class__xx
來訪問__xx
變量源譬。
但是渠脉,強烈建議不要這么干,因為不同版本的Python解釋器可能會把__xx改成不同的變量名瓶佳。總的來說鳞青,Python本身沒有任何機制阻止你干壞事霸饲,一切靠自覺。
繼承和多態(tài)
在OOP程序設(shè)計中臂拓,當定義一個class的時候厚脉,可以從某額現(xiàn)有的class繼承,新的class稱為子類(Sub class)胶惰,而被繼承的class稱為基類 傻工、父類、超類(Base class孵滞、Super class)中捆。
如,編寫一個動物的classAnimal
坊饶,有一個run()
方法可以打有刮薄:
class Animal(object):
def run(self):
print('Animal is running...')
編寫Dog
、Cat
類匿级,繼承Animal
類:
class Dog(Animal):
pass
class Cat(Animal):
pass
對于Dog
和Cat
來說蟋滴,Animal
就是它們的父類。對于Animal
來說痘绎,Dog
和Cat
就是它的子類津函。
繼承:1. 子類獲得了父類的全部功能,即Dog
和Cat
已經(jīng)自動擁有了run()
方法孤页。
dog = Dog()
dog.run() # Animal is running...
cat = Cat()
cat.run() # Animal is running...
繼承:2. 當子類和父類存在相同的run()
方法時尔苦,子類的run()
會覆蓋父類的run()
,代碼運行時,總是會調(diào)用子類的run()
蕉堰。即:多態(tài)凌净。
多態(tài):定義三個數(shù)據(jù)類型,list屋讶、Animal冰寻、Dog
a = list()
b = Animal()
c = Dog()
print(isinstance(a, list)) # True
print(isinstance(b, Animal)) # True
print(isinstance(c, Dog)) # True
print(isinstance(c, Animal)) # True
從上述結(jié)果可知,實例變量c
既是Animal
皿渗,又是Dog
斩芭。
因為Dog
時從Animal
繼承下來的,當我們創(chuàng)建一個Dog
的實例時乐疆,它時一個Dog
沒錯划乖,但同時也是一個Animal
,Dog
本來就是Animal
的一種挤土。
但是琴庵,反過來的時候就不可以了。即:
d = Animal()
print(isinstance(d, Dog)) # False
靜態(tài)語言vs動態(tài)語言
對于靜態(tài)語言(例JAVA)來說仰美,若傳入類型為Animal
迷殿,則傳入的對象必須時Animal
或它的子類,否則無法調(diào)用run()
方法咖杂。
對于Python這樣的動態(tài)語言來說庆寺,則不一定需要傳入Animal
類型,只需要保證傳入的對象有一個run()
方法即可诉字。
不管什么類型的對象都能接受懦尝,并且只要這個對象有run()
都可以輸出。作者想表達的意思應(yīng)該是多態(tài)壤圃,如果傳進去的對象自身沒有定義run()
陵霉,就會調(diào)用基類的run(),如果子對象有run()
埃唯,就會調(diào)用自身的run()
撩匕,也就實現(xiàn)了多態(tài)。但是所說的鴨子什么的墨叛,也就是只要傳進去的是一個對象止毕,并且該對象有run()
,就可以體現(xiàn)出run()
的特性漠趁。
小結(jié)
繼承可以把父類的所有功能都直接拿過來扁凛,這樣就不必從零做起,子類只需要新增自己特有的方法闯传,也可以把父類不適合的方法覆蓋重寫谨朝。