лучший способ сохранить код для последующего выполнения (Python) - PullRequest
1 голос
/ 11 января 2011

У меня есть некоторые задачи, хранящиеся в БД для последующего выполнения. Например, я могу решить задачу отправки электронной почты. И с помощью задачи cron exec (отправьте ее). Я ищу лучший способ сохранить код в БД для последующего выполнения. Для ex хранить его в сырой строке кода Python, а затем сделать Eval, но я также должен хранить относительный импорт здесь ..

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

s = "из django.core.mail import send_mail \ n send_mail ('subj', 'body', 'email@box.ru', ['email1@box.ru'], fail_silently = False) "

и позже eval .. есть идеи, как сделать это наилучшим образом или лучше шаблон для такого рода задач?

Ответы [ 5 ]

5 голосов
/ 11 января 2011

То, что вы делаете, - плохая идея, в основном потому, что вы допускаете слишком большую изменчивость в том, какой код будет выполняться. Строка кода может сделать что угодно , и я предполагаю, что есть только несколько видов задач, которые вы хотите сохранить для последующего выполнения.

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

Чтобы быть еще более необычным, у вас может быть какой-то контейнерный объект с кучей функций на нем, и сохраните имя вызываемой функции вместе с ее аргументами. Этот контейнер может быть чем-то таким простым, как модуль, в который вы импортируете функции, такие как send_mail в Django, как в вашем примере.

Тогда вы можете сохранить ваш пример вызова следующим образом:

func = 'send_mail'
args = ('subj', 'body', 'email@box.ru', ['email1@box.ru'])
kwargs = {'fail_silently': False}

my_call = cPickle.dumps((func, args, kwargs)) 

И используйте это так:

func, args, kwargs = cPickle.loads(my_call)

getattr(my_module, func)(*args, **kwargs)
2 голосов
/ 11 января 2011

Используйте celery для этого.Это лучший подход.

http://celeryproject.org/

2 голосов
/ 11 января 2011

Я бы не стал использовать это решение вообще.Я бы создал свой обработчик для каждой задачи (отправка почты, удаление файла и т. Д.).Хранение кода таким способом является хакерским.

EDIT

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

handlername;arg1;arg2;arg3;arg4

Далее вы используете python для считывания строк и их анализа.Например, это будет сохраненная строка:

sendmail;nightcracker@nclabs.org;subject;body

, которая будет проанализирована следующим образом:

for line in database:
    handler, *args = line.split(";")
    if handler == "sendmail":
        recipient, subject, body, = args[:3]
        # do stuff
    elif handler == "delfile":
        #etc
1 голос
/ 11 января 2011

Я бы хранил логические команды и выполнял их с чем-то вроде

def run_command(cmd):
    fields = map(unescape, cmd.split(";"))
    handlers[fields[0]](fields[1:])

...

@handler("mail")
def mail_handler(address, template):
    import whatever
    ...
    send_mail(address, get_template(template) % user_info, ...)

таким образом, вы можете гибко добавлять обработчики, не касаясь какого-либо кода в диспетчере, и при этом вы не записываете детали кода в базу данных, что усложнит выполнение проверок / статистики или просто исправление задач, еще не началось.

0 голосов
/ 11 января 2011

Чтобы напрямую ответить на ваш вопрос, eval действительно предназначен только для оценки кода, который даст результат. Например:

>>> eval('1 + 1')
2

Однако, если вы просто хотите выполнить код, возможно, несколько строк кода, вам нужна exec (), которая по умолчанию выполняется внутри пространства имен вызывающего:

>>> exec("x = 5 + 5")
>>> print x
10

Обратите внимание, что только доверенный код должен передаваться в exec или eval. Смотрите также execfile для выполнения файла.

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

def myMailCommand(...):
    ...

def myOtherCommand(...):
    ...

available_commands = {'mail': myMailCommand,
                      'other': myOtherCommand}

to_execute = [('mail', (arg1, arg2, arg3)),
              ('other', (arg1, arg2))]

for cmd, args in to_execute:
    available_commands[cmd](*args)

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

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