Python封裝與隱藏
今日內容:
1.封裝與隱藏
2.property
3.綁定方法與非綁定方法
知識點一:封裝與隱藏
1、什麽封裝:
封:屬性對外是隱藏的,但對內是開放的
裝:申請一個名稱空間,往裏裝入一系列名字/屬性
2、為什麽要封裝:
封裝數據屬性的目的
首先定義屬性的目的就是為了給類外部的使用者使用的,
隱藏之後是為了不讓外部使用者直接使用,需要類內部開辟一個接口
然後讓類外部的使用通過接口來間接地操作隱藏的屬性。
精髓在於:我們可以在接口之上附加任意邏輯,從而嚴格控制使用者對屬性的操作
封裝函數屬性:
首先定義屬性的目的就是為了給類外部的使用使用的,
隱藏函數屬性是為了不讓外不直接使用,需要類內部開辟一個接口
然後在接口內去調用隱藏的功能
精髓在於:隔離了復雜度
3、如何隱藏:
1、 這種隱藏僅僅只是一種語法上的變形操作
2、 這種語法上的變形只在類定義階段發生一次,因為類體代碼僅僅只在類定義階段檢測一次
3、 這種隱藏是對外不對內的,即在類的內部可以直接訪問,而在類的外則無法直接訪問,原因是
在類定義階段,類體內代碼統一發生了一次變形
4、 如果不想讓子類的方法覆蓋父類的,可以將該方法名前加一個__開頭
1 class People: 2 def __init__(self,name,age): 3 self.__name=name 4 self.__age=age 5 6 def tell_info(self): 7 print(‘%s:%s‘ %(self.__name,self.__age)) 8 9 def set_info(self,name,age): 10 if type(name) is not str: 11 # print(‘用戶名必須為str類型‘) 12 # return 13 raise TypeError(‘用戶名必須為str類型‘) 14 15 if type(age) isnot int: 16 # print(‘年齡必須為int類型‘) 17 # return 18 raise TypeError(‘年齡必須為int類型‘) 19 self.__name=name 20 self.__age=age 21 22 peo1=People(‘張三‘,34) 23 # peo1.name=123 24 # peo1.age 25 peo1.tell_info() 26 27 peo1.set_info(‘李四‘,19) 28 peo1.tell_info()
知識點二:property裝飾
property裝飾器用於將被裝飾的方法偽裝成一個數據屬性,
在使用時可以不用加括號而直接引用
1 》》》@propertyde思路演變的過程 2 版本1:正常版本 3 class People: 4 def __init__(self,name,weight,height): 5 self.name=name 6 self.weight=weight 7 self.height=height 8 9 def bmi(self): 10 return self.weight / (self.height**2) 11 12 peo=People(‘張三‘,130,1.65) 13 print(peo.name) #張三 14 print(peo.bmi()) #47.75022956841139 15 16 問題:發現bmi的訪問方式比訪問對象屬性多了個() 17 思路變化1:正常情況下我們訪問對象裏面屬性和類裏面的函數方式為: 18 思路變化2:為了方便用戶調用,能不能讓用戶已訪問對象屬性的方式去訪問bmi print(peo.bmi)
1 》》》》》》版本2:@property初始版本 2 #思考:如何實現改變訪問bmi的方式為》》》print(peo.bmi) 3 # 使用@property:作用是將本裝飾的方法偽裝成一個數據類型,在使用時可以不用加括號而直接使用 4 5 class People: 6 def __init__(self,name,weight,height): 7 self.name=name 8 self.weight=weight 9 self.height=height 10 11 @property #將bmi偽裝成一個數據類型 12 def bmi(self): 13 return self.weight / (self.height**2) 14 15 peo=People(‘張三‘,130,1.65) 16 print(peo.name) #張三 17 print(peo.bmi) #這樣可以直接調用而不用加括號
1 》》》》》完整版:@property 2 #property裝飾器 3 #是一種封裝思想的體現,方便了查 刪 改 4 5 class people: 6 def __init__(self,name): 7 self.__name=name 8 9 @property 10 def name(self): #查看obj.name 11 return ‘名字是:%s‘%self.__name 12 13 @name.setter #更改obj.name=name 14 def name(self,name): 15 if type(name) is not str: 16 raise TypeError(‘名字必須是str類型‘) 17 self.__name=name 18 @name.deleter #刪除 del obj.name 19 def name(self): 20 print(‘不讓刪除‘) #裏面可以設定提示 21 # del self.__name #也可以設定直接刪除功能 22 23 peo=people(‘張三‘) 24 #默認不加@property調用方法為: 25 26 peo.name=‘李四‘ #@name.setter 調用了更改 27 print(peo.name) #@property 調用了查看 輸出結果:名字是:李四 28 del peo.name #@name.deleter 調用了產出的需求 輸出結果:不讓刪除
知識點三:綁定方法
1.綁定方法
特性:綁定給誰就應該由誰來調用,誰來調用就會將誰當做第一個參數自動傳入
精髓:是在於自動傳值
1.1綁定對象的方法
在類內部定義的函數(沒有被任何裝飾器修飾的),默認是綁定給對象用的
1.2綁定給類的方法
在類內部定義的函數如果被裝飾器@classmethod裝飾,
那麽則是綁定給類的,應該由類來調用,類來調用就自動將類當做第一個參數自動傳入
綁定給類的:自動傳的是類的值
綁定給對象的:自動傳的是對象的值
2.非綁定方法
類中定義的函數如果被裝飾器@staticmethod裝飾,那麽該函數就變成非綁定方法
既不與類綁定,又不與對象綁定,意味著類與對象都可以來調用
但是無論誰來調用,都沒有任何自動化傳值的效果,就是一個普通函數
3.應用
什麽時候綁定給類? 什麽時候綁定給對象?
取決於函數體代碼
如果函數體代碼需要用外部傳入的類,則應該將該函數定義成綁定類的方法
如果函數體代碼需要用外部傳入的對象,則應該將該函數定義成綁定給對象的方法
如果函數體代碼既不需要外部傳入的類也不需要外部傳入的對象,則應該將該函數定義成非綁定方法對象,則應該將該函數定義成非綁定方法
1 #綁定方法初始實例:綁定給類@classmethod 2 3 class Foo: 4 @classmethod 5 def f1(cls): 6 print(‘Foo.f1‘) 7 print(cls) 8 9 def f2(self): 10 print(self) 11 obj=Foo() 12 # print(obj.f2) #默認綁定給對象用#<bound method Foo.f2 of <__main__.Foo object at 0x04BACD10>> 13 # print(Foo.f1) #綁定給類用 <bound method Foo.f1 of <class ‘__main__.Foo‘>> 14 Foo.f1() #類調用 15 print(Foo) #所以傳入的值就是類的值 <class ‘__main__.Foo‘> 16 17 obj.f2() #對象調用, 18 print(obj) #所以傳入的值就是對象的值 <__main__.Foo object at 0x04C50EB0> 19 20 # f1綁定給類的應該由類來調用,但對象其實也可以使用,只不過自動傳入的任然是類 21 #f2綁定給對象的應該由對象來調用,但是類其實也可以使用
1 # 綁定方法進階實例2:新的實例化方式,綁定給類 2 """ 3 將需要傳入的信息寫到settings.py文件裏面,調用更加靈活方便 4 IP=‘192.168.11.3‘ 5 PORT=3306 6 """ 7 import settings 8 9 class Mysql: 10 def __init__(self,ip,port): 11 self.ip=ip 12 self.port=port 13 def tell_info(self): 14 print(‘%s:%s‘%(self.ip,self.port)) 15 # print(self) 16 17 @classmethod 18 def from_conf(cls): 19 return cls(settings.IP,settings.PORT) #可以理解為 Mysql(‘1.1.1.1‘,23)即調用了init方法,給其傳參數 cls名字可以隨便起 20 # print(settings.IP) 21 22 #默認的實例化方式:類名(..)(實質給tell_info(self)裏的self傳的是對象res的值) 23 res=Mysql(‘1.1.1.1‘,23) 24 print(res) #<__main__.Mysql object at 0x05717410>即為對象res也就是tell_info(self)的值 25 res.tell_info() 26 27 # 一種新的實例化方式,從配置文件中讀取配置完成實例化(這裏實質給cls傳的是類Mysql的值) 28 res=Mysql.from_conf() 29 res.tell_info() 30 print(res.ip)
非綁定方法應用實例:
1 #非綁定方法應用實例:uuid獲取隨機id值 2 3 import uuid 4 class UserInfo: 5 def __init__(self,name,age): 6 7 self.name=name 8 self.age=age 9 self.uid = self.create_uid() 10 def tell_info(self): 11 print(‘姓名:%s,年齡:%s,ID:%s‘%(self.name,self.age,self.uid)) 12 # print(self) 13 14 @staticmethod #因為不需要傳任何參數所以定義為非綁定方法,類和對象都可以取調用 15 def create_uid(): 16 return uuid.uuid1() 17 18 res=UserInfo(‘張三‘,23,) 19 res.tell_info() 20 print(res.uid)
Python封裝與隱藏