美文网首页
__getattr__使用

__getattr__使用

作者: 流光汐舞 | 来源:发表于2018-05-30 14:41 被阅读0次

正文

__getattr__函数的作用: 如果属性查找(attribute lookup)在实例以及对应的类中(通过__dict__)失败, 那么会调用到类的__getattr__函数, 如果没有定义这个函数,那么抛出AttributeError异常。由此可见,__getattr__一定是作用于属性查找的最后一步,兜底。

我们来看几个例子:

第一个例子,很简单但经典,可以像访问属性一样访问dict中的键值对。

class ObjectDict(dict):
    def __init__(self, *args, **kwargs):
        super(ObjectDict, self).__init__(*args, **kwargs)

    def __getattr__(self, name):
        value =  self[name]
        if isinstance(value, dict):
            value = ObjectDict(value)
        return value

if __name__ == '__main__':
    od = ObjectDict(asf={'a': 1}, d=True)
    print od.asf
    print od.asf.a
    print od.d
image.png

第二个例子,对象属性的lazy initialize。

class WidgetShowLazyLoad(object):
    def fetch_complex_attr(self, attrname):
        '''可能是比较耗时的操作, 比如从文件读取'''
        return attrname

    def __getattr__(self, name):
        if name not in self.__dict__:
             self.__dict__[name] = self.fetch_complex_attr(name) 
        return self.__dict__[name]

if __name__ == '__main__':
    w = WidgetShowLazyLoad()
    print 'before', w.__dict__
    a=w.lazy_loaded_attr
    print 'after', w.__dict__
image.png

可以看到,属性访问前对象中的__dict__没有任何元素,访问之后就有添加。

这个例子是类实例的属性的惰性初始化,bottle里面也有一个用descriptor实现类属性的惰性初始化。

import functools
class lazy_attribute(object):
    """ A property that caches itself to the class object. """

    def __init__(self, func):
        functools.update_wrapper(self, func, updated=[])
        self.getter = func

    def __get__(self, obj, cls):
        value = self.getter(cls)
        setattr(cls, self.__name__, value)
        return value

class Widget(object):
    @lazy_attribute
    def complex_attr_may_not_need(clz):
        print 'complex_attr_may_not_need is needed now'
        return sum(i*i for i in range(1000))

if __name__ == '__main__':
    print Widget.__dict__.get('complex_attr_may_not_need') 
    Widget.complex_attr_may_not_need 
    print Widget.__dict__.get('complex_attr_may_not_need') 
image.png

第三个例子,我觉的是最实用的,__getattr__使得实现adapter wrapper模式非常容易,我们都知道“组合优于继承”,__getattr__实现的adapter就是以组合的形式。

class adaptee(object):
    def foo(self):
        print 'foo in adaptee'
    def bar(self):
        print 'bar in adaptee'

class adapter(object):
    def __init__(self):
        self.adaptee = adaptee()

    def foo(self):
        print 'foo in adapter'
        self.adaptee.foo()

    def __getattr__(self, name):
        print 'name',name
        return getattr(self.adaptee, name)

if __name__ == '__main__':
    a = adapter()
    a.foo()
    a.bar()
image.png

如果adapter需要修改adaptee的行为,那么定义一个同名的属性就行了,其他的想直接“继承”的属性,通通交给__getattr__就行了

最后一个例子,实际用到__getattr__,本质上和第三个例子差不多

class AlgoImpA(object):
    def __init__(self):
        self.obj_attr = 'obj_attr in AlgoImpA'

    def foo(self):
        print 'foo in AlgoImpA'

    def bar(self):
        print 'bar in AlgoImpA'

class AlgoImpB(object):
    def __init__(self):
        self.obj_attr = 'obj_attr in AlgoImpB'

    def foo(self):
        print 'foo in AlgoImpB'

    def bar(self):
        print 'bar in AlgoImpB'

class Algo(object):
    def __init__(self):
        self.imp_a = AlgoImpA()
        self.imp_b = AlgoImpB()
        self.cur_imp = self.imp_a

    def switch_imp(self):
        if self.cur_imp == self.imp_a:
            self.cur_imp = self.imp_b
        else:
            self.cur_imp = self.imp_a

    def __str__(self):
        return 'Algo with imp %s' % str(self.cur_imp)


    def __getattr__(self, name):
        return getattr(self.cur_imp, name)


if __name__ == '__main__':
    algo = Algo()
    
    print algo
    print algo.obj_attr
    algo.foo()
    
    algo.switch_imp()
    
    print algo
    print algo.obj_attr
    algo.bar()
image.png

相关文章

  • __getattr__使用

    正文 __getattr__函数的作用: 如果属性查找(attribute lookup)在实例以及对应的类中(通...

  • python之 __getattr__、__getattr__、

    __getattr__内置使用点号获取实例属性属性如 s.name,自调用__getattr____setattr...

  • 小甲鱼045.魔法方法:属性访问

    super()的使用? 用于调用父类的方法 继承的语法 __getattr__(self,name) 定义当用户试...

  • 定制类

    __str__ __getattr__ __call()__

  • 第5节 正则表达式

    python中 找变量,先找字典__dict__ 找不到再使用__getattr__ ,这个行为定义在__geta...

  • __getattr__

    正常情况下,当我们调用类的方法或属性时,如果不存在,就会报错。 Python 有一个机制,那就是 __getatt...

  • python中常用的__xxx__特殊变量

    1、__getattr__ 2、__setattr__ 3、__slots__ slots详解 4、__str__...

  • python __getattr__

    __getattr__ 这是python里的一个内建函数,当调用的属性或者方法不存在时,该方法会被调用 调用不存在...

  • __getattr__与__call__的联合使用

    __getattr__可以定义那些访问对象没有的属性时候该做如何处理,但是如果访问对象没有的函数时该如何处理呢? 输出

  • 描述符

    描述符的应用 缓存 Django中ORM的QuerySet __get__,__getattr__和__getat...

网友评论

      本文标题:__getattr__使用

      本文链接:https://www.haomeiwen.com/subject/oigtsftx.html