C++调用python

Qt调用python方法

 

 

1 接口

2 方法汇总

2.1.外部工具法Qt creator

2.2.Python官方提供的与C++交互编程方法。

1 运行python代码例子

2. 参数传递

例子3

二、含tensorflow第三方库

4 代码总结

Python虚拟机的初始化及退出

Python List API

矩阵

2.3 使用PythonQt库

2.4 boost::python

 

1 接口

上面我们提到过要让机器“学习”,一般需要:

  1. 用来解决问题的模型model

 

  1. 学习数据(或者说训练数据)data

存放在列表,表格中;

 

  1. 让模型model通过数据data学会解决特定问题的学习算法learn

 

调试:

如果python程序中包含了其他第三方库,则调用极可能出错,且不易查明原因。如笔者曾用c程序调用包含tensorflow的python程序,有的可以成功,有的则卡在某条语句,百般尝试也未能实现。

在调用含有第三方库的python程序时,首先需要保证在cmd下运行python程序无误。

C++调用例子代码正常;

2 方法汇总

2.1.外部工具法Qt creator

https://blog.csdn.net/alxe_made/article/details/83382159

 

2.2.Python官方提供的与C++交互编程方法。

 

 

1 运行python代码例子

 

#define PY_SSIZE_T_CLEAN #include int main(int argc, char *argv[]) { wchar_t *program = Py_DecodeLocale(argv[0], NULL); if (program == NULL) { fprintf(stderr, "Fatal error: cannot decode argv[0]\n"); exit(1); } Py_SetProgramName(program); /* optional but recommended */ Py_Initialize(); PyRun_SimpleString("from time import time,ctime\n" "print('Today is', ctime(time()))\n"); if (Py_FinalizeEx() < 0) { exit(120); } PyMem_RawFree(program); return 0; }

 

 

 

问题:无法打开包括文件:“python.h”: No such file or directory

说明bat里面和pro文件没把python的include目录等告诉项目;

 

问题:无法打开包括文件:“inttypes.h”: No such file or directory

解决方法:删除之,并在其之前添加如下代码:

#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)

#      define CONFIG_WIN32

#endif

#if defined(WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) && !defined(EMULATE_INTTYPES)

#      define EMULATE_INTTYPES

#endif

#ifndef EMULATE_INTTYPES

#     include

#else

      typedef signed char    int8_t;

      typedef signed short int16_t;

      typedef signed int     int32_t;

      typedef unsigned char    uint8_t;

      typedef unsigned short uint16_t;

      typedef unsigned int     uint32_t;

#     ifdef CONFIG_WIN32

          typedef signed __int64     int64_t;

          typedef unsigned __int64 uint64_t;

#     else /* other OS */

          typedef signed long long     int64_t;

          typedef unsigned long long uint64_t;

#     endif /* other OS */

#endif /* EMULATE_INTTYPES */

 

 

LNK1104: 无法打开文件“python38_d.lib”

有3个方案:

  1. 将python36.lib复制一份,重命名为python36_d.lib
  2. 修改pyconfig.h文件(奇怪,我在3.8说的文件没这个内容)。

参照网上的解决办法,是将目录Python35\include下的pyconfig.h文件中的

#ifdefined(_DEBUG)

//# pragma comment(lib,"python35_d.lib")

#pragmacomment(lib,"python34.lib") // no debug lib in python distribution

#elif...

#ifdef _DEBUG

//# define Py_DEBUG

#endif

 

uploading.4e448015.gif转存失败重新上传取消

黑体部分注释掉即可。不知会不会产生其他错误,现在标记一下。

 

LNK2019: 无法解析的外部符号 __imp__Py_FinalizeEx

等等

fatal error LNK1120: 10 个无法解析的外部命令

 

在3.6中解决inttypes.h的报错后,

我在vs中得配置平台是win32,而pthon2.7是64位的,将配置平台改为活动x64后编译通过(平台如何修改:右击项目 -> 属性->最上面的平台修改即可)。

 

3.下载python的源代码,用VS重新编译;

在解决这个问题之前,请先确保你安装了python的debug版本,如果没有,可以修改已经安装的python,如下图所示

勾选最后一项,然后install

uploading.4e448015.gif转存失败重新上传取消

