18

私は現在、Python用の独自の「マーシャル」コードをロールバックしようとしています。これにより、コンパイルされたPythonコードをGoogle App Engineに保存して、動的な方法でスクリプトを提供できます。ご存知のとおり、「marshal」はGAEでサポートされておらず、「pickle」はコードオブジェクトをシリアル化できません。

でコードオブジェクトを作成できることがわかりましたtypes.CodeType()が、12個の引数が必要です。

私が試した限り、この呼び出しに関するドキュメントは見つかりませんでした。コードオブジェクトを作成する必要があるので、それを実行できexec()ます。私の質問は、この「コンストラクター」のパラメーターや、それを内省する方法を知っている人はいますか?types.CodeType()ここでinfo()定義した関数を使用しましたが、一般的な情報だけを吐き出します!

クイックFAQ:

  • Q:なぜコードをコンパイルするのですか?
  • A:Google App EngineではCPU時間に実際の費用がかかり、CPUサイクルのすべてのビットでカウントを節約できます。
  • Q:「マーシャル」を使ってみませんか?
  • A:これはGoogleAppEngineでサポートされていないモジュールの1つです。
  • Q:「ピクルス」を使ってみませんか?
  • A:Pickleは、コードオブジェクトのシリアル化をサポートしていません。

アップデート

Google App Engineインフラストラクチャでは、2011年7月7日の時点でコードオブジェクトのインスタンス化が許可されていないため、ここでの私の議論は議論の余地があります。これがGAEで将来修正されることを願っています。

4

4 に答える 4

7

尋ねられた質問:

このtypes.CodeType()「コンストラクター」のパラメーターは何ですか

inspectモジュールに関するPythonドキュメントから:

co_argcount: number of arguments (not including * or ** args)
co_code: string of raw compiled bytecode
co_consts: tuple of constants used in the bytecode
co_filename: name of file in which this code object was created
co_firstlineno: number of first line in Python source code
co_flags: bitmap: 1=optimized | 2=newlocals | 4=*arg | 8=**arg
co_lnotab: encoded mapping of line numbers to bytecode indices
co_name: name with which this code object was defined
co_names: tuple of names of local variables
co_nlocals: number of local variables
co_stacksize: virtual machine stack space required
co_varnames: tuple of names of arguments and local variables

このブログ投稿には、はるかに詳細な説明があります:http: //tech.blog.aknin.name/2010/07/03/pythons-innards-code-objects/

注:上記の引用されたpythonドキュメントはpython 2.7ですが、ブログ投稿ではpython3について説明しています。

于 2012-10-13T22:13:38.547 に答える
6

C API関数PyCode_Newは、(最低限)ここに文書化されています:http://docs.python.org/c-api/code.html この関数(Python 2.7)のCソースコードはここにあります:http://hg。 python.org/cpython/file/b5ac5e25d506/Objects/codeobject.c#l43

PyCodeObject *
PyCode_New(int argcount, int nlocals, int stacksize, int flags,
           PyObject *code, PyObject *consts, PyObject *names,
           PyObject *varnames, PyObject *freevars, PyObject *cellvars,
           PyObject *filename, PyObject *name, int firstlineno,
           PyObject *lnotab)

ただし、Pythonコンストラクターでは、最後の6つの引数が少し入れ替わっているように見えます。これは、Pythonによって渡された引数を抽出するCコードです:http://hg.python.org/cpython/file/b5ac5e25d506/Objects/codeobject.c#l247

if (!PyArg_ParseTuple(args, "iiiiSO!O!O!SSiS|O!O!:code",
                      &argcount, &nlocals, &stacksize, &flags,
                      &code,
                      &PyTuple_Type, &consts,
                      &PyTuple_Type, &names,
                      &PyTuple_Type, &varnames,
                      &filename, &name,
                      &firstlineno, &lnotab,
                      &PyTuple_Type, &freevars,
                      &PyTuple_Type, &cellvars))
    return NULL;

Python化:

def __init__(self, argcount, nlocals, stacksize, flags, code,
                   consts, names, varnames, filename, name, 
                   firstlineno, lnotab, freevars=None, cellvars=None): # ...
于 2011-07-07T15:35:30.130 に答える
5

ここにあるコードを使用して、非推奨の「新しい」モジュールの依存関係を削除しました。

import types, copy_reg
def code_ctor(*args):
    # delegate to new.code the construction of a new code object
    return types.CodeType(*args)
def reduce_code(co):
    # a reductor function must return a tuple with two items: first, the
    # constructor function to be called to rebuild the argument object
    # at a future de-serialization time; then, the tuple of arguments
    # that will need to be passed to the constructor function.
    if co.co_freevars or co.co_cellvars:
        raise ValueError, "Sorry, cannot pickle code objects from closures"
    return code_ctor, (co.co_argcount, co.co_nlocals, co.co_stacksize,
        co.co_flags, co.co_code, co.co_consts, co.co_names,
        co.co_varnames, co.co_filename, co.co_name, co.co_firstlineno,
        co.co_lnotab)
# register the reductor to be used for pickling objects of type 'CodeType'
copy_reg.pickle(types.CodeType, reduce_code)
if __name__ == '__main__':
    # example usage of our new ability to pickle code objects
    import cPickle
    # a function (which, inside, has a code object, of course)
    def f(x): print 'Hello,', x
    # serialize the function's code object to a string of bytes
    pickled_code = cPickle.dumps(f.func_code)
    # recover an equal code object from the string of bytes
    recovered_code = cPickle.loads(pickled_code)
    # build a new function around the rebuilt code object
    g = types.FunctionType(recovered_code, globals( ))
    # check what happens when the new function gets called
    g('world')
于 2011-07-07T15:18:36.747 に答える
2

あなたが尋ねたものではなく、あなたが答える必要のある質問に答える:

現在、AppEngineのPython環境で任意のバイトコードを実行することはできません。バイトコードまたはコードオブジェクトにアクセスできる場合もありますが、ロードすることはできません。

ただし、別の方法があります。インスタンスごとのキャッシュです。コンパイルされたコードオブジェクトに(Pythonコードを格納するデータストアエントリ用の)グローバルdictマッピングデータストアキーを格納します。オブジェクトがキャッシュに存在しない場合は、ソースからコンパイルしてそこに保存します。インスタンスごとにコンパイル作業を行う必要がありますが、リクエストごとに行う必要はありません。これにより、多くの作業を節約できます。

于 2011-07-08T00:07:58.957 に答える