Как вы получаете Python для записи кода функции, имеющейся в памяти?

Когда я передаю параметры в программе (эксперимент по вычислительной биологии), я обычно передаю их через .py файл.
Поэтому у меня есть этот .py файл, который читается следующим образом:

starting_length=9
starting_cell_size=1000
LengthofExperiments=5000000

Затем я выполняю файл и получаю данные. Поскольку программа все на моей машине, и никто другой не имеет к ней доступа, она безопасна в тривиальной форме.
Я также могу написать очень простой файл:

def writeoptions(directory):
    options=""
    options+="starting_length=%s%s"%(starting_length,os.linesep)
    options+="starting_cell_size=%s%s"%(starting_cell_size,os.linesep)
    options+="LengthofExperiments=%s%s"%(LengthofExperiments,os.linesep)
...
    open("%s%soptions.py"%(directory,os.sep),'w').write(options)

Я хочу передать функцию как один из параметров:

starting_length=9
starting_cell_size=1000
LengthofExperiments=5000000

def pippo(a,b):
    return a+b
functionoperator=pippo

И, конечно же, в реальном эксперименте функция pippo будет намного сложнее. И отличается от эксперимента к эксперименту.

Но то, что я не могу сделать, - это написать функцию автоматически. Короче говоря, я не знаю, как обобщить функцию writeoptions, чтобы продолжать писать параметры, если один из вариантов - это функция. Я мог бы, конечно, скопировать исходный файл, но это неэлегантно, неэффективно (потому что оно содержит много дополнительных опций, которые не используются), и, как правило, не решает вопрос.

Как вы получаете питон для записи кода функции, поскольку он записывает значение переменной?

Ответ 2

Вы также можете рассмотреть некоторые другие способы сохранения данных. В своем собственном (астрономическом) исследовании я экспериментировал с двумя разными способами хранения сценариев для воспроизводимости. Первый заключается в том, чтобы они были исключительно внутри репозитория subversion, а затем автоматически присваивали им задание script. Например, если вы просто хотели сделать это в bash:

alias run_py='svn ci -m "Commit before running"; python2.5 $*'

и внутри script, у вас есть выход с префиксом текущий номер версии подведомственности для этого файла, у вас будет запись из каждого script, который был запущен и каким был вход. Вы могли бы вытащить это обратно из подрывной деятельности, если потребуется.

Другим, существенно менее полнофункциональным средством отслеживания ввода функции может быть через нечто вроде LodgeIt, пастебин, который принимает XML-RPC и поставляется с привязками Python. (Он может быть установлен локально и имеет поддержку для ответа и обновления существующих паст.)

Но, если вы ищете относительно небольшой объем кода, который должен быть включен, решение Vinko, использующее проверку, должно работать достаточно хорошо. Doug Hellman рассмотрел модуль inspect в своем Python Module Неделя. Вы можете создать декоратор, который проверяет каждую опцию и аргумент, а затем распечатывает его соответствующим образом (я буду использовать inspect.getargspec, чтобы получить имена аргументов.)

import inspect
from functools import wraps

def option_printer(func):
    @wraps(func)
    def run_func(*args, **kwargs):
        for name, arg in zip(inspect.getargspec(func)[0], args) \
                       + sorted(kwargs.items()):
            if isinstance(arg, types.FunctionType): 
                print "Function argument '%s' named '%s':\n" % (name, func.func_name)
                print inspect.getsource(func)
            else:
                print "%s: %s" % (name, arg)
        return func(*args, **kwargs)
    return run_func

Возможно, это может быть немного более элегантным, но в моих тестах оно работает для простых наборов аргументов и переменных. Кроме того, у него могут быть проблемы с лямбдами.

Ответ 3

Вы спрашиваете об этом?

def writeoptions(directory):
    options=""
    options+="starting_length=%s%s"%(starting_length,os.linesep)
    options+="starting_cell_size=%s%s"%(starting_cell_size,os.linesep)
    options+="LengthofExperiments=%s%s"%(LengthofExperiments,os.linesep)
    options+="def pippo(a,b):%s" % ( os.linesep, )
    options+="    '''Some version of pippo'''%s" % ( os.linesep, )
    options+="    return 2*a+b%s" % ( os.linesep, )
    open("%s%soptions.py"%(directory,os.sep),'w').write(options)

Или что-то еще?

Ответ 4

Хотя можно делать то, что вы просите (как показал Винько), я бы сказал, что использовать код проще. Поместите pippo и его приятелей в подмодуль, доступ к которым могут получить обе программы.

Ответ 5

Вместо погружения в тему дизассемблеры и байт-коды (например, inspect), почему бы вам просто не сохранить сгенерированный источник Python в модуле (file.py), а затем импортировать его?

Я бы предложил изучить более стандартный способ обработки того, что вы называете опциями. Например, вы можете использовать модуль JSON и сохранять или восстанавливать свои данные. Или посмотрите marshal и pickle модулей.