python 描述符是一種建立託管屬性的方法。每當乙個屬性被查詢時,乙個動作就會發生。這個動作預設是get,set或者delete。不過,有時候某個應用可能會有
更多的需求,需要你設計一些更複雜的動作。最好的解決方案就是編寫乙個執行符合需求的動作的函式,然後指定它在屬性被訪問時執行。乙個具有這種功能的物件
稱為描述符。描述符是python方法,繫結方法,super,property,staticmethod和classmethod的實現基礎。
描述符descriptor就是乙個表示屬性值的物件,通過實現乙個或多個__get__,__set__,__delete__方法,可以將描述符與屬性訪問機制掛鉤,還可以自定義這些操作。
__get__(self,instance,own):用於訪問屬性,返回屬性的值。instance為使用描述符的例項物件,own為例項所屬的類。當通過類訪問屬性時,instance為none。
__set__(self,instance,value):設定屬性值。
__delete__(self,instance):刪除屬性值。
class descriptor(object):
def __get__(self, instance, owner):
print 'getting:%s'%self._name
return self._name
def __set__(self, instance, name):
print 'setting:%s'%name
self._name = name
def __delete__(self, instance):
print 'deleting:%s'%self._name
del self._name
class person(object):
name = descriptor()
乙個很簡單的描述符物件就產生了,現在可以對乙個person物件進行屬性name的讀取,設定和刪除:
>>> p=person()
>>> p.name='john'
setting:john
>>> p.name
getting:john
'john'
>>> del p.name
deleting:john
注意:描述符只能在類級別上進行例項化,不能通過在__init__()和其他方法中建立描述符物件來為每個例項建立描述符。
具有描述符的類使用的屬性名稱比例項上儲存的屬性名稱具有更高的優先順序。為了能讓描述符在例項上儲存值,描述符必須挑選乙個與它本身所用名稱不同的名稱。
如上例,person類初始化__init__函式為例項設定屬性就不能用name名稱了。
data描述符與none-data描述符:
如果實現了__get__和__set__就是乙個data描述符,如果只有__get__就是乙個non-data描述符。不同的效果在於data描述符總是替代在乙個例項中的屬性實現,
而non-data描述符由於沒有set,在通過例項對屬性賦值時,例如上面的p.name = 'hello',不會再呼叫__set__方法,會直接把例項屬性p.name設為'hello'。
當然如果僅僅在__set__中raise attributeerror,仍然得到的是乙個non-data的描述符。
描述符呼叫機制:
當查詢乙個物件的屬性a.attr時,如果python發現attr是個描述符物件,如何讀取屬性取決於物件a:
直接呼叫:最簡單的呼叫是直接使用**呼叫描述符的方法,attr.__get__(a)
例項繫結:如果a是個例項物件,呼叫方法:type(a).__dict__['attr'].__get__(a,type(a))
類繫結:如果a是個類物件,呼叫方法:a.__dict__['attr'].__get__(none,a)
super繫結:如果a是個super例項,那麼super(b,obj).m()通過查詢obj.__class__.__mro__找到b的基類a,然後執行a.__dict__['m'].__get__(obj,obj.__class__)
class typedproperty(object):
def __init__(self,name,attr_type,default=none):
self.name='_'+name
self.type=attr_type
self.default=default if default else attr_type()
def __get__(self,instance,own):
return getattr(instance,self.name,self.default)
def __set__(self,instance,value):
if not isinstance(value,self.type):
raise typeerror,'must be %s'%self.type
setattr(instance,self.name,value)
def __delete__(self,instance):
raise attributeerror('can not delete attribute')
class foo(object):
name=typedproperty('name',str)
num=typedproperty('num',int,37)
上述描述符可以對屬性的型別進行檢查,如果name屬性不設為str型別或者num不設為int型別,就會報錯:
>>> f.name=21
typeerror: must be
而且禁止對屬性進行刪除操作:
>>> del f.name
attributeerror: can not delete attribute
f.name **的呼叫type(f).__dict__['name'].__get__(f,foo),即foo.name.__get__(f,foo)。
上述描述符實際是儲存在例項上的,name通過setattr(f,_name,value)儲存在f._name上,num儲存在f._num上,這也是加下劃線的原因,
否則描述符名稱name會和例項屬性name發生衝突,描述符屬性f.name會覆蓋掉例項屬性f.name。
python 描述 python描述符
在python中,訪問乙個屬性的優先順序順序按照如下順序 1.類屬性2.資料描述符3.例項屬性4.非資料描述符5.getattr 方法。描述符,用一句話來說,就是將某種特殊型別的類的例項指派給另乙個類的屬性 注意 這裡是類屬性,而不是物件屬性 而這種特殊型別的類就是實現了 get set delet...
python 描述符基本
相關資料 python的描述符 下一站,我等你 描述符的本質類 python為開發者提供了乙個非常強大的功能 描述符。那什麼是描述符呢?通過檢視python的官方文件,我們知道把實現了 get set 和 delete 中的其中任意一種方法的類稱之為描述符,描述符的本質是新式類,並且被 的類 即應用...
Python 描述符練習
要求 先定義乙個溫度類,然後定義兩個描述符用於描述攝氏度和華氏度兩個屬性 要求這個兩個屬性會自動進行轉換,也就是說你可以給攝氏度這個屬性賦值,然後列印的話華氏屬性是自動轉換的結果 class celsius def init self,value 26.0 self.value float valu...