因为目前在写一个python的项目,用到了Python的反射机制,所以做一下笔记,把写项目过程中的感悟记下来。
先简单介绍下Demo用到的函数:
sys.path 是python的模块的路径集,是一个集合(使用之前记得导入sys模块)
>>> sys.path ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-i386-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/wx-3.0-gtk2']
如果你想追加一个模块那么将他的文件夹绝对路径添加到sys.path内就可以了
>>> sys.path.append('/usr/develop/git/nearsec/') >>> sys.path ['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-i386-linux-gnu', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PILcompat', '/usr/lib/python2.7/dist-packages/gtk-2.0', '/usr/lib/pymodules/python2.7', '/usr/lib/python2.7/dist-packages/wx-3.0-gtk2', '/usr/develop/git/nearsec/']
当然这只是临时的程序结束后,sys.path还是会恢复到原来的样子。
*****************************************************************************************************************
这部分可跳过,这部分的讲解只是为了让初学者更深的的理解反射的原理。
*****************************************************************************************************************
使用globals()获取当前内存中存在哪些对象,该方法返回一个字典(假设有一个base.py文件,文件内有一个Base类): >>>globals() 创建Base类对象前: {'__builtins__': <module '__builtin__' (built-in)>, '__file__': './main.py', '__package__': None, 'sys': <module 'sys' (built-in)>, 're': <module 're' from '/usr/lib/python2.7/re.pyc'>, '__name__': '__main__', 'unittest': <module 'unittest' from '/usr/lib/python2.7/unittest/__init__.pyc'>, 'os': <module 'os' from '/usr/lib/python2.7/os.pyc'>, '__doc__': None} 创建Base类对象后: {'__builtins__': <module '__builtin__' (built-in)>, '__file__': './main.py', '__package__': None, 'sys': <module 'sys' (built-in)>, 're': <module 're' from '/usr/lib/python2.7/re.pyc'>, 'Base': <class base.Base at 0xb743520c>, 'base': <base.Base instance at 0xb743974c>, '__name__': '__main__', 'os': <module 'os' from '/usr/lib/python2.7/os.pyc'>, '__doc__': None} 下面是使用dir()的结果 >>>dir() 创建Base类对象前(可以看出内存已经导入了Base、os、re、sys等模块): ['Base', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'os', 're', 'sys'] 创建Base类对象后: ['Base', '__builtins__', '__doc__', '__file__', '__name__', '__package__', 'base', 'os', 're', 'sys'] 如果dir()方法内写入一个对象,如:dir(sys)则返回sys模块的所有方法名称: >>>dir(sys) ['__displayhook__', '__doc__', '__excepthook__', '__name__', '__package__', '__stderr__', '__stdin__', '__stdout__', '_clear_type_cache', '_current_frames', '_getframe', '_mercurial', '_multiarch', 'api_version', 'argv', 'builtin_module_names', 'byteorder', 'call_tracing', 'callstats', 'copyright', 'displayhook', 'dont_write_bytecode', 'exc_clear', 'exc_info', 'exc_type', 'excepthook', 'exec_prefix', 'executable', 'exit', 'flags', 'float_info', 'float_repr_style', 'getcheckinterval', 'getdefaultencoding', 'getdlopenflags', 'getfilesystemencoding', 'getprofile', 'getrecursionlimit', 'getrefcount', 'getsizeof', 'gettrace', 'hexversion', 'long_info', 'maxint', 'maxsize', 'maxunicode', 'meta_path', 'modules', 'path', 'path_hooks', 'path_importer_cache', 'platform', 'prefix', 'py3kwarning', 'pydebug', 'setcheckinterval', 'setdlopenflags', 'setprofile', 'setrecursionlimit', 'settrace', 'stderr', 'stdin', 'stdout', 'subversion', 'version', 'version_info', 'warnoptions']
上面对比可以看出两个方法均可以获取当前内存中的所有对象与导入的模块。
*****************************************************************************************************************
__import__(moudle) 函数更能使导入一个模块,与头部的“import moudle”一样,只不过__inport__()是动态导入模块。
既然可以通过__import__(moudle)将模块加载到内存中,那么当然可以通过python的内部函数获取模块中的某个方法了,使用getattr(moudle, 'class_name')根据模块获取对象:clas = getattr(moudle, "class_name“这样就获取到了对象clas,既然clas已经获取到了那不是想调用任何方法不都可以了吗。
好了,用到的函数都已经讲解了一遍,进入主题吧(继承也不懂得去自己查查资料吧。^_^
首先演示不继承情况下调用,main.py是Demo1测试的入口
#!/usr/bin/python # -*- coding: utf-8 -*- #Version: 0.01 #Create: 2016-03-09 #Authoruis: kun/ #project: main.py import sys,os,re def main(): base = __import__('base')#动态加载Base模块 clas = getattr(base, "Base")#获取Base对象 clas.test()#调用base中的方法 if __name__ == '__main__': main() #!/usr/bin/python # -*- coding: utf-8 -*- #Version: 0.01 #Create: 2016-03-09 #Authoruis: kun/ #project: base.py class Base(): def __init__(self): print 'init Base !' @staticmethod def test(): print 'Base test is running !' 接下来是Demo2,main.py 还是执行入口,继承后的反射调用: #!/usr/bin/python # -*- coding: utf-8 -*- #Version: 0.01 #Create: 2016-03-09 #Authoruis: kun/ #project: main.py import sys,os,re def main(): base = __import__(sys.argv[1])#动态加载控制台输入的模块名 clas = getattr(base, sys.argv[1])#动态获取对象 clas.test()#调用base中的方法 print globals() if __name__ == '__main__': main() #!/usr/bin/python # -*- coding: utf-8 -*- #Version: 0.01 #Create: 2016-03-09 #Authoruis: kun/ #project: base.py class Base(): def __init__(self): print 'init Base !' @staticmethod def test(): print 'Base test is running !' #!/usr/bin/python # -*- coding: utf-8 -*- #Version: 0.01 #Create: 2016-03-09 #Authoruis: kun/ #project: test.py from base import Base class test(Base): @staticmethod def test(): print 'test test() is run !'
控制台: root@kun:/usr/develop/git/demo# ./main.py test test test() is run ! {'__builtins__': <module '__builtin__' (built-in)>, '__file__': './main.py', '__package__': None, 'sys': <module 'sys' (built-in)>, 're': <module 're' from '/usr/lib/python2.7/re.pyc'>, '__name__': '__main__', 'main': <function main at 0xb74c1454>, 'os': <module 'os' from '/usr/lib/python2.7/os.pyc'>, '__doc__': None}
后记:其实这个demo也算是为我正在开发安全项目的一个学习Demo,可拓展部分的代码核心就是有这些思想所组成,实现整个框架的可拓展性。目前,整个框架的核心源码基本完成了,我希望找几个小伙伴一起来完善好这个框架,有这个意向和能力的小伙伴联系我吧:qq1033163112。
Demo2中有个小瑕疵就是类名都必须小写,其实解决这个问题并不难,调用python的提供的函数将首字母转换为大写即可。后期我还会写出框架中用到其它技术的核心代码讲解Demo,项目最迟会在年中的时候开源,小伙伴们敬请期待吧。