使用参数运行Python脚本

24
我希望能够从C语言中调用一个Python脚本,并传递一些脚本所需的参数。我想要使用的脚本是mrsync,或称为multicast remote sync。我已经通过命令行成功地调用了这个脚本:
python mrsync.py -m /tmp/targets.list -s /tmp/sourcedata -t /tmp/targetdata

-m 是包含目标 IP 地址的列表。 -s 是包含要同步的文件的目录。 -t 是目标机器上将放置文件的目录。

到目前为止,我已经成功运行了一个 Python 脚本,使用以下 C 程序:

Py_Initialize();
FILE* file = fopen("/tmp/myfile.py", "r");
PyRun_SimpleFile(file, "/tmp/myfile.py");
Py_Finalize();

这很好用。然而,我找不到如何将这些参数传递给PyRun_SimpleFile(..)方法。
2个回答

42

看起来你正在寻找使用Python.h开发API的Python答案。这里为您提供一个应该可以工作的示例:

#My python script called mypy.py
import sys

if len(sys.argv) != 2:
  sys.exit("Not enough args")
ca_one = str(sys.argv[1])
ca_two = str(sys.argv[2])

print "My command line args are " + ca_one + " and " + ca_two

然后是传递这些参数的C代码:

//My code file
#include <stdio.h>
#include <python2.7/Python.h>

void main()
{
    FILE* file;
    int argc;
    char * argv[3];

    argc = 3;
    argv[0] = "mypy.py";
    argv[1] = "-m";
    argv[2] = "/tmp/targets.list";

    Py_SetProgramName(argv[0]);
    Py_Initialize();
    PySys_SetArgv(argc, argv);
    file = fopen("mypy.py","r");
    PyRun_SimpleFile(file, "mypy.py");
    Py_Finalize();

    return;
}
如果您可以将参数传递到C函数中,则这个任务会更加容易:
void main(int argc, char *argv[])
{
    FILE* file;

    Py_SetProgramName(argv[0]);
    Py_Initialize();
    PySys_SetArgv(argc, argv);
    file = fopen("mypy.py","r");
    PyRun_SimpleFile(file, "mypy.py");
    Py_Finalize();

    return;
}

你可以直接传递它们。现在,我的解决方案只使用了2个命令行参数,是为了节省时间,但你可以使用相同的概念来传递需要传递的所有6个参数... 当然,在Python端捕获参数的方法也有更简洁的方式,但那只是基本思路。

希望对你有所帮助!


请注意,在Python 3中,您需要首先转换为宽字符(wchar_t)。尝试使用mbstowcs_s(#include <stdlib.h>)进行转换。 - gkimsey
嗨@Mike,你能否看一下这个情况,我需要将参数传递给一个Python包应用程序(而不仅仅是一个py文件):http://stackoverflow.com/questions/21036106/pass-command-line-arguments-to-python-2-7-6-package-application-using-c-api - Jay Zhao
@JayZ - 抱歉,今天才回来,看起来你在另一个链接上得到了答案,但如果你需要更多帮助,请告诉我。 - Mike
我重新审视了这个例子 - 虽然CPython似乎也使用argc,但我仍然会在自己构建的argv末尾使用一个NULL指针,就像标准C argv一样。 - Antti Haapala -- Слава Україні
@Mike 在哪里放置“-m”选项?如何在Python/C API中设置标志? - Shoyeb Sheikh

9
你有两个选项。
  1. Call

    system("python mrsync.py -m /tmp/targets.list -s /tmp/sourcedata -t /tmp/targetdata")
    

    in your C code.

  2. Actually use the API that mrsync (hopefully) defines. This is more flexible, but much more complicated. The first step would be to work out how you would perform the above operation as a Python function call. If mrsync has been written nicely, there will be a function mrsync.sync (say) that you call as

    mrsync.sync("/tmp/targets.list", "/tmp/sourcedata", "/tmp/targetdata")
    

    Once you've worked out how to do that, you can call the function directly from the C code using the Python API.


+1 你的第一个方法确实有效,谢谢。然而,我仍然好奇是否可以使用我在第一篇帖子中描述的Python解释器来实现它。你的第二个方法在这种情况下不起作用,因为mrsync没有提供API。 - Bram W.
实际上,可能可以使用argv初始化解释器,然后让它执行一个文件。不过,你得试一下看看,我也不确定。 - Katriel
选项1仅适用于假设“python”已保证在系统路径中的情况。 - Mike
在编程中,我总是会对使用system函数的人点个踩。因为提供给system的字符串会受到shell解释,所以这个函数非常危险。在POSIX系统中,从C语言执行命令的正确方式是使用exec*函数。因此,可以这样写:execlp("python", "python", "mrsync.py", "-m", ..., "/tmp/targetdata", NULL);如果您想链接到特定的Python解释器,可以使用Mike的答案。但请注意,如果更新了Python,您的应用程序将更容易出现故障,而仅使用exec则不一定会出现这种情况。 - Antti Haapala -- Слава Україні

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接