Home  >  Article  >  Backend Development  >  python descriptor descriptor(2)

python descriptor descriptor(2)

黄舟
黄舟Original
2016-12-23 17:38:571169browse

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:

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


All instances of this class have the same cached value:

>>> a=MyClass()
>>> b=MyClass()

>>> a.square

>>> 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 (m.sbmmt.com)!


Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn