类-封装
定義:隱藏對象的屬性和實現(xiàn)細(xì)節(jié),僅對外提供公共訪問方式。
【封裝原則】
????? 1. 將不需要對外提供的內(nèi)容都隱藏起來;
????? 2. 把屬性都隱藏,提供公共方法對其訪問。
在python中用雙下劃線開頭的方式將屬性隱藏起來(設(shè)置成私有的)
?
1)私有變量和私有方法
私有變量其實就是一種變形操作,類中所有的雙下劃線名稱如__x變成_類名__x。
#其實這僅僅這是一種變形操作 #類中所有雙下劃線開頭的名稱如__x都會自動變形成:_類名__x的形式:class A:__N=0 #類的數(shù)據(jù)屬性就應(yīng)該是共享的,但是語法上是可以把類的數(shù)據(jù)屬性設(shè)置成私有的如__N,會變形為_A__Ndef __init__(self):self.__X=10 #變形為self._A__Xdef __foo(self): #變形為_A__fooprint('from A')def bar(self):self.__foo() #只有在類內(nèi)部才可以通過__foo的形式訪問到.#A._A__N是可以訪問到的,即這種操作并不是嚴(yán)格意義上的限制外部訪問,僅僅只是一種語法意義上的變形這里想訪問到+雙下劃線的變量有以下方法:1,首先調(diào)用bar方法,2,在外面用_A__N 或者_(dá)A__x才能找到。
而且在pytharm里面,會變顏色,那是因為pytharm自身的機(jī)制導(dǎo)致,但是并沒有錯 class Person:def __init__(self,name,height,weight,sex):self.name=nameself.__height=heightself.weight=weightself.sex=sexdef tell_bmi(self):return self.weight/self.__height**2def tell_height(self,new_height):if new_height>20:self.__height=new_height egg=Person('egon',176,68,'male') egg._Person__height==80 print(egg._Person__height) print(egg.tell_bmi()) print(egg._Person__height) egg.tell_height(50) print(egg._Person__height) print(egg.tell_bmi())
如果是在類里面訪問私有變量,那就和私有變量一樣加上雙下劃線就行,但是在類外面那就必須是_類名__變量名的方法。
這種自動變形的特點:
1.類中定義的__x只能在內(nèi)部使用,如self.__x,引用的就是變形的結(jié)果。
2.這種變形其實正是針對外部的變形,在外部是無法通過__x這個名字訪問到的。
3.在子類定義的__x不會覆蓋在父類定義的__x,因為子類中變形成了:_子類名__x,而父類中變形成了:_父類名__x,即雙下滑線開頭的屬性在繼承給子類時,子類是無法覆蓋的。
?2)在父類里如果不想讓子類用自己的方法,那么就加上雙下劃線。如:
class A:def __fa(self): #這里一開始就已經(jīng)是_A__faprint('in A')def text(self):self.__fa() class B:def __fa(self): #這里是_B__faprint('in B) b=B() b.text所以當(dāng)b開始實例化B后,調(diào)用b.text運行self.__fa()時,這里的__fa就是_A__fa,所以子類B是釣不到的。3)property的用法,是一個裝飾器。
class Bmi:def __init__(self,name,height,weight):self.name=nameself.height=heightself.weight=weight@propertydef tell_bmi(self):return self.weight/self.height**2 b=Bmi('egon',1.75,70) print(b.tell_bmi)這里有個知識點,屬性和方法,以上面的print(b.tell_bmi)為例,這句話的意思是:輸出b對象的tell_bmi屬性,方法一個計算式,
2個直觀的辨別方法是 屬性沒有括號,而計算調(diào)用的話要加()。
求圓環(huán)的面積和周長就可以按照下面的辦法求
from math import pi class Circle:def __init__(self,outradius,inradius):# outrad=max(outradius,inradius)# inrad=min(outradius,inradius)self.outradius=max(outradius,inradius)self.inradius=min(outradius,inradius)@propertydef perimeter(self):return self.outradius*2*pi+self.inradius*2*pi@propertydef area(self):return self.outradius**2*pi-self.inradius**2*pi l1=Circle(20,10) print(l1.perimeter) print(l1.area) 圓的周長和面積為什么要用property
將一個類的函數(shù)定義成特性以后,對象再去使用的時候obj.name,根本無法察覺自己的name是執(zhí)行了一個函數(shù)然后計算出來的,這種特性的使用方式遵循了統(tǒng)一訪問的原則
from urllib.request import urlopen class Web_page:def __init__(self,url):self.url=urlself.count=None@propertydef content(self):if self.count:return self.countelse:self.count=urlopen(self.url).read()return self.countf=Web_page('https://www.baidu.com/') print(f.content) 打印網(wǎng)站功能,并且有緩存開始把網(wǎng)站的東西放進(jìn)去,當(dāng)你要用到的時候再拿出來,
緩存額概念就是你沒有的時候先下載,下載后等別人要再用的時候再把內(nèi)存里的拿出來就行,而不是再重新下載。
class Foo:def __init__(self,val):self.__NAME=val #將所有的數(shù)據(jù)屬性都隱藏起來 @propertydef name(self):return self.__NAME #obj.name訪問的是self.__NAME(這也是真實值的存放位置) @name.setterdef name(self,value):if not isinstance(value,str): #在設(shè)定值之前進(jìn)行類型檢查raise TypeError('%s must be str' %value)self.__NAME=value #通過類型檢查后,將值value存放到真實的位置self.__NAME @name.deleterdef name(self):raise TypeError('Can not delete')f=Foo('egon') print(f.name) # f.name=10 #拋出異常'TypeError: 10 must be str' del f.name #拋出異常'TypeError: Can not delete' property?
轉(zhuǎn)載于:https://www.cnblogs.com/52forjie/p/7366948.html
總結(jié)