从 C/C++ 调用 python 方法,并提取其返回值
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3286448/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Calling a python method from C/C++, and extracting its return value
提问by dzhelil
I'd like to call a custom function that is defined in a python module from C. I have some preliminary code to do that, but it just prints the output to stdout.
我想从 C 调用在 python 模块中定义的自定义函数。我有一些初步代码可以做到这一点,但它只是将输出打印到标准输出。
mytest.py
我的测试文件
import math
def myabs(x):
return math.fabs(x)
test.cpp
测试.cpp
#include <Python.h>
int main() {
Py_Initialize();
PyRun_SimpleString("import sys; sys.path.append('.')");
PyRun_SimpleString("import mytest;");
PyRun_SimpleString("print mytest.myabs(2.0)");
Py_Finalize();
return 0;
}
How can I extract the return value into a C double and use it in C?
如何将返回值提取到 C double 中并在 C 中使用它?
采纳答案by ThR37
As explained before, using PyRun_SimpleString seems to be a bad idea.
如前所述,使用 PyRun_SimpleString 似乎是一个坏主意。
You should definitely use the methods provided by the C-API (http://docs.python.org/c-api/).
您绝对应该使用 C-API ( http://docs.python.org/c-api/)提供的方法。
Reading the introduction is the first thing to do to understand the way it works.
阅读介绍是了解其工作方式的第一件事。
First, you have to learn about PyObject that is the basic object for the C API. It can represent any kind of python basic types (string, float, int,...).
首先,您必须了解 PyObject,它是 C API 的基本对象。它可以表示任何类型的 Python 基本类型(字符串、浮点数、整数...)。
Many functions exist to convert for example python string to char* or PyFloat to double.
存在许多函数来将例如 python 字符串转换为 char* 或 PyFloat 转换为 double。
First, import your module :
首先,导入你的模块:
PyObject* myModuleString = PyString_FromString((char*)"mytest");
PyObject* myModule = PyImport_Import(myModuleString);
Then getting a reference to your function :
然后获取对您的函数的引用:
PyObject* myFunction = PyObject_GetAttrString(myModule,(char*)"myabs");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(2.0));
Then getting your result :
然后得到你的结果:
PyObject* myResult = PyObject_CallObject(myFunction, args)
And getting back to a double :
并回到 double :
double result = PyFloat_AsDouble(myResult);
You should obviously check the errors (cf. link given by Mark Tolonen).
您显然应该检查错误(参见 Mark Tolonen 提供的链接)。
If you have any question, don't hesitate. Good luck.
如果您有任何问题,请不要犹豫。祝你好运。
回答by Pablo Alejandro Costesich
You have to extract the python method somehow and run it with PyObject_CallObject(). To do that, you can provide Python a way to set the function, as the Extending and Embedding Python Tutorialexample does.
您必须以某种方式提取 python 方法并使用PyObject_CallObject(). 为此,您可以为 Python 提供一种设置函数的方法,就像扩展和嵌入 Python 教程示例所做的那样。
回答by Mark Tolonen
A complete example of calling a Python function and retrieving the result is located at http://docs.python.org/release/2.6.5/extending/embedding.html#pure-embedding:
调用 Python 函数并检索结果的完整示例位于http://docs.python.org/release/2.6.5/extending/embedding.html#pure-embedding:
#include <Python.h>
int
main(int argc, char *argv[])
{
PyObject *pName, *pModule, *pDict, *pFunc;
PyObject *pArgs, *pValue;
int i;
if (argc < 3) {
fprintf(stderr,"Usage: call pythonfile funcname [args]\n");
return 1;
}
Py_Initialize();
pName = PyString_FromString(argv[1]);
/* Error checking of pName left out */
pModule = PyImport_Import(pName);
Py_DECREF(pName);
if (pModule != NULL) {
pFunc = PyObject_GetAttrString(pModule, argv[2]);
/* pFunc is a new reference */
if (pFunc && PyCallable_Check(pFunc)) {
pArgs = PyTuple_New(argc - 3);
for (i = 0; i < argc - 3; ++i) {
pValue = PyInt_FromLong(atoi(argv[i + 3]));
if (!pValue) {
Py_DECREF(pArgs);
Py_DECREF(pModule);
fprintf(stderr, "Cannot convert argument\n");
return 1;
}
/* pValue reference stolen here: */
PyTuple_SetItem(pArgs, i, pValue);
}
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL) {
printf("Result of call: %ld\n", PyInt_AsLong(pValue));
Py_DECREF(pValue);
}
else {
Py_DECREF(pFunc);
Py_DECREF(pModule);
PyErr_Print();
fprintf(stderr,"Call failed\n");
return 1;
}
}
else {
if (PyErr_Occurred())
PyErr_Print();
fprintf(stderr, "Cannot find function \"%s\"\n", argv[2]);
}
Py_XDECREF(pFunc);
Py_DECREF(pModule);
}
else {
PyErr_Print();
fprintf(stderr, "Failed to load \"%s\"\n", argv[1]);
return 1;
}
Py_Finalize();
return 0;
}
回答by Kylotan
If you assign the return value to a variable, then you can use something like PyEval_GetGlobals() and PyDict_GetItemString() to get the PyObject. From there, PyNumber_Float can get you the value you want.
如果将返回值分配给变量,则可以使用 PyEval_GetGlobals() 和 PyDict_GetItemString() 之类的方法来获取 PyObject。从那里, PyNumber_Float 可以为您提供您想要的值。
I suggest browsing through the whole API - certain things become obvious when you see the different methods that are available to you, and there may well be a better method than the one I've described.
我建议浏览整个 API - 当您看到可用的不同方法时,某些事情变得显而易见,并且很可能有比我描述的方法更好的方法。
回答by user3758062
I have done it using BOOST to embedded Python to C++ [This working C module should help]
我已经使用 BOOST 将 Python 嵌入到 C++ [这个工作的 C 模块应该有所帮助]
#include <boost/python.hpp>
void main()
{
using namespace boost::python;
Py_Initialize();
PyObject* filename = PyString_FromString((char*)"memory_leak_test");
PyObject* imp = PyImport_Import(filename);
PyObject* func = PyObject_GetAttrString(imp,(char*)"begin");
PyObject* args = PyTuple_Pack(1,PyString_FromString("CacheSetup"));
PyObject* retured_value = PyObject_CallObject(func, args); // if you have arg
double retured_value = PyFloat_AsDouble(myResult);
std::cout << result << std::endl;
Py_Finalize();
}
回答by kilojoules
Here is a sample code I wrote (with the help of various online sources) to send a string to a Python code, then return a value.
这是我编写的示例代码(在各种在线资源的帮助下)将字符串发送到 Python 代码,然后返回一个值。
Here is the C code call_function.c:
这是C代码call_function.c:
#include <Python.h>
#include <stdlib.h>
int main()
{
// Set PYTHONPATH TO working directory
setenv("PYTHONPATH",".",1);
PyObject *pName, *pModule, *pDict, *pFunc, *pValue, *presult;
// Initialize the Python Interpreter
Py_Initialize();
// Build the name object
pName = PyString_FromString((char*)"arbName");
// Load the module object
pModule = PyImport_Import(pName);
// pDict is a borrowed reference
pDict = PyModule_GetDict(pModule);
// pFunc is also a borrowed reference
pFunc = PyDict_GetItemString(pDict, (char*)"someFunction");
if (PyCallable_Check(pFunc))
{
pValue=Py_BuildValue("(z)",(char*)"something");
PyErr_Print();
printf("Let's give this a shot!\n");
presult=PyObject_CallObject(pFunc,pValue);
PyErr_Print();
} else
{
PyErr_Print();
}
printf("Result is %d\n",PyInt_AsLong(presult));
Py_DECREF(pValue);
// Clean up
Py_DECREF(pModule);
Py_DECREF(pName);
// Finish the Python Interpreter
Py_Finalize();
return 0;
}
Here is the Python code, in file arbName.py:
这是文件中的 Python 代码arbName.py:
def someFunction(text):
print 'You passed this Python program '+text+' from C! Congratulations!'
return 12345
I use the command gcc call_function.c -I/usr/include/python2.6 -lpython2.6 ; ./a.outto run this process. I'm on redhat. I recommend using PyErr_Print(); for error checking.
我使用命令gcc call_function.c -I/usr/include/python2.6 -lpython2.6 ; ./a.out来运行这个过程。我在红帽上。我推荐使用 PyErr_Print(); 用于错误检查。
回答by lama12345
To prevent the extra .py file as in the other answers, you can just retrieve the __main__module, which is created by the first call to PyRun_SimpleString:
为了防止在其他答案中出现额外的 .py 文件,您可以只检索__main__模块,该模块由第一次调用创建PyRun_SimpleString:
PyObject *moduleMainString = PyString_FromString("__main__");
PyObject *moduleMain = PyImport_Import(moduleMainString);
PyRun_SimpleString(
"def mul(a, b): \n"\
" return a * b \n"\
);
PyObject *func = PyObject_GetAttrString(moduleMain, "mul");
PyObject *args = PyTuple_Pack(2, PyFloat_FromDouble(3.0), PyFloat_FromDouble(4.0));
PyObject *result = PyObject_CallObject(func, args);
printf("mul(3,4): %.2f\n", PyFloat_AsDouble(result)); // 12
回答by Ashish Magar
Here is a simple and direct answer to your question:
这是对您的问题的简单直接的回答:
#include <iostream>
#include <Python.h>
using namespace std;
int main()
{
const char *scriptDirectoryName = "/yourDir";
Py_Initialize();
PyObject *sysPath = PySys_GetObject("path");
PyObject *path = PyString_FromString(scriptDirectoryName);
int result = PyList_Insert(sysPath, 0, path);
PyObject *pModule = PyImport_ImportModule("mytest");
PyObject* myFunction = PyObject_GetAttrString(pModule,(char*)"myabs");
PyObject* args = PyTuple_Pack(1,PyFloat_FromDouble(-2.0));
PyObject* myResult = PyObject_CallObject(myFunction, args);
double getResult = PyFloat_AsDouble(myResult);
return 0;
}

