Каковы аргументы вызова python types.CodeType ()? - PullRequest
15 голосов
/ 07 июля 2011

В настоящее время я пытаюсь свернуть свой собственный «маршальный» код для python, чтобы я мог хранить скомпилированный код python в Google App Engine, чтобы динамически обслуживать сценарии.Как вы все можете убедиться, маршал не поддерживается в GAE, а pickle не может сериализовать объекты кода.

Я обнаружил, что могу создать объект кода с types.CodeType(), но он ожидает 12 аргументов..

Сколько бы я ни пытался, я не могу найти никакой документации по этому вызову, и мне действительно нужно построить объект кода, чтобы я мог exec() его.У меня вопрос: кто-нибудь знает, каковы параметры для этого types.CodeType() "конструктора" или каким-либо образом для его анализа? Я использовал info() определенную здесь функцию, но онавыплевывает только общую информацию!

Быстрый FAQ:

  • В: Зачем компилировать код?
  • A: Процессорное время стоит реальных денег в Google App Engine, икаждый бит циклов ЦП, который я могу сохранить, подсчитывает.
  • В: Почему бы не использовать «маршал»?
  • A: Это один из неподдерживаемых модулей в Google App Engine .
  • Q: Почему бы не использовать «pickle»?
  • A: Pickle не поддерживает сериализацию объектов кода.

UPDATE

Инфраструктура Google App Engine не позволяет создавать экземпляры объектов кода с 7 июля 2011 года, поэтому мой аргумент здесь спорный.Надеюсь, что это будет исправлено в будущем на GAE.

Ответы [ 4 ]

6 голосов
/ 14 октября 2012

Заданный вопрос:

каковы параметры для этих типов. CodeType () "constructor"

Из документации по питону о модуле inspect:

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.

6 голосов
/ 07 июля 2011

Функция 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 последние шесть аргументов, похоже, немного поменялись местами. Это код C, который извлекает аргументы, переданные Python: 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;

Pythonized:

def __init__(self, argcount, nlocals, stacksize, flags, code,
                   consts, names, varnames, filename, name, 
                   firstlineno, lnotab, freevars=None, cellvars=None): # ...
5 голосов
/ 07 июля 2011

Я пошел и взял найденный код здесь и удалил зависимость для устаревшего "нового" модуля.

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')
2 голосов
/ 08 июля 2011

Отвечая на вопрос, на который вам нужно ответить, а не на тот, который вы задали:

В настоящее время вы не можете выполнить произвольный байт-код в среде Python App Engine. Хотя вы можете иметь доступ к байт-коду или объектам кода, вы не можете загрузить их.

Однако у вас есть альтернатива: кэширование для каждого экземпляра. Сохраните глобальные ключи хранилища данных для dict-отображения (для записей хранилища данных, в которых хранится код Python) в объекте скомпилированного кода Если объект не существует в кэше, скомпилируйте его из исходного кода и сохраните его там. Вам придется выполнять работу по компиляции в каждом экземпляре, но вам не нужно делать это при каждом запросе, что должно сэкономить вам много работы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...