由於目前在寫一個python的項目,用到了Python的反射機制,因此作一下筆記,把寫項目過程當中的感悟記下來。
先簡單介紹下Demo用到的函數:
sys.path 是python的模塊的路徑集,是一個集合(使用以前記得導入sys模塊)
python
>>> 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內就能夠了
linux
>>> 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仍是會恢復到原來的樣子。
*****************************************************************************************************************
這部分可跳過,這部分的講解只是爲了讓初學者更深的的理解反射的原理。
*****************************************************************************************************************git
使用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測試的入口
api
#!/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,可拓展部分的代碼核心就是有這些思想所組成,實現整個框架的可拓展性。目前,整個框架的核心源碼基本完成了,我但願找幾個小夥伴一塊兒來完善好這個框架,有這個意向和能力的小夥伴聯繫我吧。
Demo2中有個小瑕疵就是類名都必須小寫,其實解決這個問題並不難,調用python的提供的函數將首字母轉換爲大寫便可。後期我還會寫出框架中用到其它技術的核心代碼講解Demo,項目最遲會在年中的時候開源,小夥伴們敬請期待吧。
python 反射調用安全