python __getattr__

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

我们来看几个例子:

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

  

 1 class ObjectDict(dict):
 2     def __init__(self, *args, **kwargs):
 3         super(ObjectDict, self).__init__(*args, **kwargs)
 4
 5     def __getattr__(self, name):
 6         value =  self[name]
 7         if isinstance(value, dict):
 8             value = ObjectDict(value)
 9         return value
10
11 if __name__ == ‘__main__‘:
12     od = ObjectDict(asf={‘a‘: 1}, d=True)
13     print od.asf, od.asf.a     # {‘a‘: 1} 1
14     print od.d                 # True

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

  

 1 class WidgetShowLazyLoad(object):
 2     def fetch_complex_attr(self, attrname):
 3         ‘‘‘可能是比较耗时的操作, 比如从文件读取‘‘‘
 4         return attrname
 5
 6     def __getattr__(self, name):
 7         if name not in self.__dict__:
 8              self.__dict__[name] = self.fetch_complex_attr(name)
 9         return self.__dict__[name]
10
11 if __name__ == ‘__main__‘:
12     w = WidgetShowLazyLoad()
13     print ‘before‘, w.__dict__
14     w.lazy_loaded_attr
15     print ‘after‘, w.__dict__

输出:

before {}

after {‘lazy_loaded_attr‘: ‘lazy_loaded_attr‘}

可以看到,属性访问前对象中的__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‘)  # <__main__.lazy_attribute object at 0x02B12450>
    Widget.complex_attr_may_not_need                        # complex_attr_may_not_need is needed now
    print Widget.__dict__.get(‘complex_attr_may_not_need‘)  # 332833500

第三个例子,我觉的是最实用的,__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):
        return getattr(self.adaptee, name)

if __name__ == ‘__main__‘:
    a = adapter()
    a.foo()
    a.bar()

如果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()

输出:

Algo with imp <__main__.AlgoImpA object at 0x02AA2270>
obj_attr in AlgoImpA
foo in AlgoImpA
Algo with imp <__main__.AlgoImpB object at 0x02AA22B0>
obj_attr in AlgoImpB
bar in AlgoImpB

首先,Algo提供给使用者的接口应该尽量简单,因此应该使用algo.func, 而不是algo.cur_imp.func。其次,AlgoImpA和AlgoImpB都有很多的属性(泛指函数和数据属性),使用__getattr__能大幅简化代码。Why we use python,life is short。

references:

http://stackoverflow.com/questions/10761779/when-to-use-getattr

http://western-skies.blogspot.fr/2008/02/complete-example-of-getattr-in-python.html

时间: 2024-08-10 21:28:46

python __getattr__的相关文章

python __setattr__, __getattr__, __delattr__, __call__

python __setattr__, __getattr__, __delattr__, __call__ getattr `getattr`函数属于内建函数,可以通过函数名称获取 value = obj.attribute value = getattr(obj, "attribute") 使用`getattr`来实现工厂模式 #一个模块支持html.text.xml等格式的打印,根据传入的formate参数的不同,调用不同的函数实现几种格式的输出 import statsout

python 中__getattr__ 以及 __setattr__

python 中__getattr__ 以及 __setattr__ 下面是mydict.py: #!/usr/bin/env python class Dict(dict): def __init__(self, **kw): super(Dict, self).__init__(**kw) def __getattr__(self, key): try: return self[key] except KeyError: raise AttributeError(r"'Dict' objec

转载Python中__getattr__ __getattribute__ __get__解释

来源:http://www.myexception.cn/perl-python/620096.html python中__get__,__getattr__,__getattribute__的区别 __get__,__getattr__和__getattribute都是访问属性的方法,但不太相同. object.__getattr__(self, name) 当一般位置找不到attribute的时候,会调用getattr,返回一个值或AttributeError异常. object.__get

8.python之面相对象part.6(反射&__call__,__setattr__,__delattr__,__getattr__)

一.什么是反射? 反射,又被称为自省,主要是指程序本身可以访问,检测,和修改"自己",状态或行为的一种能力. 二.python是如何体现这种反射机制的? 通过字符串去操作对象相关的属性,python中,一切皆对象,所有的地方都可以用到反射. python内部提供了四个实现反射(自省)的函数,这四个函数可以适用于任何的类和对象(这是因为类本身也是一个对象!) 1.hasattr(object,str) 用来检测一个对象中是否有某个字符串对应的方法或者属性. 例如: l1 = [] pri

Python的getattr(),setattr(),delattr(),hasattr()及类内建__getattr__应用

@Python的getattr(),setattr(),delattr(),hasattr() 先转一篇博文,参考.最后再给出一个例子 getattr()函数是Python自省的核心函数,具体使用大体如下: 获取对象引用getattrGetattr用于返回一个对象属性,或者方法 class A: def __init__(self): self.name = 'zhangjing'   #self.age='24' def method(self): print"method print&quo

python Class:面向对象高级编程 __getattr__

官网解释: object.__getattr__(self, name) Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name. This method should ret

python自定义属性访问__setattr__, __getattr__, __setattribute__

object._getattr_(self, name) 实例instance通过instance.name访问属性name,只有当属性name没有在实例的__dict__或它构造类的__dict__或基类的__dict__中没有找到,才会调用__getattr__.当属性name可以通过正常机制追溯到时,__getattr__是不会被调用的.如果在__getattr__(self, attr)存在通过self.attr访问属性,会出现无限递归错误. class ClassA(object):

Python的魔法函数系列 __getattrbute__和__getattr__

  #!/usr/bin/env python # -*- coding: utf-8 -*- import sys __metaclass__ = type """ __getattr__ 和 __getattribute__ 的区别 """ class ClassName: def __init__(self, name, info={}): self.name = name self.info = info # def __getattri

Python的__getattr__和__getattribute__

__getattr____getattr__在当前主流的Python版本中都可用,重载__getattr__方法对类及其实例未定义的属性有效.也就属性是说,如果访问的属性存在,就不会调用__getattr__方法.这个属性的存在,包括类属性和实例属性. __getattribute____getattribute__仅在新式类中可用,重载__getattrbute__方法对类实例的每个属性访问都有效. 另外,当同时定义__getattribute__和__getattr__时,__getattr