然后,解决方法很简单,给如下图所示的项目添加python37_d.lib所在的路径即可

【安装失败,估计是VS2008太老了,安装VS2017看看】

安装VS2017后,发现还是不行,打开软件安装日志查看是安装包没下载,人工下载后,安装失败;

Error 0x80072f7d: Failed to send request to URL: https://www.python.org/ftp/python/3.8.1/win32/core_pdb.msi, trying to process HTTP status code anyway.

 

uploading.4e448015.gif转存失败重新上传取消

VS2017安装的时候安装了python3.6的64位版本,用3.6看看;

 

下载源代码;

1)命令行进入到解压目录的PCbuild,如X:\Python-2.7.16\PCbuild

2)运行get_externals.bat,下载外部库,如图所示

我的运行失败;

0x03 编译

1)打开PCbuild目录的pcbuild.sln,根据需要选择后点“确定”,如图所示:

 

C++调用python_第1张图片

 

2)先选择python、pythoncore的win32 debug 版本测试编译,如图所示:

 

C++调用python_第2张图片

 

 

3)编译失败,需要修改相关标识符

 

C1189 #error: "No Target Arc

C++调用python_第3张图片

 定位错误位置在winnt.h

#if defined(_AMD64_) || defined(_X86_) #define PROBE_ALIGNMENT( _s ) TYPE_ALIGNMENT( DWORD ) #elif defined(_IA64_) || defined(_ARM_) || defined(_ARM64_) #define PROBE_ALIGNMENT( _s ) TYPE_ALIGNMENT( DWORD ) #elif !defined(RC_INVOKED) #error "No Target Architecture" #endif

原因也很简答,就是没有定义 (_AMD64_) 、(_X86_)这几个宏,编译器检查到,就抛出异常

我选择在项目中添加_AMD64_宏(其他三个也可以)解决该问题。

具体方法:项目名称右键-->属性-->C/C++-->预处理器-->添加宏,如下所示:

 

 

4)timezone改为_timezone , daylight改为daylight , tzname改为tzname后,重新编译[未出现]

1 #ifdef PYOS_OS2 2 PyModule_AddIntConstant(m, "timezone", _timezone); 3 #else /* !PYOS_OS2 */ 4 PyModule_AddIntConstant(m, "timezone", _timezone); 5 #endif /* PYOS_OS2 */ 6 #ifdef HAVE_ALTZONE 7 PyModule_AddIntConstant(m, "altzone", altzone); 8 #else 9 #ifdef PYOS_OS2 10 PyModule_AddIntConstant(m, "altzone", _timezone-3600); 11 #else /* !PYOS_OS2 */ 12 PyModule_AddIntConstant(m, "altzone", _timezone -3600); 13 #endif /* PYOS_OS2 */ 14 #endif 15 PyModule_AddIntConstant(m, "daylight", _daylight); 16 PyModule_AddObject(m, "tzname", 17 Py_BuildValue("(zz)", _tzname[0], _tzname[1]));

 

5)编译仍然失败,如下图所示:

 

6)找到pythoncore 工程的posixmodule.c , 修改_PyVerify_fd如下[未出现]

/* This function emulates what the windows CRT does to validate file handles */ int _PyVerify_fd(int fd) { // const int i1 = fd >> IOINFO_L2E; // const int i2 = fd & ((1 << IOINFO_L2E) - 1); // static int sizeof_ioinfo = 0; // /* Determine the actual size of the ioinfo structure, // * as used by the CRT loaded in memory // */ // if (sizeof_ioinfo == 0 && __pioinfo[0] != NULL) { // sizeof_ioinfo = _msize(__pioinfo[0]) / IOINFO_ARRAY_ELTS; // } // if (sizeof_ioinfo == 0) { // /* This should not happen... */ // goto fail; // } // /* See that it isn't a special CLEAR fileno */ // if (fd != _NO_CONSOLE_FILENO) { // /* Microsoft CRT would check that 0<=fd<_nhandle but we can't do that. Instead // * we check pointer validity and other info // */ // if (0 <= i1 && i1 < IOINFO_ARRAYS && __pioinfo[i1] != NULL) { // /* finally, check that the file is open */ // my_ioinfo* info = (my_ioinfo*)(__pioinfo[i1] + i2 * sizeof_ioinfo); // if (info->osfile & FOPEN) { // return 1; // } // } // } //fail: // errno = EBADF; //a call to _get_osfhandle with invalid fd sets errno to EBADF if (_get_osfhandle(fd) == INVALID_HANDLE_VALUE) return 0; else return 1; return 0; }

 

7)再次编译,编译成功。

 

