getattr是python内置函数中的一个。其就在用方法是:getattr(object,“attribution”,None) ,一般情况我们这么用getattr(object,name)。一般来说这里的object是对象,name传的是字符串。对象又是什么呢?可以简单的理解为:在import 引入模块时,通过dir可查询的目标就是对像,而查询得到的结果就是属性,属性就是getattr用法中name部分传入的值。

一、getattr交互式理解

便于理解,我们先交互式的示例看下getattr的用法:

1>>> class test:
2...     cal=1
3...
4>>> getattr(test,"cal")
51
6>>> test.cal

上面这个结果很容易理解,cal是test类的一个属性。而如何理解对象呢?这里就用到了dir命令,具体如下:

1>>> dir(test)
2['__doc__', '__module__', 'cal']
3>>> getattr(test,__doc__)
4Traceback (most recent call last):
5  File "<stdin>", line 1, in <module>
6TypeError: getattr(): attribute name must be string
7>>> getattr(test,'__doc__')

上例中test是对象,可以传入的属性有查询到的三个结果。再看一个例子:

1>>> t = {}
2>>> t['a'] = "hello"
3>>> t['b'] = "world"
4>>> getattr(t,"a")
5Traceback (most recent call last):
6  File "<stdin>", line 1, in <module>
7AttributeError: 'dict' object has no attribute 'a'

上面t是一个字典,为什么传入a不行呢?因为a不是t的属性。t的属性有哪些呢?看下面:

1>>> dir(t)
2['__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的属性。我们试下

1>>> getattr(t,"__str__")
2<method-wrapper '__str__' of dict object at 0x1bbb230>
3>>> getattr(t,"__str__")()
4"{'a': 'hello', 'b': 'world'}"
5>>> t.__str__()
6"{'a': 'hello', 'b': 'world'}"

因为__str__ 是一个函数,所以在通过getattr调用出来执行后是一个内存地址,显示结果需要像调用函数一样加上括号。

二、__getattr__ 方法

在python中以开头,并以结尾的方法我们称之为魔术方法或专用方法,同样也存在一个getattr 方法。该方法是仅当属性不能在实例的dict或它的类(类的dict),或父类其dict中找到时,才被调用。一般在代码中包含一个对getattr()內建函数的调用。

每一个类都会用一个字典,把它包含的属性放到自己的字典里(这是内建的)。接着上面的例子,我们使用__dict__ 查看下返回值:

1>>> test.__dict__
2{'__module__': '__main__', '__doc__': None, 'cal': 1}

还是上面的test类,这里三个对象都以键值对的形式显示出来了。

再来个示例:

 1#!/usr/bin/env python
 2## site: www.361way.com
 3## desc: getattr and __getattr
 4class WrapMe(object):
 5    def __init__(self,obj):
 6        print "I am in init"
 7        self.__data = obj
 8    def get(self):
 9        print "I am in get"
10        return self.__data
11    def __repr__(self):
12        print "I am in repr"
13        return 'self.__data'
14    def __str__(self):
15        print "I am in str"
16        return str(self.__data)
17    def __getattr__(self, attr):
18        print "I am in getattr"
19        return getattr(self.__data, attr)
20if __name__ == "__main__":
21    wcomplex = WrapMe(3.5+4.2j)
22    print  wcomplex
23    print wcomplex.real
24    print wcomplex.get() 

执行该脚本后输出结果如下:

1I am in init
2I am in str
3(3.5+4.2j)
4I am in getattr
53.5
6I am in get
7(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方法输出即可。