如何在Xcode中将Python函数导入C?

1 投票
1 回答
670 浏览
提问于 2025-04-17 16:25

我正在尝试把C语言和Python结合起来做研究,但我的代码出现了一些问题。我用了一个教程里的代码,但似乎获取Python文件的代码不太好使。以下是代码:

helloClass.py

def sayHello(name):
return "Hello " + name + "!"

main.c

int main(int argc, const char * argv[]) {
char name[50];
printf("What's your name?\n");
fgets(name, 64, stdin);
char *answer = NULL;
PyObject *modname, *mod, *mdict, *func, *stringarg, *args, *rslt;
Py_Initialize();
PySys_SetPath(Py_GetPath()); 
modname = PyString_FromString("helloClass");
mod = PyImport_Import(modname);// Here mod = null because it can´t find it.
if (mod){
    mdict = PyModule_GetDict(mod);
    func = PyDict_GetItemString(mdict, "sayHello");
    if (func){
        if (PyCallable_Check(func)) {
            stringarg = PyString_FromString(name);
            args = PyTuple_New(1);
            PyTuple_SetItem(args, 0, stringarg);
            rslt = PyObject_CallObject(func, args);
            if (rslt) {
                answer = PyString_AsString(rslt);
                Py_XDECREF(rslt);
            }
            Py_XDECREF(stringarg);
            Py_XDECREF(args);
        }
        Py_XDECREF(mdict);
        Py_XDECREF(func);
    }
    Py_XDECREF(modname);
    Py_XDECREF(mod);
}
printf("%s", answer);
answer = NULL; }

1 个回答

1

这里的信息不够详细,无法给出完整的答案,但基本问题几乎肯定是 helloClass.py 没有出现在模块搜索路径上,所以 PyImport_Import 找不到它。

举个例子,可能你把 main 可执行文件放在了像 ~/Library/Developer/Xcode/DerivedData/Hello/Build/Products/Release/hello 这样的地方,但没有把 helloClass.py 复制到那里。或者,可能你确实把它复制过去了,但 dirname $0 的结果不在你的模块路径上。还有很多其他可能性,但每种情况的答案都是一样的:

  1. 找出可执行文件和 Python 文件被安装到哪里。

  2. 根据这些信息构建一个合适的(可能是相对的)路径。

  3. 确保这个路径被添加到模块路径中。

Python 搜索模块的具体细节在不同版本之间有所不同,但基本思路可以在 import 语句(或者 3.3 版本,它又参考了 导入系统)中找到,通常只需要在 sys.path 中添加一些东西。

(注意,如果你构建的是 .app 包而不是简单的 Unix 命令行可执行文件,有一个标准的解决方案——你把 .py 文件放在一个标准位置,使用 Cocoa 或 CoreFoundation API 获取路径,然后使用这个路径。但这似乎在这里不太相关。)


看看你上传的项目 https://github.com/Eduardof0nt/help.git

你没有把 helloClass.py 复制到任何地方。你需要决定 要把它复制到哪里,这完全取决于你想如何部署它。但为了调试方便,想要得到一个可以测试的东西,你可以把它放在 Hello Python! 可执行文件旁边(在 build/Debugbuild/Release 中)。具体操作如下:

  • 在项目导航器中选择项目。
  • 在出现的项目视图左侧边栏中选择目标。
  • 选择构建阶段标签。
  • 点击添加构建阶段按钮。
  • 添加一个复制文件阶段。
  • 将目标设置为产品目录。
  • helloClass.py 从项目导航器拖到构建阶段中。

现在,当你构建时,如果查看输出(打开“所有”和“所有消息”),你会看到“复制 build/Debug/helloClass.py”紧接在“链接 build/Debug/Hello Python!”之后。如果你查看那个目录,会看到这两个文件并排放着。

但这并不能解决你所有的问题。因为 /wherever/you/started/build/Debug 不会在 Python 使用的 sys.path 中。解决这个问题的最快方法是在 Py_Initialize() 之前调用 Py_SetProgramName(argv[0]),然后在之后调用 PySys_SetArgvEx(argc, argv, 1)。这可能不适合你的使用场景,但你需要阅读文档,了解这些操作的具体作用,因为我无法在 StackOverflow 的回答中解释所有嵌入 Python 的细节。

在你学习这些内容时,可能需要进行一些调试。例如,你可以使用 printf(path=%s\n", Py_GetPath()) 来查看 sys.path 的内容,使用 PyObject_Print(mod, stdout, 0) 来查看 mod 中的内容,等等。但实际上,你会想使用 Xcode 调试器——设置一个断点,尝试在运行时进行这些操作。

很多内容在 扩展和嵌入 Python 解释器 中有解释,你确实需要阅读这些;没有替代品。(你不需要阅读整个 Python/C API 参考手册,但你最终会阅读很多内容,并在完成之前熟练搜索它。)然而,由于嵌入 Python 比扩展它要少见得多,文档中并没有包含你需要的所有内容,所以……如果你使用的教程没有涵盖 PySys_*Py_GetPath 之类的内容,你可能需要先找到一个更好的教程。

撰写回答