8)根据需要选择相应库进行编译

 

Python-3.6.10\PCbuild打开python.vcxproj

以下这两个操作必不可少!

 

1、将python37_d.lib所在文件夹的路径添加到库目录里面

2、然后在附加依赖项中添加python37_d.lib,就是刚才找不到的这个库文件的名字

3、重新右键生成opencv_python3,问题解决!发现生成的lib文件在本地d盘,没在c盘;

 

SyntaxError: (unicode error) 'utf-8' codec can't decode byte 0xc1 in position 0: invalid start byte

python中默认的编码格式是 utf-8,因此需要将编辑的文件格式进行转换为utf-8,只需对Geany软件进行如下设置:

在菜单栏中选择“文档”中的“设置文件编码”选择“Unicode(UTF-8)”,如图

 

 

无法打开包括文件:“pyconfig.h”: No such file or directory

文件对比发现VS2017配套安装的3.6是有这个文件的;

 

集成到组态计算软件中,报错:

pyconfig.h:ssize_t重定义

解决方法:

typedef _W64 int ssize_t_px;

继续编辑

include\object.h(190) : error C2059: 语法错误 : ";"

解决办法:

注释该行: //PyType_Slot *slots; /* terminated by slot==0. */

 

2. 参数传递

 

参数传递的意思就是将 C 的值传递给 py 的函数,然后进行计算输出。

 

将数据值从C转换为Python,

使用转换后的值对Python接口例程执行函数调用

将数据值从Python调用转换为C。

2. 例子

虽然该程序的功能相当大,但是大部分代码用于Python和C之间的数据转换以及错误报告。

第二个程序的目标是在Python脚本中执行一个函数,现在这里需要传递参数。与关于非常高级接口的部分一样,Python解释器并不直接与应用程序交互(但这将在下一节中进行更改)。

 

运行Python脚本中定义的函数的代码是:

 

#define PY_SSIZE_T_CLEAN

#include

#include

int main(int argc, char *argv[])

{

QCoreApplication a(argc, argv);

PyObject *pName, *pModule, *pFunc;

PyObject *pArgs, *pValue;

int i;

if (argc < 3) {

fprintf(stderr,"用法: call pythonfile funcname [args]\n");

return 1;

}

Py_Initialize(); //初始化 Py 解释器

PyRun_SimpleString("import sys\n");

PyRun_SimpleString("print(sys.path.append('/Users/wangxinnian/Downloads/qtApp/testQP2'))\n");

pName = PyUnicode_DecodeFSDefault(argv[1]);

/* Error checking of pName left out */

pModule = PyImport_Import(pName);

Py_DECREF(pName);

if (pModule != nullptr) {

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 = PyLong_FromLong(atoi(argv[i + 3]));

if (!pValue) {

Py_DECREF(pArgs);

Py_DECREF(pModule);

fprintf(stderr, "不能转化参数\n");

return 1;

}

/* pValue reference stolen here: */

PyTuple_SetItem(pArgs, i, pValue);

}

pValue = PyObject_CallObject(pFunc, pArgs);

Py_DECREF(pArgs);

if (pValue != nullptr) {

printf("Result of call: %ld\n", PyLong_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;

}

if (Py_FinalizeEx() < 0) {

return 120;

}

return a.exec();

}

 

无法解析的外部符号 __imp___Py_RefTotal    

无法解析的外部符号 __imp___Py_NegativeRefcount,该符号在函数 __import_array 中被引用    

 

这是由于安装的python为Release版本,而你的C++项目为Debug模式,因此更改你的项目为Release模式。另外需要注意,区分32位和64位;然后重新编译;

 

(2)Python脚本文件MyMultiply.py代码,保存到代码指定的目录,没指定的话放c++的生成exe目录:

 

def multiply(a,b):

print("Will compute", a, "times", b)

c = 0

for i in range(0, a):

c = c + b

return c

 

(3)VS命令行参数:MyMultiply multiply 5 3

 

(4)程序运行结果:

uploading.4e448015.gif转存失败重新上传取消

 

例子3

/*

* test.cpp

* Created on: 2010-8-12

* Author: lihaibo

*/

#include

#include

#include

int main(void) {

Py_Initialize(); // 启动虚拟机

if (!Py_IsInitialized())

return -1;

// 导入模块

PyObject* pModule = PyImport_ImportModule("testpy");

if (!pModule) {

printf("Cant open python file!/n");

return -1;

}

// 模块的字典列表

PyObject* pDict = PyModule_GetDict(pModule);

if (!pDict) {

printf("Cant find dictionary./n");

return -1;

}

// 演示函数调用

PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi");

PyObject_CallFunction(pFunHi, "s", "lhb");

Py_DECREF(pFunHi);

// 演示构造一个Python对象,并调用Class的方法

// 获取Second类

PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second");

if (!pClassSecond) {

printf("Cant find second class./n");

return -1;

}

//获取Person类

PyObject* pClassPerson = PyDict_GetItemString(pDict, "Person");

if (!pClassPerson) {

printf("Cant find person class./n");

return -1;

}

//构造Second的实例

PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL);

if (!pInstanceSecond) {

printf("Cant create second instance./n");

return -1;

}

//构造Person的实例

PyObject* pInstancePerson = PyInstance_New(pClassPerson, NULL, NULL);

if (!pInstancePerson) {

printf("Cant find person instance./n");

return -1;

}

//把person实例传入second的invoke方法

PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson);

