封裝、property和綁定方法
一、封裝
1.定義
封:指的是該屬性對外是隱藏的,但是對內部是開放的
裝:申請一個名稱空間,往裏邊丟名字和屬性
2.為什麽要有封裝
2.1 封裝數據屬性的目的:
首先定義數據屬性的目的就是為了給類外部使用的,隱藏之後就是為了不讓外部直接使用,需要通過調用類內部開通的接口來使用;然後類外部需要用到這個功能的時候,可以通過這個接口來間接的調用並操作這個隱藏屬性。
精髓:我們可以在該接口上附加上任何我們想要的邏輯與功能,從而達到嚴格控制使用者對屬性的操作。
2.2 封裝函數屬性的目的:
定義函數屬性的目的就是為了給類外部使用的,隱藏函數屬性的目的就是為了不讓外部直接使用,須在類的內部開辟一個專門的接口;外部需要使用是,也是需通過這個接口來間接的調用並操作這個隱藏的函數屬性。
精髓:隔離了復雜的程度
3.如何做到封裝
可以在需要隱藏的屬性前面加上__開頭
解釋:
3.1 這種隱藏僅僅是一種語法上的變形操作。
3.2 變形操作只在類的定義階段發生一次,因為類體代碼僅僅只在定義階段檢測一次。
3.3 這種隱藏是對外不對外的,即在類的內部可以直接訪問而在外部不能直接訪問;究其根本原因是在類的定義階段,類體的代碼發生了一次統一的變形。
3.4 如果不想讓子類的方法覆蓋父類的,可以直接在子類的方法名前加上__開頭,隱藏其屬性。
1 class People(): 2 def __init__(self,name,age): 3 self.__name封裝的簡單例子=name 4 self.__age=age 5 def tell_info(self): 6 print(‘%s - %s‘%(self.__name,self.__age)) 7 def reset_info(self,name,age): 8 self.__name = name 9 self.__age = age 10 if type(name) is not str: # 在接口上可以添加我們想要的邏輯 11 raise NameError(‘name must be string‘) 12 if type(age) is not int: 13 raise TypeError(‘age must be integer‘) 14 15 p1=People(‘大仙‘,999) 16 # print(p1.name) # 外部已經訪問不到該屬性了 17 p1.tell_info() 18 p1.reset_info(‘瓶蓋‘,9) # 通過類內部定義的特定接口來更改數據 19 p1.tell_info()
二、property
property 將被裝飾的方法偽裝成一個數據屬性,這樣在使用時就可以不用加括號而直接引用。
class People: def __init__(self,name,height,weight): self.name=name self.weight=weight self.height=height @property def BMI(self): return self.weight/(self.height**2) p=People(‘黃山‘,1.7,75) print(p.BMI) # 可以不用加括號而直接調用property
1 class People: 2 def __init__(self,name): 3 self.__name=name 4 5 # 將name函數偽裝成一個普通的數據屬性 6 @property # 查看obj.name 7 def name(self): 8 return ‘your name is %s‘ %self.__name 9 10 @name.setter # 修改obj.name的值 11 def name(self,name): 12 if type(name) is not str: 13 raise NameError(‘your name must be str ‘) 14 self.__name=name 15 # 相當於在類的內部提供了一個專門修改名字的接口 16 17 @name.deleter # 刪除obj.name 18 def name(self): 19 raise PermissionError(‘Deleting the name is not permission‘) 20 # del self.__name # 若要刪除obj.name這個屬性,可以註釋掉上面的raise error, 21 # 相當於在類的內部提供了一個專門刪除obj.name的接口 22 23 p=People(‘大佬‘) 24 print(p.name) # 可以不直接加括號而直接引用 25 26 # p.name=123 27 # print(p.name) #NameError: your name must be str 28 29 del p.name #NameError: your name must be str
三、綁定方法和非綁定方法
1.定義
1.1 綁定方法
綁定方法分成兩類:
1.1.1 綁定給對象
在類內部定義的函數且沒有被任何函數裝飾器修飾的,這種就是默認綁定給對象的
1.1.2 綁定給類
在類內部定義的函數如果被裝飾器@classmethod 裝飾的,這個函數就是綁定給類的,就應該由類來調用,類來調用就會將類當作第一個參數自動傳入。
1.1.3 綁定方法的特性:
綁定給誰就應該由誰來調用,誰來調用就會將誰當成第一個參數自動傳入<其精髓就在於:自動傳值>
1.2 非綁定方法
類中定義的函數如果被裝飾器@staticmethod 裝飾,那麽該函數就變成非綁定方法。
函數如果沒有被綁定,則意味著類和對象皆可調用,但無論誰來調用,都沒有自動傳值的效果,就是一個普通的函數,這種情況則應該傳入相應的參數。
2. 如何使用
如果函數體代碼需要使用外部傳入的類,則應該將函數定義成綁定成給類的方法
如果函數體代碼需要使用外部傳入的對象,則應該將函數定義成綁定給對象的方法
如果函數體代碼既不需要使用外部傳入的類,也不需要使用外部傳入的對象,那麽應該將函數定義成非綁定方法/普通函數。
1 import settings 2 import uuid 3 4 class Mysql(): 5 def __init__(self,ip,port): 6 self.uuid=self.create_uuid() 7 self.ip=ip 8 self.port=port 9 10 def get_info(self): 11 print(‘%s - %s‘%(self.ip,self.port)) 12 13 @classmethod 14 def from_settings(cls): 15 return cls(settings.ip,settings.port) 16 17 @staticmethod 18 def create_uuid(): # 非綁定方法,所以不需要參數 19 return uuid.uuid4() 20 21 # 默認的實例化方式 22 obj=Mysql(‘192.168.0.0‘,3306) 23 obj.get_info() # 這種情況下函數是已經執行了, 24 # 所以不必在用print(obj.get_info())了, 25 # 否則在輸出結果的同時,會收到一個函數的默認返回值 26 27 # 一種新的實例化方式,從配置文件中讀取出配置完成實例化 28 obj=Mysql.from_settings() 29 obj.get_info() 30 31 # 若函數是非綁定方法,則類和對象皆可調用 32 obj.create_uuid() 33 Mysql.create_uuid()小實例
ip=‘192.168.0.0‘ port=3306settings
封裝、property和綁定方法