Home >Backend Development >Python Tutorial >python descriptor descriptor(2)
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 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'
Old code using this class will use the class attribute oldname, and a warning message will be printed to encourage the user to use the new attribute newname.
Cache attribute values
Calculate the value of instance attributes or class attributes based on requirements and provide automated caching.
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): C iF Instance is None:
Return Self
Result = Self.method (Instance)
Setattr (Instance, Self.name, Result) Return Result
Class MyObject (Object): I 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
on first visit m After .square, the square attribute is cached in instance m. When the instance attribute n is changed, the square attribute will not change. If you need to clear the cache, just del m.square. If you access the m.square attribute square again, the value of square will be calculated again.
Cache class attributes:
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
All instances of this class have the same cached value:
>>> a=MyClass()
>>> b=MyClass()
>>> print a.square
576>>> print b.square
576
> >> print MyClass.square
576
The above is the content of the python descriptor descriptor (2). For more related content, please pay attention to the PHP Chinese website (www.php.cn)!