//释放

Py_DECREF(pInstanceSecond);

Py_DECREF(pInstancePerson);

Py_DECREF(pClassSecond);

Py_DECREF(pClassPerson);

Py_DECREF(pModule);

Py_Finalize(); // 关闭虚拟机

return 0;

}

 

 

例子4:tensorflow第三方库

在调用含有第三方库的python程序时,首先需要保证在cmd下运行python程序无误。环境配置如上文所述,但是很多时候程序在

 

pModule = PyImport_ImportModule("test3");//Python文件名

这一行出错,pModule 结果为null,原因通常是import tensorflow as tf这一句未能成功调用,将需调用的python程序中只保留这一句,可轻松验证。

经探索,可在原cpp文件中加入命令行参数即可成功运行。

 

/**

*Copyright @ 2019 Zhang Peng. All Right Reserved.

*Filename:

*Author: Zhang Peng

*Date:

*Version:

*Description:

**/

 

#include

#include

 

using namespace std;

 

int main()

{

//***python调用***//

//初始化python模块

Py_Initialize();

// 检查初始化是否成功

if (!Py_IsInitialized()) {

printf("py_initialize failed");

}

 

PyObject *pModule;

PyObject*pFunc = NULL;

PyObject*pArg = NULL;

 

//main命令行参数

int argc = 1;

wchar_t * argv[] = { L" " };

PySys_SetArgv(argc, argv); //加入argv参数 否则出错

 

pModule = PyImport_ImportModule("test3");//Python文件名

if (!pModule) {

printf("cannot open module!");

Py_Finalize();

return 0;

}

else

{

pFunc = PyObject_GetAttrString(pModule, "run");//Python文件中的函数名

if (!pFunc) {

printf("cannot open FUNC!");

Py_Finalize();

return 0;

}

else

{

PyObject* pPath = Py_BuildValue("(s)", "7513.jpg");

pArg = PyEval_CallObject(pFunc, pPath);//调用函数

int result;

PyArg_Parse(pArg, "i", &result);

cout << "预测结果: " << result << endl;

}

}

system("pause");

return 0;

}

 

 

以上代码中重要的地方就是加入以下几行代码

 

//main命令行参数

int argc = 1;

wchar_t * argv[] = { L" " };

PySys_SetArgv(argc, argv); //加入argv参数 否则出错

————————————————

 

4 代码总结

第1步是导入.py文件:

Python虚拟机的初始化及退出

初始化Python虚拟机需要调用Py_Initialize()来实现。

Py_IsInitialized()用于判断Python虚拟机初始化是否成功,True是成功,False是失败。

C/C++中调用Python之前必须先初始化虚拟机。

 

第2步是导入.py文件:

 

