一、环境准备
假设python安装位置为:C://python310
编译环境为:
- 头文件 位置:C://python310//include
- lib库 位置:C://python310//libs (需要python310.lib)
运行环境为:
- dll动态库 位置:C://python310 (需要python310.dll)
- pyd扩展库 位置:
- Python库 位置:C://python310//Lib
二、执行python字符串
void python1() // 执行Python字符串{// 设置Python的home路径Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");// Python解释器初始化Py_Initialize();int ret = 0;// 执行Python脚本字符串,执行在 __main__ 模块ret = PyRun_SimpleString("print('hello world')");ret = PyRun_SimpleString("print(f'__name__ = {__name__}')");// 都是执行在__main__模块下的,所以可以访问变量ret = PyRun_SimpleString("a=10");ret = PyRun_SimpleString("print(a)");if (ret != 0) {PyErr_Print(); // 输出错误信息}//Py_Finalize();}
- 需要先设置python的home目录,此步骤必须在初始化python解释器之前调用。
- 初始化python解释器
- 执行python脚本,通过
PyRun_SimpleString()- python脚本字符串都执行在
__main__模块,相当于 C++ 的void main(int argc, char* argv[]){ } - 即使先通过PyRun_SimpleString()设置一个变量,后面也是可以调用该变量的
PyRun_SimpleString()会返回执行状态,是否执行成功的标识,0代表成功,1代表失败
- python脚本字符串都执行在
- 最后调用
Py_Finalize()销毁python解释器
三、执行python脚本
python文件:python_scripy.py
if __name__ == "__main__":
print("this is a python file")
C++代码:
void python2() // 执行Python文件
{
// 设置Python的home路径
Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
const char* filename = "python_scripy.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
Py_Finalize();
}
- 需要先设置python的home目录,此步骤必须在初始化python解释器之前调用。
- 初始化python解释器
- 通过
PyRun_AnyFile()打开文件,第一个参数为FILE*,第二个参数为文件名。 - 最后调用
Py_Finalize()销毁python解释器
四、获取python脚本的变量(以字典为例)
python文件:python_scripy.py
if __name__ == "__main__":
conf = {
"width": 1920,
"height": 1080,
"title": "C++ call python"
}
C++代码
void python3() // 执行Python文件并读取字典中元素的值
{ // 设置Python的home路径
Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
// 运行python文件
const char* filename = "python_scripy.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
// 获取主模块
PyObject* __main__ = PyUnicode_FromString("__main__");
PyObject* module = PyImport_GetModule(__main__); // 不清理参数,需要手动清理
Py_XDECREF(__main__);
// 根据模块和名称获取对象->字典
PyObject* conf = PyObject_GetAttrString(module, "conf");
if (!conf) {
cout << " conf not find!" << endl;
}
// 从字典中取值
PyObject* keyWidth = PyUnicode_FromString("width");
int width = PyLong_AsLong(PyDict_GetItem(conf, keyWidth));
Py_XDECREF(keyWidth);
PyObject* keyHeight = PyUnicode_FromString("height");
int height = PyLong_AsLong(PyDict_GetItem(conf, keyHeight));
Py_XDECREF(keyHeight);
cout << "width: " << width << " height: " << height << endl;
PyObject* keyTitle = PyUnicode_FromString("title");
wchar_t title[1024] = { 0 };
int size = PyUnicode_AsWideChar(PyDict_GetItem(conf, keyHeight), title, 1024);
Py_XDECREF(keyTitle);
wcout << "size: " << size << " title: " << title << endl;
Py_XDECREF(conf);
Py_XDECREF(module);
Py_Finalize();
}
- 需要先设置python的home目录,此步骤必须在初始化python解释器之前调用。
- 初始化python解释器
- 获取主模块
- 通过
PyUnicode_FromString("__main__")获取__main__这个变量 - 将
__main__这个变量传递给PyImport_GetModule()即可
- 通过
- 通过key获取字典的value
- 通过
PyObject_GetAttrString()获取字典对象,第一个参数为模块对象,第二个参数为字典变量的名称 - 通过
PyUnicode_FromString()获取该key对应的value对象 - 通过
PyLong_AsLong()/PyUnicode_AsWideChar()转换为C++的类型
- 通过
- 最后调用
Py_Finalize()销毁python解释器注:创建一个
**PyObject***记得通过**Py_XDECREF()**进行释放
五、调用python的类实例化并访问成员函数和成员变量
python文件:python_scripy.py
class TypePy:
global_field = 99
def __init__(self):
print("TypePy init")
def test(self):
print("TypePy test")
def test_param(self, num:int, value:str):
print(f"num: {num}, value: {value}")
return "test_param"
C++代码
void python4() // 调用python的类实例化对象、访问成员函数和成员
{
// 设置Python的home路径
Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
// 运行python文件
const char* filename = "python_scripy.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
// 获取主模块
PyObject* __main__ = PyUnicode_FromString("__main__");
PyObject* module = PyImport_GetModule(__main__); // 不清理参数,需要手动清理
Py_XDECREF(__main__);
// 1.获取类
PyObject* typePy = PyObject_GetAttrString(module, "TypePy");
if (!typePy) {
cout << "get class TypePy failed!" << endl;
return;
}
// 2.实例化对象, 即调用构造函数__init__。
PyObject* object = PyObject_CallObject(typePy, nullptr);
if (!object) {
cout << "create TypePy object failed!" << endl;
}
// 3. 调用成员函数(无参数)
PyObject_CallMethod(object, "test", nullptr);
// 4. 调用成员函数(带参数并含返回值,如果有返回值需要清理)
PyObject* func = PyObject_CallMethod(object, "test_param", "is", 100, "student");
const char* funcRet = PyUnicode_AsUTF8(func);
cout << "return: " << funcRet << endl;
// 5. 成员变量
PyObject* var = PyObject_GetAttrString(object, "global_field");
cout << "TypePy id=" << PyLong_AsLong(var) << endl;
Py_XDECREF(var);
Py_XDECREF(func);
Py_XDECREF(object);
Py_XDECREF(typePy);
// 类
Py_XDECREF(module);
Py_Finalize();
}
六、调用python函数并传递list参数及获取返回值
python文件:python_scripy.py
def func_main1():
print("python func main1")
def func_main2(a_list:list):
print(f"python func main2-> param:{a_list}")
return [1,2,3,4,5,6, 8]
C++代码
void python5() // 调用python函数并传递list参数并获取返回
{
// 设置Python的home路径
Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
// 运行python文件
const char* filename = "python_scripy.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
// 获取主模块
PyObject* __main__ = PyUnicode_FromString("__main__");
PyObject* module = PyImport_GetModule(__main__); // 不清理参数,需要手动清理
Py_XDECREF(__main__);
// 调用python的函数
PyObject* func1 = PyObject_GetAttrString(module, "func_main1"); // 无参无返回值
if (func1 && PyCallable_Check(func1)) {
PyObject_CallObject(func1, 0);
}
Py_XDECREF(func1);
PyObject* func2 = PyObject_GetAttrString(module, "func_main2"); // 带参带返回值
if (func1 && PyCallable_Check(func1)) {
// 参数准备 参数变量是tuple
PyObject* args = PyTuple_New(1); // 参数元组1只有一个参数
// 传递的list对象
PyObject* lst = PyList_New(0);
for (int i = 0; i < 5; i++) {
PyList_Append(lst, PyLong_FromLong(i + 100));
}
// 将list写入参数列表
PyTuple_SetItem(args, 0, lst);
// 函数对象和参数 返回对象
PyObject* ret = PyObject_CallObject(func2, args);
int size = PyList_Size(ret);
cout << "size: " << size << endl;
// 获取返回值
list<int> a_list;
for (int i = 0; i < size; i++) {
PyObject* val = PyList_GetItem(ret, i);
if (!val)
continue;
// printf("[%ld]", PyLong_AsLong(val));
a_list.push_back(PyLong_AsLong(val));
}
for (int item : a_list) {
cout << item << " ";
}
Py_XDECREF(ret);
Py_XDECREF(args); // lst也在args中销毁
}
// 类
Py_XDECREF(module);
Py_Finalize();
}
七、给python传递变量的两种方法
python文件:python_scripy.py
if __name__ == "__main__":
print(f"a={a}")
print(f"count={count}")
C++代码
//传递位置 要在python代码调用之前
void python6() // 给python传递变量的两种方法
{
// 设置Python的home路径
Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
// 获取主模块
PyObject* __main__ = PyUnicode_FromString("__main__");
PyObject* module = PyImport_GetModule(__main__); // 不清理参数,需要手动清理
Py_XDECREF(__main__);
// 方法1. 只能传给主模块(__main__)
PyRun_SimpleString("a=888");
// 方法2. 空间转给python管理
PyObject_SetAttrString(module, "count", PyLong_FromLong(777));
// 运行python文件
const char* filename = "python_scripy.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
// 类
Py_XDECREF(module);
Py_Finalize();
}
八、给python传递函数
python文件:python_scripy.py
if __name__ == "__main__":
test_cfun()
C++代码
static PyObject* test_cfun(PyObject* self, PyObject* args)
{
cout << "in c++ call test_cfun function" << endl;
Py_RETURN_TRUE;
}
//传递位置 要在python代码调用之前
void python7() // 给python传递函数和类 PyModule_Ad
{
// 设置Python的home路径
Py_SetPythonHome(L"D:\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
// 获取主模块
PyObject* __main__ = PyUnicode_FromString("__main__");
PyObject* module = PyImport_GetModule(__main__); // 不清理参数,需要手动清理
Py_XDECREF(__main__);
// 给python传递函数
PyMethodDef cfunc[] = {
{ "test_cfun", test_cfun, METH_VARARGS, 0 },
{ nullptr }
};
PyModule_AddFunctions(module, cfunc);
// 运行python文件
const char* filename = "python_scripy.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
// 类
Py_XDECREF(module);
Py_Finalize();
}
八、给python传递类
九、读取python模块并给python主模块传递模块
python文件:python_scripy.py
if __name__ == "__main__":
testmod.testmod()
python文件:testmod.py
print("this is testmod")
def testmod():
print("testmod function")
C++代码
void python8() // 读取python模块并给python主模块传递
{
// 设置Python的home路径
Py_SetPythonHome(L"D:\\AB_Code\\CPP\\CppCallPython\\Python");
// Python解释器初始化
Py_Initialize();
// 获取主模块
PyObject* __main__ = PyUnicode_FromString("__main__");
PyObject* module = PyImport_GetModule(__main__); // 不清理参数,需要手动清理
Py_XDECREF(__main__);
// 读取模块 脚本文件直接当做模块
PyObject* testmod = PyImport_ImportModule("testmod");
if (!testmod) {
cout << "PyImport_ImportModule testmod failed" << endl;
return;
}
PyModule_AddObject(module, "testmod", testmod);
// 运行python文件
const char* filename = "python_test.py";
FILE* fp = fopen(filename, "r");
if (!fp) {
cout << "open file " << filename << " failed.";
}
int ret = PyRun_AnyFile(fp, filename);
if (ret != 0) {
PyErr_Print();
cout << "PyRun_AnyFile failed!" << endl;
Py_Finalize();
return;
}
// 类
Py_XDECREF(module);
Py_Finalize();
}
注意:testmod.py需要和可执行文件位于同一目录,否则会导入模块失败
