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
    

      

  • 相关阅读:
    POJ 3468 A Simple Problem with Integers
    BZOJ 4430 Guessing Camels
    POJ 2309 BST
    POJ 1990 MooFest
    cf 822B Crossword solving
    cf B. Black Square
    cf 828 A. Restaurant Tables
    Codefroces 822C Hacker, pack your bags!
    [HDU 2255] 奔小康赚大钱
    [BZOJ 1735] Muddy Fields
  • 原文地址:https://www.cnblogs.com/linxiyue/p/3857650.html
Copyright © 2011-2022 走看看