關於隱藏屬性
引子:
當類的屬性或者類實例對象的屬性隱藏的時候必須通過存取器方法來獲取和設置這些隱藏的屬性。
例如:
def get_name(self,name): #存取器方法
self._name=name
通過外部調用實例函數傳參達到獲取和設置隱藏屬性的目的。這樣的函數叫做存取器
缺點:是必須通過調用存取器方法來實現這些功能
為此python提供了更強大的特性函數,即property函數
(1)property()函數
例如:
name=property(get_name,set_name)
property函數封裝了get_name,set_name存取器方法,在類的外部可以像其他沒隱藏的屬性一樣操作屬性
實際上,property是一個類,它的實例包含了一些魔法方法,上述例子name=property()就是它的一個實例對象,這個實例對象實現了隱藏屬性的反隱藏
property還可以通過修飾器的形式實現這個功能
(2)@property裝飾器
實現其他語言所擁有的getter,setter和deleter的功能(例如IOS蘋果開發,實現獲取,設置,刪除隱藏的屬性)
作用:
用來模擬一個屬性
(其實‘模擬’這個說法不是很准確,官方這么說就這么用了,應該說重寫更合適,因為模擬前后的屬性是同一個屬性,用id()函數獲取的地址值是相同的)
通過@property裝飾器可以對模擬屬性的取值和賦值加以控制
例如:
__雙下划線隱藏的屬性可以被控制在外部修改
@property (實現getter取值)
def score(self):
return self.__score 返回隱藏的屬性
(score看似是一個實例函數,其實是一個屬性,因為它已經被property裝飾器裝飾了)
@score.setter (實現設置值,必須寫成setter,因為python就是這么規定的)
def score(self,v):
assert 0<=v<=100,‘成績不合法’
self.__score=v
@score.deleter
def.score(self): (實現刪除值)
del self.__socre
注意:
屬性一旦刪除,就無法設置和獲取
為什么用properyt函數?
property通常用在類或者子類中對隱藏屬性的改寫,類的代碼可能有幾千行,隱藏屬性在內部調用的次數可能就有幾百次,如果一個個修改很麻煩,用存取器方法和property函數可以很方便的實現隱藏屬性的反隱藏
另外python還有一種處理隱藏屬性的方法,不過這個知識點比較晦澀難懂
(3)python的類內部有__getattr__,__setattr__,__delattr__魔法方法,能攔截所有的類屬性
例如:
a.name
當在類的外部訪問不到隱藏的屬性時候,__getattr__會被自動調用,它搜索所的類屬性,直到找到隱藏的屬性
在類內__getattr__這些魔法方法是可以重寫的(重寫還是比較復雜的)
class A;
def __getattr__(self,name): #這里的形參name是屬性名的意思,不是類屬性self.name的那個name
if name=‘name’:
return self.__name
else:
raise AttributeError()
這里要寫一個判斷,目的是為了當找不到屬性時候(類里面根本就沒有這個屬性,無論是否是隱藏的屬性),就直接報錯,避免__getattr__一直不停地搜尋下去,形成死循環
在交互模式下用help(list.__getattribute__)查看__getattr__或者__getattribute__的工作原理如下:
__getattribute__(self, name, /)
Return getattr(self, name)
它是返回python的內建函數getattr(),即不斷地查詢類內的所有屬性
class A;
def __setattr__(self,name,value):
if name=‘name’:
self.__name=name
else:
self.__dict__[name]=value
這里設置判斷,如果沒有這個屬性,就直接用__dict__[name]=name來給類實例增加一個屬性,避免死循環
所以總結一下,用魔法方法__getattr__這類方法比用property屬性方法相比更復雜點,建議處理同類問題的時候用property屬性方法更好
