python內建的描述符
python有些內建的描述符對象,PRoperty、staticmethod、classmethod,python實現如下:
class Property(object):
def __init__(self,getf,setf,delf,doc):
self.getf=getf
self.setf=setf
self.delf=delf
self.doc=doc
def __get__(self,instance,own=None):
if instance is None:
return self
if self.getf is None:
raise AttributeError
return self.getf(instance)
def __set__(self,instance,value):
if self.setf is None:
raise AttributeError
self.setf(instance,value)
def __del__(self,instance):
if self.delf is None:
raise AttributeError
self.delf(instance)
class StaticMethod(object):
def __init__(self,func):
self.func=func
def __get__(self,instance,own=None):
return self.func
class ClassMethod(object):
def __init__(self,func):
self.func=func
def __get__(self,instance,own=None):
if own is None:
own=type(instance)
def callfunc(*args):
return self.func(own,*args)
return callfunc
為屬性值設定別名
有時候你想用一個屬性名稱作為另一個屬性名稱的別名,比如設定一些屬性的預設值必須和其他屬性的當前值一樣,而且還需要獨立的設定和刪除。
class DefaultAlias(object):
def __init__(self,name):
self.name=name
def __get__(self,instance,own):
if instance is None: #類屬性訪問時
return self
return getattr(instance,self.name).title()
class Person(object):
def __init__(self,name,aliasname=None):
self.name=name
if aliasname is not None:
self.aliasname=aliasname
aliasname=DefaultAlias('name')
>>> p=Person('sam')
>>> p.aliasname
'Sam'
>>> p.aliasname='jack'
>>> p.aliasname
'jack'
>>> del p.aliasname
>>> p.aliasname
'Sam'
這樣就為屬性name設定了一個別名aliasname,或者說把aliasname的值儲存在了name中。DefaultAlias並不是資料描述符,因為它沒有__set__方法,而是一個non-data描述符。所以我們給一個執行個體屬性賦值時(p.aliasname='jack'),執行個體會正常地記錄屬性,而且執行個體屬性會覆蓋掉類屬性。這樣aliasname屬性就能單獨的設定而不影響name屬性了。當我們del p.aliasname時,刪除了執行個體的屬性,類屬性又會再次顯現出來。
對於某些開發的類,如果要保持後續版本的相容性,可以用新名稱來命名方法和屬性,同時保留舊名字的可用性。
class OldAlias(object):
def __init__(self,name,oldname):
self.name=name
self.oldname=oldname
def _warn(self):
print 'use %r,not %r'%(self.name,self.oldname)
def __get__(self,instance,own):
self._warn()
if instance is None:
return self
return getattr(instance,self.name)
def __set__(self,instance,value):
self._warn()
setattr(instance,self.name,value)
def __del__(self,instance):
self._warn()
delattr(instance,self.name)
class NewClass(object):
def __init__(self,newname):
self.newname=newname
oldname=OldAlias('newname','oldname')
>>> c=NewClass('a')
>>> c.oldname
use 'newname',not 'oldname'
'a'
使用這個類的舊代碼會使用類屬性oldname,同時一個警告資訊被列印,鼓勵使用者使用新屬性newname。
緩衝屬性值
根據需求計算執行個體屬性或類屬性的值,並提供自動化的緩衝。
class CachedAttribute(object):
def __init__(self,method,name=None):
self.method=method
self.name=name if name else method.__name__
def __get__(self,instance,own):
if instance is None:
return self
result=self.method(instance)
setattr(instance,self.name,result)
return result
class MyObject(object):
def __init__(self,n):
self.n=n
@CachedAttribute
def square(self):
return self.n*self.n
>>> m=MyObject(2)
>>> m.square
4
>>> m.n=5
>>> m.square
4
>>> del m.square
>>> m.square
25
在首次訪問m.square後,square屬性就被緩衝在執行個體m中,當改變執行個體屬性n時,square屬性不會改變。如果需要清除緩衝,del m.square即可,再次訪問m.square屬性square的值會被再次計算。
緩衝類屬性:
class CachedClassAttribute(CachedAttribute):
def __get__(self,instance,own):
return super(CachedClassAttribute,self).__get__(own,own)
class MyClass(object):
class_attr=24
@CachedClassAttribute
def square(cls):
return cls.class_attr*cls.class_attr
這樣類的所有執行個體都有同樣的緩衝值了:
>>> a=MyClass()
>>> b=MyClass()
>>> a.square
>>> print a.square
576
>>> print b.square
576
>>> print MyClass.square
576
以上就是python描述符descriptor(二)的內容,更多相關內容請關注topic.alibabacloud.com(www.php.cn)!