getattr是python内置函数中的一个。其就在用方法是:getattr(object,“attribution”,None) ,一般情况我们这么用getattr(object,name)。一般来说这里的object是对象,name传的是字符串。对象又是什么呢?可以简单的理解为:在import 引入模块时,通过dir可查询的目标就是对像,而查询得到的结果就是属性,属性就是getattr用法中name部分传入的值。
一、getattr交互式理解
便于理解,我们先交互式的示例看下getattr的用法:
>>> class test: ... cal=1 ... >>> getattr(test,"cal") 1 >>> test.cal
上面这个结果很容易理解,cal是test类的一个属性。而如何理解对象呢?这里就用到了dir命令,具体如下:
>>> dir(test) ['__doc__', '__module__', 'cal'] >>> getattr(test,__doc__) Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: getattr(): attribute name must be string >>> getattr(test,'__doc__')
上例中test是对象,可以传入的属性有查询到的三个结果。再看一个例子:
>>> t = {} >>> t['a'] = "hello" >>> t['b'] = "world" >>> getattr(t,"a") Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'dict' object has no attribute 'a'
上面t是一个字典,为什么传入a不行呢?因为a不是t的属性。t的属性有哪些呢?看下:
>>> dir(t) ['__class__', '__cmp__', '__contains__', '__delattr__', '__delitem__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setitem__', '__sizeof__', '__str__', '__subclasshook__', 'clear', 'copy', 'fromkeys', 'get', 'has_key', 'items', 'iteritems', 'iterkeys', 'itervalues', 'keys', 'pop', 'popitem', 'setdefault', 'update', 'values']
看到了吧,这里面没有“a”, __str__是t的属性。我们试下
>>> getattr(t,"__str__") <method-wrapper '__str__' of dict object at 0x1bbb230> >>> getattr(t,"__str__")() "{'a': 'hello', 'b': 'world'}" >>> t.__str__() "{'a': 'hello', 'b': 'world'}"
因为__str__ 是一个函数,所以在通过getattr调用出来执行后是一个内存地址,显示结果需要像调用函数一样加上括号。
二、__getattr__ 方法
在python中以__开头,并以__结尾的方法我们称之为魔术方法或专用方法,同样也存在一个__getattr__ 方法。该方法是仅当属性不能在实例的__dict__或它的类(类的__dict__),或父类其__dict__中找到时,才被调用。一般在代码中包含一个对getattr()內建函数的调用。
每一个类都会用一个字典,把它包含的属性放到自己的字典里(这是内建的)。接着上面的例子,我们使用__dict__ 查看下返回值:
>>> test.__dict__ {'__module__': '__main__', '__doc__': None, 'cal': 1}
还是上面的test类,这里三个对象都以键值对的形式显示出来了。
再来个示例:
#!/usr/bin/env python ## site: www.361way.com ## desc: getattr and __getattr class WrapMe(object): def __init__(self,obj): print "I am in init" self.__data = obj def get(self): print "I am in get" return self.__data def __repr__(self): print "I am in repr" return 'self.__data' def __str__(self): print "I am in str" return str(self.__data) def __getattr__(self, attr): print "I am in getattr" return getattr(self.__data, attr) if __name__ == "__main__": wcomplex = WrapMe(3.5+4.2j) print wcomplex print wcomplex.real print wcomplex.get()
执行该脚本后输出结果如下:
I am in init I am in str (3.5+4.2j) I am in getattr 3.5 I am in get (3.5+4.2j)
执行过程分析如下:
1、wcomplex = WrapMe(3.5+4.2j)该包执行时,会运行__init__将类实例化,会输出I am in init;
2、执行print wcomplex语句时调用的是__str__ 函数,此时输出I am in str (3.5+4.2j),后面的对象输出是因为调用了return str(self.__data);
3、real 属性由于不存在,所以执行时,这里便返回了__getattr__ 方法的内容。返回结果应该也不难猜到吧;
4、get方法更不用解释了。因为存在,按类中的get方法输出即可。