本文主要介绍Python中的反射和自省,以及该机制的简单应用
熟悉Java的程序员,一定经常和Class.forName打交道。即使不是经常亲自调用这个方法,但是在很多框架中(spring,eclipse plugin机制)都依赖于JAVA的反射和自省能力。而在python中,也同样有着强大的反射和自省能力,本文将做简单的介绍。
首先看一下自省,介绍一下几个重要的函数:
dir函数,传入的参数是对象,返回该对象的所有属性和函数列表:
如:
>>> import string >>> dir(string) [‘ChainMap‘, ‘Formatter‘, ‘Template‘, ‘_TemplateMetaclass‘, ‘__builtins__‘, ‘__cached__‘, ‘__doc__‘, ‘__file__‘, ‘__loader__‘, ‘__name__‘, ‘__package__‘, ‘__spec__‘, ‘_re‘, ‘_string‘, ‘ascii_letters‘, ‘ascii_lowercase‘, ‘ascii_uppercase‘, ‘capwords‘, ‘digits‘, ‘hexdigits‘, ‘octdigits‘, ‘printable‘, ‘punctuation‘, ‘whitespace‘] >>>
可以看到,string对象的所有函数,属性都列举出来了。
getattr方法,传入参数是对象和该对象的函数或者属性的名字,返回对象的函数或者属性实例,如下:
>>> getattr(string, ‘printable‘) ‘0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\‘()* +,-./:;<=>[email protected][\\]^_`{|}~ \t\n\r\x0b\x0c‘ >>>
callable方法,如果传入的参数是可以调用的函数,则返回true,否则返回false。
>>> callable(getattr(string, ‘printable‘)) False >>> callable(getattr(string, ‘punctuation‘)) False >>> callable(getattr(string, ‘Formatter‘)) True >>>
下面这段代码列出对象所有函数:
methodList = [method for method in dir(object) if callable(getattr(object,method))]
比如查看string的所有函数:
>>> methodList = [method for method in dir(string) if callable(getattr(string, method))] >>> methodList [‘ChainMap‘, ‘Formatter‘, ‘Template‘, ‘_TemplateMetaclass‘, ‘capwords‘] >>>
接下来,看看python的是如何体现反射的。
globals()
这个函数返回一个map,这个map的key是全局范围内对象的名字,value是该对象的实例。
在不导入任何module下,执行globals()的结果如下:
>>> globals() {‘__doc__‘: None, ‘__package__‘: None, ‘__builtins__‘: <module ‘builtins‘ (built-in)>, ‘__spec__‘: None, ‘__loader__‘: <class ‘_frozen_importlib.BuiltinImporter‘>, ‘__name__‘: ‘__main__‘} >>>
在导入sys后,可以发现,globals()返回的map中,多了sys module:
>>> import sys >>> globals() {‘__doc__‘: None, ‘__package__‘: None, ‘__builtins__‘: <module ‘builtins‘ (built-in)>, ‘__spec__‘: None, ‘__loader__‘: <class ‘_frozen_importlib.BuiltinImporter‘>, ‘__name__‘: ‘__main__‘, ‘sys‘: <module ‘sys‘ (built-in)>} >>>
在导入sgmllib,如下:
如果导入类后,在map中,可以找到类。
所以,只要将class的名字最为key,即可得到class。如下:
而如果要实例化一个对象,可以如下:
这样,实现了类似java中,Class.forName().newInstance()的功能。但是,在使用globals函数之前,还需要导入相应的类,如果不导入,而直接使用globals[‘...’]查找这个类,则会抛出异常。
所以,我在介绍一种可以动态导入的方法。
首先,介绍一个函数 __import__, 这个函数传入的参数是module的名字,返回这个module,然后,在结合之前介绍过的getattr,于是,我们可以写出下面两句代码,实现对象的自省。
由此可见,python提供的反射和自省机制是十分便捷的。这也方便了很多操作。比如,如下这段代码,将导入脚本文件所在文件夹下的所有测试文件(以test结尾的脚本文件0,并进行测试)
代码出自dive in python(这本书写的很好),比较容易理解,不做详细介绍了。主要是先获得目录,然后过滤出符合条件的脚本文件,去掉后缀名,作为模块加载。
参考:http://blog.csdn.net/lokibalder/article/details/3459722
http://www.cnblogs.com/huxi/archive/2011/01/02/1924317.html