在Windows編程的時候,有些時候,咱們常常會要使用一些很是規的方法,好比說從內存中加載DLL,而後使用DLL中的函數。因而就思索在用Python的時候是否可以將幾個編譯好的Pyc合併成一個,而後使用動態的讀取這個文件,而後根據標記進行劃分,得到不一樣的模塊的pyc內容,而後動態做爲一個新的模塊引用到咱們的程序中去,這就涉及到一個問題,如何將一個pyc整到內存,而後從內存中獲取變成一個新模塊進行引入處理。以後找了一些資料以後,發現一種方法,就是經過PyCodeObject這個代碼對象來進行處理,也就是用compile編譯以後的內容,而後讀取造成codeobject對象,而後用types.ModuleType創建一個新的模塊,而後將這個新模塊加入到sys.modules字典中去,以後在這這個新建的模塊環境中執行前面讀取的codeObject對象,那麼久可使用這個新的導入模塊了,方式以下:python
#代碼以下: PycContext = open('test.pyo', 'rb').read() import marshal #能夠查看PyCodeObject數據結構前面8個位是一個4字節MagicNum和4字節的時間戳,因此從第八位開始 PyCodeObject = marshal.loads(b[8:]) import types #創建一個名字叫testSimple的新模塊 newModule = types.ModuleType('testSimple') import sys sys.modules['testSimple'] = newModule #這個時候已經能夠用import testSimple了 #可是運行時候會發現,這個新模塊什麼功能函數都沒有,由於尚未和 #上面的PyCodeObject關聯起來,此時須要關聯 #就是使用exec在本模塊環境執行一次,則可 exec c in newModule.__dict__ #這樣,上面的codeObject和新模塊就關聯起來了,而後就可使用裏面的函數了
另外記錄一個外國的資料代碼以下編程
def load_compiled_from_memory(name, filename, data, ispackage=False): if data[:4]!=imp.get_magic(): raise ImportError('Bad magic number in %s' % filename) # Ignore timestamp in data[4:8] code = marshal.loads(data[8:]) imp.acquire_lock() # Required in threaded applications try: mod = imp.new_module(name) sys.modules[name] = mod # To handle circular and submodule imports # it should come before exec. try: mod.__file__ = filename # Is not so important. # For package you have to set mod.__path__ here. # Here I handle simple cases only. if ispackage: mod.__path__ = [name.replace('.', '/')] exec code in mod.__dict__ except: del sys.modules[name] raise finally: imp.release_lock() return mod
另外須要說明一下的是,使用Python import自動生成的編譯後的文件通常都帶有魔數和時間戳,也就是說讀取codeObject的時候須要移動8位,可是有些用Python的API生成的不必定帶有這個魔數和時間戳的,那麼這個時候就不用移位,而直接讀取生成codeobject數據結構
國外參考資料app