python的三大特性之封裝
封裝
隱藏物件的某些屬性和實現的細節,僅僅只對外提供公共訪問的方式。將函式和屬性裝到了一個非全域性的名稱空間。
封裝的好處
(1)將變化隔離
(2)便於使用
(3)提高複用性
(4)提高安全性
封裝原則
(1)將不需要對外提供的內容全部都隱藏起來
(2)吧屬性都隱藏,提供公共方法對其訪問
私有變數和私有方法
私有變數:不能在類的外面去引用它。
它依然存在於__dict__中,我們仍然可以呼叫到。只是python對其的名字進行了修改: _類名__名字。但是在類的外部呼叫 :需要“_類名__名字”去使用,在類的內部可以正常的使用名字
在python中定義一個私有的名字 :使用兩條下劃線開頭的方式來定義變數名稱 __N = ‘aaa’
class Student: __id = 0 #變成了私有的靜態變數類的資料屬性就應該是 # 共享的,但是語法上是可以把類的資料屬性設定成私有的如__N,會變形為_A__N def __init__(self, name, age): self.name = name #變形為self._Student__name ,私有屬性 self.age = age #變形為self._Student__age ,私有屬性 def func(self): print(Student.__id) #在類的內部使用正常 s = Student('hh', 18) s.func() print(Student.__id) # 在類的外部直接使用 報錯
print(Student._Student__id) #不報錯
由此,私有變數只能在類的內部訪問的到,外部不能訪問,但是,由於它是一個變形的方式。其實可以通過變形以後的方式進行訪問,但嚴格意義上來講,我們不能通過它來訪問,這時只有我們程式設計師知道就可以了
這種自動變形的特點:
1.類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。
2.這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字訪問到的。
3.在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
變形需要注意的問題是:
1.這種機制也並沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然後就可以訪問了,如a._A__N
2.變形的過程只在類的內部生效,在定義後的賦值操作,不會變形
私有方法
私有方法的定義和私有變數一樣,只需要在前面加上雙下劃線,就是標誌著私有方法
class Student:
def func(self):
print("我是一個好學生") # 在類的內部使用正常
def __ADCa(self):
print("我喜歡喝ADCa")
s = Student()
s.func() #普通方法呼叫
s._Student__ADCa() #私有方法呼叫
s.__ADCa #這樣呼叫,直接報錯
在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的
#正常情況,方法都是普通方法
class Dad:
def dear(self):
print('from Dad')
def father(self):
self.dear()
class Son(Dad):
def dear(self):
print('from Son')
s = Son()
s.father()
#當某一個方法是私有的時候,子類就不能繼承父類的私有方法了
class Dad:
def dear(self):
print('from Dad')
def __father(self):
self.dear()
class Son(Dad):
def dear(self):
print('from Son')
s = Son()
s.father()
總之,在類中,靜態屬性,方法,物件屬性都可以變成私有的,只需要在這些名字之前加上__
私有的名字,在類內使用的時候,就是會變形成_該類名__方法名。下面這個例子:
以此為例 :沒有雙下換線會先找E中的func,但是有了雙下劃線,會在呼叫這個名字的類D中直接找_D__func
class D:
def __init__(self):
self.__func()
def __func(self):
print('in D')
class E(D):
def __func(self):
print('in E')
e = E() #結果:<em id="__mceDel">in D</em><em id="__mceDel" style="font-size: 1.5em; background-color: #ffffff; font-family: "PingFang SC", "Helvetica Neue", Helvetica, Arial, sans-serif"> </em>
封裝與擴充套件性
封裝在於明確區分內外,使得類實現者可以修改封裝內的東西而不影響外部呼叫者的程式碼;而外部使用用者只知道一個介面(函式),只要介面(函式)名、引數不變,使用者的程式碼永遠無需改變。這就提供一個良好的合作基礎——或者說,只要介面這個基礎約定不變,則程式碼改變不足為慮。
#類的設計者,輕鬆的擴充套件了功能,而類的使用者完全不需要改變自己的程式碼
class Room:
def __init__(self,name,owner,width,length,high):
self.name=name
self.owner=owner
self.__width=width
self.__length=length
self.__high=high
def tell_area(self): #對外提供的介面,隱藏內部實現,此時我們想求的是體積,內部邏輯變了,<br> #只需求修該下列一行就可以很簡答的實現,而且外部呼叫感知不到,仍然使用該方法,但是功能已經變了
return self.__width * self.__length * self.__high #對於仍然在使用tell_area介面的人來說,根本無需改動自己的程式碼,就可以用上新功能