使用PyObject* pModule来存储导入的.py文件模块, 调用的方法是PyImport_ImportModule(path):  PyObject* pModule = PyImport_ImportModule("testpy"); 

使用PyObject* pDict来存储导入模块中的方法字典, 调用的方法是PyModule_GetDict(module):  PyObject* pDict = PyModule_GetDict(pModule); 

这样就完成了.py文件的导入.

 

第3步是导入已导入模块中的方法或类:

 

获取方法, 调用的方法是PyDict_GetItemString(dict, methodName): PyObject* pFunHi = PyDict_GetItemString(pDict, "sayhi"); 

获取类, 调用的方法同上, 注意红体部分的字符串对应于.py文件中的类/方法名:  PyObject* pClassSecond = PyDict_GetItemString(pDict, "Second"); 

 

第4步是使用导入的方法或类:

 

使用方法, 调用PyObject_CallFunction(pFunc, "s", args)即可:  PyObject_CallFunction(pFunHi, "s", "lhb"); 

使用类构造对象, 调用PyInstance_New(pClass, NULL, NULL)即可:  PyObject* pInstanceSecond = PyInstance_New(pClassSecond, NULL, NULL); , 注意其中的pClassSecond为第二步.2中获取的类指针

使用类对象的方法, 调用PyObject_CallMethod(pInstance, methodname, "O", args)即可:  PyObject_CallMethod(pInstanceSecond, "invoke", "O", pInstancePerson); 

上述调用中的"s"和"O"代表的是参数列表的类型, 我们可以在 Py_BuildValue 找到所有的类型, 本文最后也附了此表.

 

第5部 销毁和退出

最后不要忘记销毁这些对象:  Py_DECREF(pointer); 

退出虚拟机的时候调用Py_Finalize()。

进程退出时要退出Python虚拟机。

 

 

PyObject

Python的所有对象类型都是此类型的扩展。 这是一种类型,它包含Python将对象的指针视为对象所需的信息。 在正常的“发布”版本中,它仅包含对象的引用计数和指向相应类型对象的指针。 实际上没有任何东西被声明为PyObject,但是每个指向Python对象的指针都可以转换为PyObject *。 必须使用宏Py_REFCNT和Py_TYPE来访问成员。

 

宏描述,不包括全部

Py_TYPE: 获取Python对象的数据类型 Py_REFCNT: Python的引用计数器 Py_SIZE: 获取Python数据大小 还有很多...

Py_BuildValue

可以使用其将C的所有基本数据类型转换成Python可访问的数据类型。

标识符介绍:

