存储代码以供以后执行的最佳方式(python)

发布于 2024-10-11 22:58:31 字数 556 浏览 3 评论 0原文

我有一些任务存储在数据库中供以后执行。例如,我可以修复发送电子邮件的任务。并通过 cron 执行任务(发送它)。我寻找将代码存储在数据库中以供以后执行的最佳方法。例如,将其存储在 python 代码的原始字符串中,而不是进行 eval,但我也必须在此处存储相对导入。

例如,对于发送电子邮件,我必须修复如下字符串:

s = "from django.core.mail import send_mail\n send_mail('subj', 'body', '[电子邮件受保护]' ,['[电子邮件受保护]'],fail_silently=False)"

和稍后评估..有什么想法可以最好的方式或更好的模式来完成此类任务?

I have some tasks stored in db for later execution. For example i can fix task of sending email. And by cron exec task (send it). I search for best way to store code in db for later execution. For ex store it in raw string of python code and than do eval, but also i must store relative imports here..

for example for send email i must fix string like this:

s = "from django.core.mail import send_mail\n
send_mail('subj', 'body', '[email protected]',['[email protected]'], fail_silently=False)"

and later eval.. any ideas to do it best way or mb better pattern for this kind of task?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

要走干脆点 2024-10-18 22:58:32

我根本不会使用这个解决方案。我会为每个任务创建一个不同的处理程序(发送邮件、删除文件等)。以这种方式存储代码是很黑客的。

编辑

一个例子是为处理程序创建您自己的格式。例如,每一行一个处理程序采用以下格式:

handlername;arg1;arg2;arg3;arg4

接下来,您使用 python 读出行并解析它们。例如,这将是一个存储的行:

sendmail;[email protected];subject;body

它将像这样解析:

for line in database:
    handler, *args = line.split(";")
    if handler == "sendmail":
        recipient, subject, body, = args[:3]
        # do stuff
    elif handler == "delfile":
        #etc

I wouldn't use this solution at all. I would create a different handler for each task (sending a mail, deleting a file, etc). Storing code in this manner is hackish.

EDIT

An example would be creating your own format for handlers. For example each line one handler in this format:

handlername;arg1;arg2;arg3;arg4

Next you use python to read out the lines and parse them. For example this would be a stored line:

sendmail;[email protected];subject;body

Which would be parsed like this:

for line in database:
    handler, *args = line.split(";")
    if handler == "sendmail":
        recipient, subject, body, = args[:3]
        # do stuff
    elif handler == "delfile":
        #etc
童话里做英雄 2024-10-18 22:58:32

我会存储逻辑命令,并用类似的方式执行它们,

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, ...)

这样您就可以灵活地添加处理程序,而不必接触调度程序中的任何代码,但您不会在数据库中编写代码详细信息,这会变得更加困难进行检查/统计或只是尚未开始的热修复工作。

I'd store logical commands, and exec them with something like

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, ...)

this way you can have both the flexibility to add handlers without having to touching any code in the dispatcher and yet you're not writing the code details in the database that would make harder doing inspections/stats or just hot fixing jobs that didn't start yet.

心如狂蝶 2024-10-18 22:58:32

为了直接回答您的问题,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)

在上面的伪代码中,我定义了两个方法。然后我有一个字典将操作映射到命令。然后,我检查操作和参数的数据结构,并相应地调用适当的参数。你明白了。

To directly answer your question, eval is really only for evaluating code that will produce a result. For example:

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

However if you simply want to execute code, possibly several lines of code, you want exec(), which by default executes inside the caller's namespace:

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

Note that only trusted code should be passed to either exec or eval. See also execfile to execute a file.

Having said all that, I agree with other posters that you should find a way to problematically do what you want to do instead of storing arbitrary code. You could, for example, do something like this:

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)

In the above pseudo-code, I defined two methods. Then I have a dictionary mapping actions to commands. Then I go through a data structure of actions and arguments, and call the appropriate argument accordingly. You get the idea.

安人多梦 2024-10-18 22:58:31

你正在做的事情是一个坏主意,主要是因为你允许执行的代码有太多的可变性。代码字符串可以做任何事情,我猜您只想存储几种任务以供以后执行。

因此,弄清楚这些任务中的变量是什么(非编程意义上的变量:变化的事物),并且只存储这些变量,也许作为函数参数的元组和关键字参数的字典来应用于已知的功能。

更奇特的是,您可以拥有某种带有一堆函数的容器对象,并存储要调用的函数的名称及其参数。该容器可以是像模块一样简单的东西,您可以在其中导入 Django 的 send_mail 等函数,如示例中所示。

然后您可以像这样存储示例调用:

func = 'send_mail'
args = ('subj', 'body', '[email protected]', ['[email protected]'])
kwargs = {'fail_silently': False}

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

并像这样使用它:

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

getattr(my_module, func)(*args, **kwargs)

What you're doing is a bad idea mainly because you allow for way too much variability in what code will be executed. A code string can do anything, and I'm guessing there are only a few kinds of tasks you want to store for later execution.

So, figure out what the variables in those tasks are (variables in a non-programming sense: things that vary), and only store those variables, perhaps as a tuple of function arguments and a dictionary of keyword arguments to be applied to a known function.

To be even more fancy, you can have some kind of container object with a bunch of functions on it, and store the name of the function to call along with its arguments. That container could be something as simple as a module into which you import functions like Django's send_mail as in your example.

Then you can store your example call like this:

func = 'send_mail'
args = ('subj', 'body', '[email protected]', ['[email protected]'])
kwargs = {'fail_silently': False}

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

And use it like this:

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

getattr(my_module, func)(*args, **kwargs)
帝王念 2024-10-18 22:58:31

为此,请使用 celery 。这是最好的方法。

http://celeryproject.org/

Use celery for this. That's the best approach.

http://celeryproject.org/

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文