Python入門 類class提高篇
一、python類中的訪問限制(常用)
1、屬性的訪問限制,Python私有屬性
Python類中有很多屬性,如果有些屬性不希望被外部訪問,我們可以屬性命名時以雙下劃線開頭(__),改屬性不能使用原變數名訪問,使屬性變為私有的(偽私有)。
但,如果一個屬性以"__xxx__"的形式定義,那它又可以被外部訪問了,以"__xxx__"定義的屬性在Python的類中被稱為特殊屬性,有很多預定義的特殊屬性可以使用,所以我們不要把普通屬性用"__xxx__"定義。
以單下劃線開頭的屬性"_xxx"雖然也可以被外部訪問(通過 _類名__xx 可以訪問到),但是,按照習慣,他們不應該被外部訪問,遵照編碼規範我們也不該在外部訪問 __xx 屬性。
如下圓類Circle的示例,我們將pi屬性開頭加上雙下劃線變成私有屬性:
class Circle(object):n __pi = 3.14nn def __init__(self, r):n self.r = rnn def area(self):n """n圓的面積n """n return self.r **2* self.__pinncircle1 = Circle(1)nprint(Circle.__pi) # 拋出AttributeError異常nprint(circle1.__pi) # 拋出AttributeError異常n
通過Circle.__pi與circle1.__pi訪問__pi時 都會出現AttributeError異常,證明訪問許可權已被控制。
那麼是不是我們就不能訪問__pi變數?
不是,其實還是可以訪問__pi ,可以通過 Circle._Circle__pi 訪問到__pi 屬性,為什麼能這麼訪問這裡不多講。
按照習慣,他們不應該使用Circle._Circle__pi 訪問到__pi屬性,這是編碼規範。
2、方法的訪問限制,Python私有訪問
同屬性的訪問限制,方法的訪問限制也是在方法名前加雙下劃線(__),它也是一種偽私有。
示例:
class Circle(object):n __pi = 3.14nn def __init__(self, r):n self.r = rnn def area(self):n """n圓的面積n """n return self.r**2 * self.__pinn def __girth(self):n """n圓的周長n """n return 2*self.r * self.__pinncircle1 = Circle(2)nprint(circle1.__girth()) # 拋出AttributeError異常n
私有化方法後我們只能在類的內部使用,不能被外部調用。
同屬性控制,方法需要訪問被限制的方法也是 _類名__xx 如circle1._Circle__girth()。
二、Python類中的@classmethod、@staticmethod 裝飾方法
@classmethod 用來修飾類方法。使用在與類進行交互,但不和其實例進行交互的函數方法上。
@staticmethod 用來修飾靜態方法。使用在有些與類相關函數,但不使用該類或該類的實例。如更改環境變數、修改其他類的屬性等。
兩者最明顯的區別,classmethod必須使用類的對象作為第一個參數,而staticmethod則可以不傳遞任何參數
1、@classmethod 類方法
類方法,我們不用通過實例化類就能訪問的方法。而且@classmethod 裝飾的方法不能使用實例屬性,只能是類屬性。它主要使用在和類進行交互,但不和其實例進行交互的函數方法上。
下面,我們要寫一個只在類中運行而不在實例中運行的方法。
簡單示例,讀取私有化類屬性數據,如下:
class Circle(object):n __pi = 3.14nn def __init__(self, r):n self.r = rnn @classmethodn def pi(self):n return self.__pinn def area(self):n """n圓的面積n """n return self.r ** 2 * self.__pinnprint(Circle.pi()) # 沒有實例化 能直接訪問pi() 方法ncircle1 = Circle(2)nprint(circle1.pi()) # 也可以通過實例訪問pi()方法n
Circle類下的pi()方法被 @classmethod 裝飾後,我們能通過Circle.pi() 直接運行方法,不用實例化類。
重構構造__init__() 方法應用示例:
class Date(object):n day = 0n month = 0n year = 0nn def __init__(self, year=0, month=0, day=0):n self.day = dayn self.month = monthn self.year = yearnn @classmethodn def from_string(cls, date_as_string):n year, month, day = date_as_string.split(-)n date = cls(year, month, day)n return datenndate1 = Date.from_string(2017-10-17) # 直接使用固定格式的字元串就能創建Date的實例nprint(date1.year, date1.month, date1.day)n
from_string 返回的是Date類的實例,所以我們可以通過from_string 實例化類。
注意:from_string(cls, date_as_string)中cls表示的是類,它和self類實例有一定的差別。類方法中都是使用cls,實例方法中使用self。
2、@staticmethod 靜態方法
@staticmethod 和@classmethod非常的相似,但是@staticmethod 不強制要求傳遞參數(它做的事與類方法或實例方法一樣)。
@staticmethod使用在有些和類相關函數,但不使用該類或者該類的實例。如更改環境變數、修改其他類的屬性等。
一句話@staticmethod 修飾的方法是放在類外的函數,我們為了方便將他移動到了類裡面,它對類的運行無影響。
class Date(object):n day = 0n month = 0n year = 0nn def __init__(self, year=0, month=0, day=0):n self.day = dayn self.month = monthn self.year = yearnn @classmethodn def from_string(cls, date_as_string):n year, month, day = date_as_string.split(-)n date = cls(year, month, day)n return datenn @staticmethodn def is_date_valid(date_as_string):n """n 用來校驗日期的格式是否正確n """n year, month, day = date_as_string.split(-)n return int(year) <= 3999 and int(month) <= 12 and int(day) <= 31nndate1 = Date.from_string(2012-05-10)nprint(date1.year, date1.month, date1.day)nis_date = Date.is_date_valid(2012-09-18) # 格式正確 返回Truen
is_date_valid(date_as_string) 只有一個參數,它的運行不會影響類的屬性,
注意:@staticmethod修飾方法 is_date_valid(date_as_string)中無實例化參數self或者cls;而@classmethod修飾的方法中有from_string(cls, date_as_string) 類參數cls。
三、Python 的 property使用
property的有兩個作用
- 作為裝飾器 @property將類方法轉換為類屬性(只讀)
- property重新實現一個屬性的setter和getter方法
1、@property將類方法轉換為只讀屬性(常用)
使用property的最簡單的方法是將它作為裝飾器來使用。這可以讓你將一個類方法轉變成一個類屬性。
示例:
class Circle(object):n __pi = 3.14nn def __init__(self, r):n self.r = rnn @propertyn def pi(self):n return self.__pinncircle1 = Circle(2)nprint(circle1.pi)ncircle1.pi=3.14159 # 出現AttributeError異常n
上面示例裝飾了pi方法,創建實例後我們可以使用circle1.pi 自己獲取方法的返回值,而且他只能讀不能修改。
2、property重新實現setter和getter方法(少用)
示例1:(用得較少)
class Circle(object):n __pi = 3.14nn def __init__(self, r):n self.r = rnn def get_pi(self):n return self.__pinn def set_pi(self, pi):n Circle.__pi = pinn pi = property(get_pi, set_pi)nncircle1 = Circle(2)ncircle1.pi = 3.14 # 設置 pi的值nprint(circle1.pi) # 訪問 pi的值n
正如你所看到的,當我們以這種方式使用屬性函數時,它允許pi屬性設置並獲取值本身而不破壞原有代碼。讓我們使用屬性裝飾器來重寫這段代碼,看看我們是否能得到一個允許設置的屬性值。
示例2:(用得比示例1多)
class Circle(object):n __pi = 3.14nn def __init__(self, r):n self.r = rnn @propertyn def pi(self):n return self.__pinn @pi.settern def pi(self, pi):n Circle.__pi = pinncircle1 = Circle(2)ncircle1.pi = 3.14 # 設置 pi的值nprint(circle1.pi) # 訪問 pi的值n
把一個getter方法變成屬性,只需要加上@property就可以了,如上此時pi(self)方法,@property本身又創建了另一個裝飾器@pi.setter,負責把一個setter方法變成屬性賦值,於是,將@pi.setter加到pi(self, pi)上,我們就擁有一個可控的屬性操作。
推薦閱讀:
※抓取60000+QQ空間說說做一次數據分析
※利用 Python 打造反向 TCP 後門
※基於pytesseract的簡單驗證碼識別
※快收藏了!GitHub 上最火最值得看的 Python 開源項目
※Python入門到精通視頻課程(10)