s(str或None)[char *] 使用'utf-8'编码将以null结尾的C字符串转换为Python str对象。如果C字符串指针为NULL,则表示None。 s#(str或None)[char *,int] 使用'utf-8'编码将C字符串及其长度转换为Python str对象。如果C字符串指针为NULL,则忽略长度返回None。 y(字节)[char *] 这会将C字符串转换为Python字节对象。如果C字符串指针为NULL,则返回None。 y#(字节)[char *,int] 这会将C字符串及其长度转换为Python对象。如果C字符串指针为NULL,则返回None。 z(str或None)[char *] 与s相同。 z#(str或None)[char *,int] 与s#相同。 u(str)[Py_UNICODE *] 将Unicode(UCS-2或UCS-4)数据的以null结尾的缓冲区转换为Python Unicode对象。如果Unicode缓冲区指针为NULL,则返回None。 u#(str)[Py_UNICODE *,int] 将Unicode(UCS-2或UCS-4)数据缓冲区及其长度转换为Python Unicode对象。如果Unicode缓冲区指针为NULL,则忽略长度并返回None。 U(str或None)[char *] 与s相同。 U#(str或None)[char *,int] 与s#相同。 i(int)[int] 将普通的C int转换为Python整数对象。 b(int)[char] 将纯C char转换为Python整数对象。 h(int)[short int] 将普通的C short int转换为Python整数对象。 l(int)[long int] 将C long int转换为Python整数对象。 B(int)[unsigned char] 将C unsigned char转换为Python整数对象。 H(int)[unsigned short int] 将C unsigned short int转换为Python整数对象。 I(int)[unsigned int] 将C unsigned int转换为Python整数对象。 k(int)[unsigned long] 将C unsigned long转换为Python整数对象。 L(int)[long long] 将C long long转换为Python整数对象。 K(int)[unsigned long long] 将C unsigned long long转换为Python整数对象。 n(int)[Py_ssize_t] 将C Py_ssize_t转换为Python整数。 c(长度为1的字节)[char] 将表示字节的C int转换为长度为1的Python字节对象。 C(长度为1的str)[int] 将表示字符的C int转换为长度为1的Python str对象。 d(float) [double] 将C double转换为Python浮点数。 f(float) [float] 将C float转换为Python浮点数。 D(complex) [Py_complex *] 将C Py_complex结构转换为Python复数。 O(object) [PyObject *] 不改变Python对象的传递(引用计数除外,它增加1)。如果传入的对象是NULL指针,则假定这是因为产生参数的调用发现错误并设置了异常。因此,Py_BuildValue()将返回NULL但不会引发异常。如果尚未引发异常,则设置SystemError。 S(object) [PyObject *] 与O相同 N((object) [PyObject *] 与O相同,但不会增加对象的引用计数。通过调用参数列表中的对象构造函数创建对象时很有用。 O&(object) [converter, anything] 通过转换器函数将任何内容转换为Python对象。该函数被调用任何东西(应与void *兼容)作为其参数,并应返回“新”Python对象,如果发生错误则返回NULL。 (items) (tuple) [matching-items] 将一系列C值转换为具有相同项目数的Python元组。 [items](list) [matching-items] 将一系列C值转换为具有相同项目数的Python列表。 {items}(dict) [matching-items] 将一系列C值转换为Python字典。每对连续的C值将一个项添加到字典中,分别用作键和值。 如果格式字符串中存在错误,则设置SystemError异常并返回NULL。

