python學習_day26_面向對象之封裝
1、私有屬性
(1)動態屬性
在python中用雙下劃線開頭的方式將屬性隱藏起來。類中所有雙下劃線開頭的名稱,如__x都會自動變形成:_類名__x的形式。這種自動變形的特點是:
a.類中定義的__x只能在內部使用,如self.__x,引用的就是變形的結果。b.這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字訪問到的。c.在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
class Teacher: def __init__(self,name,pswd): self.name=name self.__pswd=pswd #私有屬性 def func(self): print(self.__pswd) alex=Teacher(‘alex‘,‘3714‘) alex.func() # print(alex.__pswd) #私有屬性不可以通過此方式查看 print(alex._Teacher__pswd) #私有屬性外部查看的方式:_Teacher__pswd儲存
(2)靜態屬性
私有化的方式同樣為在屬性名前加雙下劃線,只能在內部進行使用,外部查看方式與動態屬性一樣。
class Teacher: __identifier=‘teacher‘ #私有靜態屬性 def __init__(self,name,pwd): self.name=name self.__pwd=pwd #私有屬性 deffunc(self): print(self.__pwd,Teacher.__identifier) print(Teacher._Teacher__identifier) #在外面查看靜態屬性方法 alex=Teacher(‘alex‘,‘1234‘) alex.__a=‘aaa‘ #在外部定義,並不會形成私有化,__a即為一個合法的正常變量名 print(alex.__dict__) #查看動態屬性字典,結果為:{‘name‘: ‘alex‘, ‘_Teacher__pwd‘: ‘1234‘, ‘__a‘: ‘aaa‘}
問題點總結:
(a).這種機制也並沒有真正意義上限制我們從外部直接訪問屬性,知道了類名和屬性名就可以拼出名字:_類名__屬性,然後就可以訪問了,如a._A__N。
(b).“__屬性”變形到“_類名__屬性”只在類的內部生效,在定義後的進行的近似私有化賦值操作,不會變形,為正常的賦值過程。
2、私有方法
私有化方法也只能在類的內部進行進行使用,有一些方法的返回值只是用來作為中間結果,可以進行私有化,如下例:
class Teacher: def __init__(self,name,pwd): self.name=name self.__pwd=pwd #私有屬性 def __func(self): #私有方法 return hash(self.__pwd) def login(self,password): return hash(password)==self.__func() alex=Teacher(‘alex‘,‘1234‘) ret=alex.login(‘2234‘) print(ret) #輸出結果為:False
在繼承中,父類如果不想讓子類覆蓋自己的方法,可以將方法定義為私有的。
class Foo: def __jinghong_sb(self): #變形為:_Foo__jinghong_sb print(‘Foo‘) class Son(Foo): def __jinghong_sb(self): #變形為:_Son__jinghong_sb print(‘Son‘) def func(self): self.__jinghong_sb() #變形為:_Son__jinghong_sb, son = Son() son.func() #結果為:son
3、property方法
實現類中的方法時,以查看類的屬性的方式進行,即將類中的方法看起來像屬性而不是方法。如下例:
#例1:
class Person: def __init__(self,name,height,weight): self.name = name self.__height = height self.__weight = weight @property def bmi(self): return self.__weight / (self.__height**2) jinghong = Person(‘景弘‘,1.8,94) print(jinghong.name,jinghong.bmi) #輸出結果:景弘 29.012345679012345
#例2: import math class Circle: def __init__(self,radius): self.radius=radius @property def area(self): return math.pi * self.radius**2 #計算面積 @property def perimeter(self): return 2*math.pi*self.radius #計算周長 c=Circle(10) print(c.radius) print(c.area) #可以向訪問數據屬性一樣去訪問area,會觸發一個函數的執行,動態計算出一個值 print(c.perimeter) #可以向訪問數據屬性一樣去訪問area,會觸發一個函數的執行,動態計算出一個值
將一個類的函數定義成特性以後,對象再去使用的時候obj.name,根本無法察覺自己的name是執行了一個函數然後計算出來的,這種特性的使用方式遵循了統一訪問的原則。以上不可以通過賦值對jinghong.bmi、c.area、c.perimeter進行更改。一個靜態屬性property本質就是實現了get,set,delete三種方法,具體實例如下:
class Shop: discount = 0.75 def __init__(self,name,price): self.name = name self.__price = price @property def price(self): return self.__price * Shop.discount @price.setter def price(self,new_price): self.__price = new_price @price.deleter def price(self): del self.__price apple = Shop(‘apple‘,5) print(apple.price) #獲取商品價格 print(apple.__dict__) #輸出結果:{‘name‘: ‘apple‘, ‘_Shop__price‘: 5} apple.price = 6 #修改商品原價 print(apple.price) print(apple.__dict__) #輸出結果:{‘name‘: ‘apple‘, ‘_Shop__price‘: 6} del apple.price #刪除商品原價 print(apple.__dict__) #輸出結果:{‘name‘: ‘apple‘}
註意:只有在屬性AAA定義property後才能定義AAA.setter,AAA.deleter,如上例且各屬性方法名需一樣,均為price。
4、classmethod和staticmethod
(1)普通方法:必須傳一個對象 可以使用對象的屬性和類的屬性
class A: def __init__(self,name): self.name = name def func(self): #普通方法,self為形式參數 print( self.name)
(2)類方法(classmethod):必須傳一個類,方法不需要使用對象的屬性,但可以使用類的屬性
class A: role = ‘a‘ @classmethod def class_method(cls): #類方法,cls代表類 print(cls.role) A.class_method() #輸出結果:a類名.方法名()調用
(3)靜態方法(staticmethod):沒有必須傳的參數,方法不需要用對象的屬性和類的屬性
class Staticmethod_Demo(): role = ‘dog‘ @staticmethod def func(): #靜態方法,不需要參數 print("a") Staticmethod_Demo.func() #調用方式:類名.方法名()
使用情況:不能將函數獨立的放在類外面 完全使用面向對象編程的時候,並且這個函數完全不需要依賴對象的屬性和類的屬性, 就可以用staticmethod裝飾這個函數。
python學習_day26_面向對象之封裝