2009-12-02 11 views
6

zipfile(圧縮されたpy2exeで構築)からすべてのモジュール(プリコンパイル済み)を読み込んでメモリにロードする必要があります。 これはzipファイルから直接ロードすることで行うことができますが、私はそれらをメモリからロードする必要があることを知っています。 アイデア(Windows上でPython 2.5.2を使用しています) TIA Steveメモリからコンパイル済みのPythonモジュールをロードするには?

+0

もう少し背景を教えてもらえますか?最初にコードをメモリにロードする必要があるのはなぜですか?なぜZIPファイルからの読み込みが合わないのですか? – Ber

答えて

30

「モジュール(プリコンパイル済み)」の正確な内容によって異なります。

$ cat>'ciao.py' 
def ciao(): return 'Ciao!' 
$ python -c'import ciao; print ciao.ciao()' 
Ciao! 

IOW、これ建てたciao.pyc、あなたが今やると言う:によって建てられたとのは、それは例えば、.pycファイルの正確内容だciao.pycを想定してみましょう

$ python 
Python 2.5.1 (r251:54863, Feb 6 2009, 19:02:12) 
[GCC 4.0.1 (Apple Inc. build 5465)] on darwin 
Type "help", "copyright", "credits" or "license" for more information. 
>>> b = open('ciao.pyc', 'rb').read() 
>>> len(b) 
200 

をし、あなたの目標はにありますそのバイト文字列bからインポート可能なモジュールciaoに移動します。

>>> import marshal 
>>> c = marshal.loads(b[8:]) 
>>> c 
<code object <module> at 0x65188, file "ciao.py", line 1> 

これはあなたが.pycバイナリコンテンツからのコードオブジェクトを取得する方法である:ここでは方法です。 を編集します。最初の8バイトは「マジックナンバー」とタイムスタンプです(ここでは必要ありません)(正当性を確認し、例外が発生しない限り、質問:marshal.loadsは、とにかく破損文字列を検出した場合に発生します)。

その後:

>>> import types 
>>> m = types.ModuleType('ciao') 
>>> import sys 
>>> sys.modules['ciao'] = m 
>>> exec c in m.__dict__ 

すなわち:新しいモジュールオブジェクトを作成し、sys.modulesでそれをインストールし、その__dict__にコードオブジェクトを実行することで、それを取り込みます。 を編集してください:sys.modulesを挿入する順番とexecの順番は問題ありませんが、これはPythonの独自の順番であるため、具体的な内容はありません欠点)。

いくつかの方法で(たとえば、newimpなどの標準ライブラリモジュールの関数から)新しいモジュールオブジェクトを作成できますが、「インスタンスを取得するために型を呼び出す」ことは、タイプを取得するための通常の場所(名前が組み込まれていないか、そうでなければ手軽に使っている場合を除く)は、標準ライブラリモジュールtypesからのものです。

さて、最後に:

>>> import ciao 
>>> ciao.ciao() 
'Ciao!' 
>>> 

...あなたはモジュールをインポートするというようにその関数、クラス、およびを使用することができます。他のimport(およびfrom)ステートメントは、この操作のシーケンスを繰り返す必要はないので、sys.modules['ciao']というモジュールを見つけることになります。import文が必要です他の場所からインポートすることができます - 私はそれが動作することを示すためにのみ追加しています;-)。

編集:あなたは絶対にパッケージやモジュールではなく、私がちょうどあったとして「プレーンモジュール」よりも、そこからこの方法でインポートする必要がある場合は、それはあまりにも、なんとかだが、少し複雑。この答えはすでにかなり長いので、この目的のためにプレーンなモジュールに固執してあなたの人生を単純化することができたら幸いです。

「メモリから同じモジュールを複数回ロードする」場合は、これが必要な場合とできない場合があります(これはモジュールを毎回再構築するため、sys.modulesをチェックし、 (ロックが必要ですが、より良いアーキテクチャは、タスクを実行するための専用のスレッドを1つ持つことです。他のモジュールは、そのモジュールと通信しています)。キュー)。

最後に、importステートメント内部機構のメカニズムに自動的に関与する透過的な「インポートフック」としてこの機能をインストールする方法については何も言及していません - それは実行可能でもありませんが、私はあなたの人生を単純化することができます、この答えが概説しているように、単純な方法で代わりにしてください。

+1

ちょうど興味深いですが、.pydファイルでも動作しますか? – YOU

+1

私は同じ要件を持っていて、解決策を探していました。ありがとうございました:) – Parthan

+0

@ S.Mark、いいえ、 '.pyc'または' .pyo'のみ - '.pyd'sは本質的に' .dll'sです偽の名前の下で**完全に**異なる問題を提示する。 @技術革新、あなたは大歓迎! - ) –

9

、Pythonのファイルは、我々は新しいソースを持っているかどうかを確認する

  1. マジックナンバー(4バイト)タイプとPythonのバージョンを決定するために、
  2. タイムスタンプ(4バイト)で構成されてコンパイルさ
  3. マーシャリングコードオブジェクト。

あなたは、imp.new_module()でモジュールオブジェクトを作成するには、新しいモジュールの名前空間にunmashaledコードを実行し、sys.modulesでそれを置くために持っているモジュールをロードします。サンプル実装における下:

import sys, imp, marshal 

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 

更新:コードが正しくパッケージを処理するように更新されます。

ロードされたモジュール内でインポートを処理するには、インポートフックをインストールする必要があります。これを行う1つの方法は、ファインダーをsys.meta_pathに追加することです。詳細については、PEP302を参照してください。

関連する問題