python反射与自省getattr入门篇

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方法输出即可。




本站的发展离不开您的资助,金额随意,欢迎来赏!

You can donate through PayPal.
My paypal id: itybku@139.com
Paypal page: https://www.paypal.me/361way

  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.