zoukankan      html  css  js  c++  java
  • python描述符descriptor(二)

    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
    

      

  • 相关阅读:
    HDOJ-3635-Dragon Balls 解题报告
    HDOJ-1217-Arbitrage 解题报告
    C语言控制台窗口图形界面编程(总结)
    PC(win10)上搭建 kubernetes + docker 集群环境
    Hessian 2.0 序列化协议
    对响应式布局的理解
    常用链接集合
    dubbox升级dubbo的过渡方案:通过扩展dubbo的Protocol实现dubbo与dubbox的相互调用
    Wordpress部署 —— 基于Ubuntu、Mysql和Nginx
    关于27种常见设计模式的总结
  • 原文地址:https://www.cnblogs.com/linxiyue/p/3857650.html
Copyright © 2011-2022 走看看