目錄python
封裝: 就是打包,封起來,裝起來,把你丟進袋子裏,而後用繩子把袋子綁緊,你還能拿到袋子裏的那我的嗎?函數
1.隱藏屬性和方法,外部(類的外部)沒法使用,內部(類額內部)可使用,在類定義階段就執行了,真的想引用,就使用_類名__屬性名學習
封裝分爲兩個層面:優化
第一個層面: 對象能拿到類的東西,可是類能拿到對象的東西嗎?編碼
class Foo(): count = 0 print(count) f = Foo() print(f.count) f.name = 'nick' # 對 對象進行了封裝,類拿不到對象的name print(Foo.name) # AttributeError: type object 'Foo' has no attribute 'name'
AttributeError
英文:屬性錯誤的意思code
第二個層面的: 內部(類的內部)可使用,外部(類的外部)不可使用,在你須要封裝的屬性前面加上__對象
# 之前定義變量並不會如下劃線開頭,如下劃線開頭的變量,好比隱藏屬性,或者如下劃線開頭方法,在某種狀況下會自動調用,好比__init__() lass People(): lover = 'male' print('in',lover) # 內部可用lover print('out',People.lover) # 外部可用lover # 屬性隱藏,在屬性前加__ class People(): __lover = 'male' print('in',__lover) # 內部可用__lover # print('out',People.__lover) # 外部不能夠用__lover print('out',People._People__lover) # out male 若是你真的要拿,_類名__屬性去拿(不可能這樣作) # 函數隱藏,在函數前加__函數名 # 正常 class People(): def eat(self): print('eat') People.eat(111) # 類調用,須要傳參 pe = People() pe.eat() # 隱藏方法 class People(): __love_people = 'male' # print('in',love_people) 報錯 # print('in',__love_people) 報錯 # 定義一個吃飯的流程:拿碗,拿筷子,吃飯 def __nawan(self): print('nawan') def __nakuaizi(self): print('nakuaizi') def __chifan(self): print('chifan') def chifan_all(self): # 吃飯 self.__nawan() self.__nakuaizi() self.__chifan() # print('out',People.__nawan(11)) # 報錯,不能夠引用內部的__nawan函數,函數進行了隱藏 p = People() # print('out',p.nawan()) # print('out',p.nakuaizi()) # print('out',p.chifan()) print('out',p.chifan_all())
2.隱藏模塊內的函數/變量 _x: from module import * (沒法導入),from module import _x(不合理)it
# 正常狀況下 # m1.py x= 10 def f1(): print('from f1') # m2.py from m1 import x # from m1 import * print(x) f1() #如今對模塊內的函數/變量 進行隱藏 # m1.py _x= 10 def __f1(): print('from f1') # m2.py from m1 import _X,__f1 (能夠導入_x,__f1,可是不合理,變量/函數前面加_或者__都行,主要原模塊m1中變量或者函數名寫成什麼樣,m2單獨導入就導什麼樣) # from m1 import * (導不出_x,__f1) ,除掉註釋,下面兩行代碼都會報錯 print(_x) # 能夠導入 __f1() # 能夠導入
對屬性這個封裝有什麼用:藏起來了,保護了你的隱私,類內部的屬性不想讓其餘人訪問io
對方法封裝有什麼好處:精簡了代碼,你吃飯就使用chifan_all這個方法就能夠了,不須要去關心其餘的操做,而且外部調用者也不知道你內部發生了什麼function
作一個小練習,理解封裝其實在定義階段就已經執行了,會把私有屬性__f1變成 _Foo__f1,以後都不會作這種處理
class Foo: def __f1(self): print('Foo.f1') def f2(self): print('_Foo__f1') self.__f1() print(Foo.__dict__) #注意字典中 __f1 變成了什麼,_Foo__f1 {'__module__': '__main__', '_Foo__f1': <function Foo.__f1 at 0x00000231DCBE0488>, 'f2': <function Foo.f2 at 0x00000231DCBE0510>, '__dict__': <attr class Bar(Foo): def __f1(self): print('Bar.f1') bar = Bar() # 實例化一個對象 bar.f2() # 對象bar中找f2,沒有,而後Bar類也沒有,去父類Foo找,找到f2,打印 _Foo__f1,再執行self.__f1(),self是對象,對象有__f1,打印 Bar.f1 bar.f2() # _Foo__f1,Bar.f1
class Foo(): __count = 0 foo = Foo() print(foo) foo.__y = 1 # 給對象foo添加屬性__y print(foo.__y) # 1
@property : 被@property 裝飾的函數會從函數變成屬性,也就是說直接 .函數名,不須要加括號使用
# BMI class People(): def __init__(self,height,weight): self.height = height self.weight = weight @property def bmi(self): return self.weight/(self.height**2) peo = People(1.8,70) print(peo.height) # print(peo.bmi()) 沒用 @property的時候須要這樣寫 print(peo.bmi)
@方法名.setter : 被@方法名.setter 裝飾的函數,方法名修改,會執行這個裝飾的函數
@方法名.deleter: 被@方法名.deleter 裝飾的函數,方法名刪除,會執行這個裝飾的函數
# 裝飾器用法(只在Python3中使用) class People(): def __init__(self,height,weight): self.height = height self.weight = weight @property # 獲取值的時候觸發,你不須要加括號使用,不能加參數 def bmi(self): return self.weight/(self.height**2) @bmi.setter # 在修改bmi的時候觸發,必須得加參數 def bmi(self, value): print(f'你已經成功修改成{value}') @bmi.deleter # 在刪除bmi的時候觸發,不能加參數 def bmi(self): print('delter') peo = People(1.8,70) print(peo.bmi) print('*'*50) peo.bmi = 50 print('*'*50) del peo.bmi
綁定方法: 綁定的方法
1.對象的綁定方法:沒有加任何裝飾的方法就是對象的綁定方法
2.類的綁定方法: 加了@classmethod裝飾器的方法就是類的綁定方法
3.非綁定方法: 加了@staticmethod裝飾器的方法就是非綁定方法,其實就是一個普通的函數
@property 讓函數方法 bmi() 變成屬性,
@bmi.setter 和 @bmi.deleter 讓這個函數方法 bmi() 能夠進行屬性同樣的修改和刪除,
因此 @bmi.setter 和 @bmi.deleter 裝飾的函數方法名必須是property裝飾的函數方法名bmi(),而不能夠是隨意定義的函數名字,若是換成其餘名字會報錯,顯示的就是該屬性(實際是個函數)沒法進行修改或刪除。
隨意定義函數方法名是 類屬性方法使用property 能夠擁有的
class Foo: # 綁定給對象,只有對象能用,可是類也能使用,使用的時候必須得傳參 def f1(self): print(self) @classmethod # 讓被裝飾的函數給類使用,約定俗稱參數爲cls # 綁定給類的方法,類能使用,對象也可使用,可是參數依然是類 def f2(cls): print(cls) # 什麼都不綁定的,非綁定方法,定義了普通的函數 @staticmethod def f3(self): print(self) f = Foo() f.f1() Foo.f1(1111) print('*' * 50) Foo.f2() f.f2() print('*'*50) Foo.f3(2222) f.f3(2222) # f爲對象,但f3爲普通函數,該傳什麼參就傳什麼參
<__main__.Foo object at 0x000002C80DCBC828> 1111 ************************************************** <class '__main__.Foo'> <class '__main__.Foo'> ************************************************** 2222 2222
🌸🌸🌸🌸🌸🌸🌸🌸🌸🌸
學習python已有月把時間,強烈推薦小夥伴們要開始培養本身優化代碼的思惟了
《編寫高質量代碼:改善python程序的91個建議》
《編寫高質量python代碼的59個有效方法》--》改善代碼的風格
《流暢的python》--》面向對象
以上三本書看不懂的跳過,是潛移默化去薰陶編碼的思惟,代碼寫得更精簡優美,不要去深究,若是想深刻,之後有時間再探究😂