學(xué)習(xí)一下幾個內(nèi)容
- __getattr__和__setattr__方法,把未定義的屬性獲取和所有的屬性賦值指向通用的處理器方法
- __getattribute__方法纤房,把所有屬性都指向Python3.0中類的一個泛型處理器的方法
- property內(nèi)置函數(shù)鹃骂,把特定屬性訪問定位到get和set處理函數(shù)笨腥,也叫做特性(Property)
- 描述符協(xié)議撩独,把特定屬性訪問定位到具有任意get和set處理器方法的類的實例
特性協(xié)議允許我們把一個特定屬性的get和set操作指向我們所提供的函數(shù)或方法校读,使得我們能夠插入在屬性訪問的時候自動運行代碼。
*基礎(chǔ)知識
attribute = property(fget,fset,fdel,doc)
四個參數(shù)分別代表屬性attribute的get丧靡,set蟆沫,del方法和文檔性信息
#-*-coding:UTF-8-*-
class Person:
def __init__(self,name):
self._name = name
def getName(self):
print('fetch...')
return self._name
def setName(self,value):
self._name = value
print('change...')
def delName(self):
print('remove...')
del self._name
name = property(getName,setName,delName,'name property docs') #屬性name是通過property內(nèi)置函數(shù)創(chuàng)建的并提供一些方法操作name的值
if __name__ == '__main__':
bob = Person('Bob Smith')
print(bob.name) #調(diào)用getName方法 獲取name的值
bob.name = 'Robert Smth' #調(diào)用setName方法設(shè)置值
print(bob.name)
del bob.name
print(Person.name.__doc__)
####
fetch...
Bob Smith
change...
fetch...
Robert Smth
remove...
name property docs
[Finished in 0.3s]
像所有的類屬性一樣,實例和較低的子類都繼承特性温治。
class Coder(Person):
pass
if __name__ == '__main__':
bob = Coder('Bob Smith')
print(bob.name)
###
fetch...
Bob Smith
Coder子類從Person繼承了name特性
計算屬性
class PropSquare:
def __init__(self, start):
self.value = start
def getX(self):
return self.value**2
def setX(self,value):
self.value = value
X = property(getX,setX)
if __name__ == '__main__':
P = PropSquare(3)
Q = PropSquare(32)
print(P.X)
P.X = 4
print(P.X)
print(Q.X)
###
9
16
1024
說明可以在自定義的函數(shù)中做一些數(shù)據(jù)方面的處理
使用裝飾器來編寫特性
#-*-coding:UTF-8-*-
"""
@decorator
def func(args):...
相當于
def func(args):...
func = decorator(func)
"""
class Person:
def __init__(self, name):
self._name = name
@property
def name(self):
"""name property docs"""
print('fetch.....')
return self._name
@name.setter
def name(self,value):
print('change')
self._name = value
@name.deleter
def name(self):
print('remove...')
del self._name
if __name__ == '__main__':
rose = Person('Rose Jhon')
print(rose.name)
rose.name = 'Roose Jhon'
print(rose.name)
del rose.name
###
fetch.....
Rose Jhon
change
fetch.....
Roose Jhon
remove...
裝飾是編寫特性的替代方法饭庞。注意set和del方法的裝飾
描述符
描述符提供了攔截屬性訪問的一種替代方法。特性是描述符的一種熬荆,property內(nèi)置函數(shù)是創(chuàng)建一個特定類型描述符的一種簡化方法舟山。
描述符協(xié)議允許特性我們把一個特定屬性的get和set操作指向我們提供的一個單獨類對象的方法:他們提供了一種方式插入在訪問屬性的時候自動運行的代碼,并且他們允許我們攔截屬性刪除并且為屬性提供文檔卤恳。描述符作為獨立的類創(chuàng)建累盗,并且他們就像方法函數(shù)一樣分配給類屬性,也可以通過子類和實例繼承
*基礎(chǔ)知識
class Descriptor:
def __get__(self,instance,owner):...
def __set__(self,instance,value):...
def __delete__(self,instance):.....
帶有這些方法的類都可以看做是描述符突琳,并且當他們的一個實例分配給另一個類的屬性的時候幅骄,它們的這些方法是特殊的----當訪問屬性的時候,會自動調(diào)用它們本今。
描述符參數(shù):都傳遞了描述符類實例(self)以及描述符實例所附加的客戶類的實例(instance)。__get__訪問方法還額外的接收一個owner參數(shù)主巍,指定描述符實例要附加到的類冠息。
#-*-coding:UTF-8-*-
"""
描述符
"""
class Name:
def __get__(self,instance,owner):
print(self,instance,owner)
return instance._name
def __set__(self,instance,value):
print('change')
instance._name = value
def __delete__(self,instance):
print('remove')
del instance._name
"""
描述符生成的屬性
"""
class Person:
def __init__(self,name):
self._name = name
name = Name()
"""
self是Name類的實例
instance是Person類的實例
owner是Person類
"""
if __name__ == '__main__':
bob = Person('Jim Green')
print(bob.name)
bob.name = 'Jam Green'
del bob.name
###
<__main__.Name object at 0x00610FB0> <__main__.Person object at 0x00610FD0> <class '__main__.Person'>
Jim Green
change
remove
描述符的計算屬性
計算屬性
class DescSquare:
def __init__(self,start):
self.value = start
def __get__(self,instance,owner):
return self.value**2
def __set__(self,instance,value):
self.value = value
class Client1:
X = DescSquare(3) #類屬性 所有實例共享的 描述符類實例化的時候傳值
if __name__ == '__main__':
c1 = Client1()
print(c1.X)
print(Client1.X)
在描述符中使用狀態(tài)信息
- 描述符狀態(tài)用來管理內(nèi)部用于描述符工作的數(shù)據(jù)
- 實例狀態(tài)記錄了和客戶類相關(guān)的信息,以及可能有客戶類創(chuàng)建的信息
"""
描述符狀態(tài)信息
"""
class DescState:
def __init__(self,value):
self.value = value
def __get__(self,instance,owner):
print('DescState get')
return self.value*10
def __set__(self,instance,value):
print('DescState set')
self.value = value
class CalcAttrs:
X = DescState(2)
Y = 3
def __init__(self):
self.Z = 4
if __name__ == '__main__':
obj = CalcAttrs()
print(obj.X,obj.Y,obj.Z)
####
value屬性僅存在描述符中孕索,在CalcAttrs中使用value也不會沖突
對描述符存儲或使用附加到客戶類的實例的一個屬性逛艰,不是描述符類的屬性
class InsState:
def __get__(self,instance,owner):
print('InsState get')
return instance._Y*100
def __set__(self,instance,value):
print('InsState set')
instance._Y = value
class CalcAttrs1:
X = DescState(2)
Y = InsState()
def __init__(self):
self._Y = 3
self.Z = 4
if __name__ == '__main__':
obj = CalcAttrs1()
print(obj.X,obj.Y,obj.Z)
###
DescState get
InsState get
20 300 4
在運行的時候 會傳遞CalcAttrs1類的實例過去(instance)
在描述符類中instance._Y調(diào)用的就是obj的屬性。在obj.Y的時候 會調(diào)用 InsState實例Y中的__get__方法并傳遞相關(guān)參數(shù)過去
__getattr__和__getattribute__
- __getattr__針對未定義的屬性運行----也就是說搞旭,屬性沒有存儲在實例上散怖,或者沒有從父類之一繼承
- __getattribute__針對每個屬性菇绵,當使用時,需要小心避免通過把屬性訪問傳遞給超類而導(dǎo)致遞歸循環(huán)
def __getattr__(self,name): #On undefined attribute fetch [obj.name]
def __getattribute__(self,name):#on all attribute fetch [obj.name]
def __setattr__(self,name,value):#on all attribute assignment [obj.name=value]
def __delattr__(self,name): #on all attribute deletion [del obj.name]
其中self通常是主體實例對象镇眷,name是將要訪問的屬性的字符串咬最,value是要賦給該屬性的對象
例子
#-*-coding:UTF-8-*-
class Catcher:
def __getattr__(self,name):
print('Get:',name)
def __setattr__(self,name,value):
print('Set:',name,value)
def test(slef):
print('test')
class Wrapper:
def __init__(self,obj):
self.wrapper = obj
def __getattr__(self,attrname):
print('Trace:',attrname)
return getattr(self.wrapper,attrname)
if __name__ == '__main__':
X = Catcher()
X.job
X.pay = 99
Y = Wrapper(X)
Y.test()
###
Get: job
Set: pay 99
Trace: test
test
####
Catcher的實例X在調(diào)用X.job時,會遭到getattr方法的攔截(攔截沒有定義的屬性)
注意使用__setattr__和__getattribute__要避免循環(huán)
#-*-coding:UTF-8-*-
class Person:
def __init__(self,name):
self._name = name
# def __getattr__(self,attr):
# if attr == 'name':
# print('fetch....')
# return self._name
# else:
# raise AttributeError(attr)
def __getattribute__(self,attr):
if attr == 'name':
print('fetch')
attr = '_name'
return object.__getattribute__(self,attr)
def __setattr__(self,attr,value):
if attr=='name':
print('change...')
attr = '_name'
print(attr)
self.__dict__[attr] = value #避免循環(huán) 如果使用self._name = value會產(chǎn)生遞歸循環(huán)
def __delattr__(self,attr):
if attr == 'name':
print('remove...')
attr = '_name'
del self.__dict__[attr]
if __name__ == '__main__':
bob = Person('Bob Smith')
print(bob.name)
bob.name = 'Robert Smith'
print(bob.name)
del bob.name
print('-'*20)
sue = Person('Sue Jones')
print(sue.name)
- 構(gòu)造函數(shù)中的self._name = name會觸發(fā)__setattr__
__getattr__和__getattribute__比較
- __getattr__攔截未定義的屬性欠动,已經(jīng)定義的屬性不會攔截
- __getattribute__攔截所有的屬性獲取永乌,并且需要將沒有管理的屬性訪問指向超類獲取器以避免循環(huán)