void int_object(){ // 第一种方式 PyObject *py_ival = Py_BuildValue("i", -5987); // Python有符号整型 PyObject *py_ival2 = PyLong_FromLong(-8979); int ival = PyLong_AsLong(py_ival); // 把Python有字符整型转换成C的有字符整型 int ival2 = PyLong_AsLong(py_ival2); // 把Python有字符整型转换成C的有字符整型 printf("ival = %d, ival2 = %d\n", ival, ival2); // 第二种方式 PyObject *py_uval = Py_BuildValue("I", 465486); // Python无符号整型 PyObject *py_uval2 = PyLong_FromUnsignedLong(1654864); unsigned int uval = PyLong_AsUnsignedLong(py_uval); // 把Python无字符整型转换成C的无字符整型 unsigned int uval2 = PyLong_AsUnsignedLong(py_uval2); // 把Python无字符整型转换成C的无字符整型 printf("uval = %u, uval2 = %u\n", uval, uval2); }

创建长整型的Python对象

void long_object(){ // 第一种方式 PyObject *py_lval = Py_BuildValue("L", 45648946484984); // Python 长整型 long long c_lval = PyLong_AsLongLong(py_lval); // 转换成C的长整型 printf("clval = %lld\n", c_lval); // 第二种方式 PyObject *py_lval2 = PyLong_FromLongLong(234234623454525); // PyLong_FromLongLong 使用方法定义一个Python长整型 long long c_lval2 = PyLong_AsLongLong(py_lval2); // 转换成C的长整型 printf("clval2 = %lld\n", c_lval2); }

创建浮点类型的Python对象

 

 

void double_object(){ // 第一种方式 float fval = 632.045; PyObject *py_fval = Py_BuildValue("d", fval); // Python 浮点类型 float c_fval = PyFloat_AsDouble(py_fval); // C的浮点类型 printf("fval = %f\n", c_fval); // 第二种方式 double dval = 48941546.578; PyObject *py_dval = PyFloat_FromDouble(dval); // Python 浮点类型 double c_dval = PyFloat_AsDouble(py_dval); // C的浮点类型 printf("c_dval = %lf\n", c_dval); }

创建布尔类型对象

void boolean_object(){ // 第一种方式 bool bval = true; // false 反之 PyObject *py_bval = Py_BuildValue("b", bval); // Python 布尔类型 int c_bval = PyInt_AsLong(py_bval); printf("c_bval = %d\n", c_bval); // 第二种方式 bool bval2 = false; PyObject *py_bval2 = PyBool_FromLong(bval2); // Python 布尔类型 int c_bval2 = PyInt_AsLong(py_bval2); printf("c_bval2 = %d\n", c_bval2); }

创建Python string对象

void string_object(){ // 第一种方式 const char *pstr = "this is a test"; PyObject *py_str = Py_BuildValue("s", pstr); // Python 字符串对象 char *c_pstr = PyString_AsString(py_str); // 转成C的字符指针 printf("c_pstr = %s\n", c_pstr); // 第二种方式 const char *pstr2 = "this is a test1"; PyObject *py_str2 = PyString_FromString(pstr2); // Python 字符串对象 char *c_pstr2 = PyString_AsString(py_str2); // 转成C的字符指针 printf("c_pstr2 = %s\n", c_pstr2); // 创建一个二进制的字符串对象 // 第一种方式 const int mem_len = 1024; char *mem = new char[mem_len]; PyObject *py_mem = Py_BuildValue("s#", mem, mem_len); // 1. 数据的类型 2. 指向数据的指针 3. 数据的长度 int c_data_len = PyString_Size(py_mem); printf("c_data_len = %d\n", c_data_len); // 第二种方式 PyObject *py_mem2 = PyString_FromStringAndSize(mem, mem_len); int c_data_len2 = PyString_Size(py_mem2); printf("c_data_len2 = %d\n", c_data_len2); }

创建unicode字符串对象

void unicode_object(){ const char *p_ustr = "兰玉磊"; PyObject *py_unicode = PyUnicode_FromString(p_ustr); // 把C的字符串转成Python的unicode // 把unicode转成C的字符串 PyObject *py_utf8 = PyUnicode_AsUTF8String(py_unicode); // 把unicode转成utf-8 const char *c_string = PyString_AsString(py_utf8); // 把utf-8转成c的字符串 printf("c_utf8 = %s\n", c_string); // 格式化unicode字符串 // 创建一个unicode字符串 PyObject *py_unicode_fmt = PyUnicode_FromFormat("%s%d%s", "我今年", 18, "岁"); // 把unicode转C字符串 PyObject *py_utf8_fmt = PyUnicode_AsUTF8String(py_unicode_fmt); const char *utf8_fmt = PyString_AsString(py_utf8_fmt); printf("utf8_fmt = %s\n", utf8_fmt); }

使用Py_None

Py_None是一个全局的变量

PyObject* none_object(){ Py_RETURN_NONE; // 不需要自己return }

 

Python List API

List API 简单介绍

int PyList_Check(PyObject *p) 判断是否是一个Python List(列表)

PyObject* PyList_New(Py_ssize_t len) 创建一个列表

Py_ssize_t PyList_Size(PyObject *list) 获取列表元素的个数 len(list)

 

Python Dict API

Dict API 简单介绍

int PyDict_Check(PyObject *p) 判断对象是不是一个字典

PyObject* PyDict_New() 创建一个Python对象

void PyDict_Clear(PyObject *p) 清空Python对象的数据

 

// 生成Python可调用的动态链接库 BOOST_PYTHON_MODULE(gpassword){ class_ ("gpassword", init()) .def("getPassword", &GeneratePassword::getPassword);

 

矩阵

2.3.2 numpy基本数据类型

numpy中的数据类型被称为ndarray(即 N-dimensional array,多维数组),创建一个ndarray很简单:

  1.  import numpy as np
  1. array=np.array([1,2,3],dtype=np.uint8)
  1.  print array

即向np.array()函数传入一个python列表即可。注意dtype参数是可选的,它指定了生成的数组的数据长度和类型,这里是长度为8bit的无符号整数。

2.3.3 快速创建矩阵

mat1=np.zeros((2,3))

np.zeros()快速创建一个指定维度的全0矩阵,注意传进去的参数是一个tuple。

2.3.4 numpy中的高维矩阵

"矩阵"一般指有行和列的“二维”矩阵,但numpy还支持高维矩阵,比如下面:

  1.  nd=np.zeros((1,2,3,4))
  2.  print nd.shape
  3.  print nd.size

nd就可以看作是一个1x2x3x4尺寸的高维矩阵。ndarray.shape保存的是数组的“形状”,也就是高维矩阵每一维的长度。ndarray.size保存的是数组每一维长度相乘的结果,即数组元素的个数。

 

 

初始化解释器之后,使用PyImport_Import()加载脚本。这个例程需要一个Python字符串作为参数,它是使用PyUnicode_FromString()数据转换例程构造的。

 

加载脚本之后,使用PyObject_GetAttrString()检索我们要查找的名称。如果名称存在,并且返回的对象是可调用的,则可以安全地假设它是一个函数。然后程序按照正常方式构造一个参数元组。然后用以下方法调用Python函数。

 

在函数返回时,pValue要么为NULL,要么包含对函数返回值的引用。请确保在检查值之后释放引用。

————————————————

版权声明:本文为CSDN博主「caridle」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/caridle/article/details/97366903

 

2.3 使用PythonQt库

https://www.cnblogs.com/xia-weiwen/p/7932379.html

 

2.4 boost::python

boost::python库是pyhon和c++相互交互的框架,可以再python中调用c++的类和方法,也可以让c++调用python的类和方法

 

python自身提供了一个Python/C API用来实现python和c++的交互,boost::python是Python/C API的包装,所以用起来更简单一些。

 关于python与C++混合编程,事实上有两个部分 

  1. extending   所谓python 程序中调用c/c++代码, 其实是先处理c++代码, 预先生成的动态链接库, 如example.so,  而在python代码中import example;即可使用c/c++的函数 .
  2. embedding  c++代码中调用 python 代码.

 

Python对一个动态类型的语言,C++是一个静态类型的语言,对于Python中的变量类型,Boost.Python都有相应的类对应,他们都是boost::python::object的子类。boost::python::object 包装了PyObject *, 通过这种方式c++可以平滑的操作python对象。Boost.Python的主要目标既保持Python的编程风格同时又提供C++和Python的双向映射。

 

Python::Object对应一个Python对象,那么c++怎么获取Python对象的值呢,这个需要使用Python::extract方法

  1. double d=python::extract(obj)

通过PyObject*构造一个boost::python::object对象。

boost::python::object o(boost::python::handle<>(pyobj));

这样情况下. o管理pyobj, 不会增加pyobj的引用计数。

  1. boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj)));

这中情况下,会调用Py_INCREF ,当O对象生命周期结束 ,pyobj不会析析构掉

 

怎么从python::object对象中获取PyObject* :

  1. obj.ptr()

 

 

#include

using namespace std;

#include

using namespace boost::python;

 

int main(int argc, char *argv[])

{

Py_Initialize();

 

object main_module = import("__main__");

object main_namespace = main_module.attr("__dict__");

exec("hello = file('hello.txt', 'w')\n"

"hello.write('Hello world!')\n"

"hello.close()",

main_namespace);

exec("result = 5 ** 2", main_namespace);

int five_squared = extract(main_namespace["result"]);

cout << "The five_squeared caculated by python is " << five_squared << endl;

 

// Load the sys module.

object sys = import("sys");

 

// Extract the python version.

std::string version = extract(sys.attr("version"));

std::cout << version << std::endl;

 

//要求simple.py与可执行文件在相同路径下! 运行ok

object simple = exec_file("simple.py",main_namespace, main_namespace);

//dict global;

//object result = exec_file("simple.py", global, global);

object foo = main_namespace["foo"];

int val = extract(foo(5));

cout << "Python has caculated foo as " << val << endl;

 

 

return 0;

}

 

 如何编译这个程序呢,其实就是能找的python, 以及boost.python的头文件和库文件.我采用了cmake,管理.

 最简单的在相同代码路径下,建立一个文件CMakeLists.txt,写入以下内容,注意你可能需要根据自己的安装路径进行

 更改.

 

project(Embedding) #随便起一个工程名称

 

#boost.python,python头文件路径

include_directories(/usr/local/boost1.4/include /usr/local/include/python2.6)

 

link_directories(/usr/local/boost1.4/lib /usr/local/lib)  #boost.python,python动态链接库路径

 

add_executable (embedding embedding.cc)  #源文件embedding.cc 生成可执行文件embedding

target_link_libraries(embedding libboost_python.so libpython2.6.so) #可执行文件依赖与这两个库

你可能感兴趣的:(C++调用python)