標籤:set foo auth 模組名 clear 父類 層級 atm code
python 3 封裝
從封裝本身的意思去理解,封裝就好像是拿來一個麻袋,把小魚,小蝦,小王八,一起裝進麻袋,然後把麻袋封上口子。照這種邏輯看,封裝=‘隱藏’,這種理解是相當片面的。
先看如何隱藏
在python中用雙底線開頭的方式將屬性隱藏起來(設定成私人的)
其實這僅僅這是一種變形操作
類中所有雙底線開頭的名稱如__x都會自動變形成:_類名__x的形式:
class A: __N=0 #類的資料屬性就應該是共用的,但是文法上是可以把類的資料屬性設定成私人的如__N,會變形為_A__N def __init__(self): self.__X=10 #變形為self._A__X def __foo(self): #變形為_A__foo print(‘from A‘) def bar(self): self.__foo() #只有在類內部才可以通過__foo的形式訪問到.A._A__N是可以訪問到的,即這種操作並不是嚴格意義上的限制外部存取,僅僅只是一種文法意義上的變形。
View Code
這種自動變形的特點:
- 類種定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。
- 這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字訪問到的。
- 在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙底線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
這種變形需要注意的問題是:
1.這種機制也沒有真正意義上限制我們從外部直接存取屬性,知道了雷鳴和屬性名稱就可以拼出名字:_類名__屬性,然後皆可以訪問了,如a._A__N
2.變形的過程只在類的定義時放生一次,在定義後的賦值操作,不會變形
3.在繼承中,父類如果不想讓子類渡改自己的方法,可以將方法定義為私人的
python並不會真的阻止你訪問私人的屬性,模組也遵循這種約定,如果模組名以單底線開頭,那麼from module import *時不能被匯入,但是你from module import _private_module依然是可以匯入的其實很多時候你去調用一個模組的功能時會遇到單底線開頭的(socket._socket,sys._home,sys._clear_type_cache),這些都是私人的,原則上是供內部調用的。作為外部也可以用,只過寫出代碼比較傻了,python要想與其他程式設計語言一樣,嚴格控制屬性的存取權限,只能藉助內建方法如__getattr__
#先看如何隱藏class Foo: __N=111111 #_Foo__N def __init__(self,name): self.__Name=name #self._Foo__Name=name def __f1(self): #_Foo__f1 print(‘f1‘) def f2(self): self.__f1() #self._Foo__f1() f=Foo(‘egon‘)# print(f.__N)# f.__f1()# f.__Namef.f2() #通f #這種隱藏需要注意的問題:#1:這種隱藏只是一種文法上變形操作,並不會將屬性真正隱藏起來print(Foo.__dict__)print(f.__dict__)print(f._Foo__Name)print(f._Foo__N)#2:這種文法層級的變形,是在類定義階段發生的,並且只在類定義階段發生Foo.__x=123123123123123123123123123123123123123123print(Foo.__dict__)print(Foo.__x)f.__x=123123123print(f.__dict__)print(f.__x)#3:在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。class Foo: def __f1(self): #_Foo__f1 print(‘Foo.f1‘) def f2(self): self.__f1() #self._Foo_f1class Bar(Foo): def __f1(self): #_Bar__f1 print(‘Bar.f1‘)b=Bar()b.f2()#封裝不是單純意義的隱藏#1:封裝資料屬性:將屬性隱藏起來,然後對外提供訪問屬性的介面,關鍵是我們在介面內定製一些控制邏輯從而嚴格控制使用對資料屬性的使用class People: def __init__(self,name,age): if not isinstance(name,str): raise TypeError(‘%s must be str‘ %name) if not isinstance(age,int): raise TypeError(‘%s must be int‘ %age) self.__Name=name self.__Age=age def tell_info(self): print(‘<名字:%s 年齡:%s>‘ %(self.__Name,self.__Age)) def set_info(self,x,y): if not isinstance(x,str): raise TypeError(‘%s must be str‘ %x) if not isinstance(y,int): raise TypeError(‘%s must be int‘ %y) self.__Name=x self.__Age=yp=People(‘egon‘,18)p.tell_info()# p.set_info(‘Egon‘,‘19‘)p.set_info(‘Egon‘,19)p.tell_info()#2:封裝函數屬性:為了隔離複雜度#取款是功能,而這個功能有很多功能組成:插卡、密碼認證、輸入金額、列印賬單、取錢#對使用者來說,只需要知道取款這個功能即可,其餘功能我們都可以隱藏起來,很明顯這麼做#隔離了複雜度,同時也提升了安全性class ATM: def __card(self): print(‘插卡‘) def __auth(self): print(‘使用者認證‘) def __input(self): print(‘輸入取款金額‘) def __print_bill(self): print(‘列印賬單‘) def __take_money(self): print(‘取款‘) def withdraw(self): self.__card() self.__auth() self.__input() self.__print_bill() self.__take_money()a=ATM()a.withdraw()# _x=123
範例程式碼
python 3 封裝