【问题标题】:What are the arguments to the types.CodeType() python call?types.CodeType() python 调用的参数是什么?
【发布时间】:2011-09-30 13:04:58
【问题描述】:

我目前正在尝试为 python 推出我自己的“marshal”代码,以便我可以将编译后的 python 代码存储在 Google App Engine 上,以便以动态方式提供脚本。大家都可以验证,GAE 不支持“marshal”,“pickle”无法序列化代码对象。

我发现我可以使用 types.CodeType() 构造一个代码对象,但它需要 12 个参数。

尽管我已经尝试过了,但我找不到任何有关此调用的文档,我确实需要构造代码对象,以便我可以exec() 它。我的问题是,有谁知道这个types.CodeType()“构造函数”的参数是什么?我使用了info() 定义的here 函数,但它只是吐出通用信息!

快速常见问题解答:

  • 问:为什么要编译代码?
  • 答:在 Google App Engine 上,CPU 时间成本是真金白银,而我可以节省的每一点 CPU 周期都很重要。
  • 问:为什么不使用“元帅”?
  • A:那是unsupported modules in Google App Engine 之一。
  • 问:为什么不用“pickle”?
  • 答:Pickle 不支持代码对象的序列化。

更新

自 2011 年 7 月 7 日起,Google App Engine 基础架构不允许对代码对象进行实例化,因此我的论点没有实际意义。希望这个问题将来能在 GAE 上得到解决。

【问题讨论】:

  • 你能解释一下你到底想做什么吗?你将如何处理腌制代码?
  • 我希望每个问题都更像这样。
  • @Anurag Uniyal:我在 Google App Engine 基础架构上运行“托管”代码,该代码来自前端,编码人员可以在该前端直接在浏览器上编程,并且代码被即时编译到检查语法/类型错误(很像 Cloud9,但用于 GAE)。我不想在执行时重新编译代码,因为重新编译的峰值会破坏我的 CPU 配额和我的钱包。这个想法是获取字节码(我已经拥有)并在沙盒环境中运行它。
  • @something:这段代码很有帮助!谢谢!但是,“新”模块在 2.6 上已弃用,GAE 的 python 运行时即将更改为 2.7,所以我必须知道 type.CodeType 的参数的确切顺序
  • @Chiguireitor:我删除了对“新”模块的需求并将其发布为答案。希望对您有所帮助。

标签: python google-app-engine compiler-construction introspection dynamic-cast


【解决方案1】:

我去拿找到here的代码并删除了对已弃用的“新”模块的依赖。

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')

【讨论】:

  • 这对@something 有很大帮助,谢谢...不得不摆弄 type.CodeType 以使其工作。参数列表与here 完全相同
  • 我花了一点时间才意识到这与我的答案是如何吻合的:有两个可选参数,freevars 和 cellvars。我想它们是后来添加的。
  • freevarscellvars 用于闭包。它们是可选的,因为并非所有函数都使用它们。
  • 在所有这些麻烦之后,我将解决方案部署到我的 GAE 服务器,它向我打招呼“运行时错误:无法在受限执行模式下创建代码对象”:-(
  • 嗯。也许您可以编译一次对象,然后将它们保存在字典中?
【解决方案2】:

C API 函数 PyCode_New (最少)记录在此处:http://docs.python.org/c-api/code.html — 此函数的 C 源代码(Python 2.7)在此处: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 构造函数中,最后六个参数似乎交换了一点。这是提取 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): # ...

【讨论】:

    【解决方案3】:

    回答您需要回答的问题,而不是您提出的问题:

    目前,您无法在 App Engine Python 环境中执行任意字节码。尽管您可能能够访问字节码或代码对象,但您无法加载。

    不过,您还有一个替代方案:按实例缓存。将全局 dict 映射数据存储键(用于存储 Python 代码的数据存储条目)存储到已编译的代码对象。如果缓存中不存在该对象,则从源代码编译它并将其存储在那里。您必须对每个实例进行编译工作,但不必对每个请求都进行编译,这样可以节省大量工作。

    【讨论】:

    • 谢谢尼克,这是我今天下午早些时候测试的,我知道如果在每个实例上缓存多个脚本,这个解决方案会消耗大量内存,但正如我所见,目前这是实现我的用例的最佳方式。如果动态代码加载将在 2.7 版本中可用,是否有任何提示?那太好了:-)
    【解决方案4】:

    问的问题:

    这个类型的参数是什么。CodeType() "constructor"

    来自关于 inspect module 的 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 3,而上面引用的 python 文档是 python 2.7。

    【讨论】:

    • 在op的情况下,我会说python 2.5.2。
    猜你喜欢
    • 1970-01-01
    • 2011-08-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-10
    • 1970-01-01
    • 2020-04-30
    • 2021-05-25
    相关资源
    最近更新 更多