Ответ 1
[email protected]$ more a.py def foo(a): print a [email protected]$ more b.py import a import inspect a.foo(89) print inspect.getsource(a.foo) [email protected]$ python b.py 89 def foo(a): print a
Когда я передаю параметры в программе (эксперимент по вычислительной биологии), я обычно передаю их через .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, чтобы продолжать писать параметры, если один из вариантов - это функция. Я мог бы, конечно, скопировать исходный файл, но это неэлегантно, неэффективно (потому что оно содержит много дополнительных опций, которые не используются), и, как правило, не решает вопрос.
Как вы получаете питон для записи кода функции, поскольку он записывает значение переменной?
[email protected]$ more a.py def foo(a): print a [email protected]$ more b.py import a import inspect a.foo(89) print inspect.getsource(a.foo) [email protected]$ python b.py 89 def foo(a): print a
Вы также можете рассмотреть некоторые другие способы сохранения данных. В своем собственном (астрономическом) исследовании я экспериментировал с двумя разными способами хранения сценариев для воспроизводимости. Первый заключается в том, чтобы они были исключительно внутри репозитория 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
Возможно, это может быть немного более элегантным, но в моих тестах оно работает для простых наборов аргументов и переменных. Кроме того, у него могут быть проблемы с лямбдами.
Вы спрашиваете об этом?
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)
Или что-то еще?
Хотя можно делать то, что вы просите (как показал Винько), я бы сказал, что использовать код проще. Поместите pippo
и его приятелей в подмодуль, доступ к которым могут получить обе программы.
Вместо погружения в тему дизассемблеры и байт-коды (например, inspect), почему бы вам просто не сохранить сгенерированный источник Python в модуле (file.py), а затем импортировать его?
Я бы предложил изучить более стандартный способ обработки того, что вы называете опциями. Например, вы можете использовать модуль JSON и сохранять или восстанавливать свои данные. Или посмотрите marshal и pickle модулей.