qt如何用python结合_Qt总结(九)-- c++&&python混合编程

工欲善其事,必先利其器

文章目录

python 2.7

升级python 2.7到3.6

准备

编译&&安装

软连接

.pro添加

静态库

gcc -ldl 选项作用

动态链接库

准备

工程中配置

demo && 解析

C++调用py脚本

C++向python传递参数

创建元组

示例

格式化字符

转换Python的返回值

python调用C/C++

python2的方法

python3的方法

reference

python 2.7

.pro文件添加

INCLUDEPATH += -I /usr/include/python2.7

LIBS += /usr/lib/x86_64-linux-gnu/libpython2.7.so

升级python 2.7到3.6

python -V 查看版本

准备

(1)首次安装需要先安装zlib*

sudo apt-get install zlib*

(2)下载并解压

官网下载

wget http://www.python.org/ftp/python/3.6.6/Python-3.6.6.tgz

我把下载的.tgz移到software,再打开终端输入命令解压

tar -xzvf Python-3.6.6.tgz

wget是一个下载文件的工具,用在命令行下。未指定目录情况下所下载的文件在home目录下

编译&&安装

在/usr/local目录新建一个文件夹python3

sudo -s

mkdir /usr/local/python3

到解压后的目录

./configure -prefix=/usr/local/python3

make

make install

加上–enable-shared和-fPIC之后可以将python3的动态链接库编译出来

./configure --prefix=/usr/local/python3 --enable-shared CFLAGS=-fPIC

软连接

先修改一下老版本的连接,修改后命令行输入python_old2 -V,会看到旧版本的版本号

mv /usr/bin/python /usr/bin/python_old2

为python3创建新的软连接

ln -s /usr/local/python3/bin/python3 /usr/bin/python

python -V,可以看到升级成功了

[python3采用编译动态链接库后]

python -V报错

python: error while loading shared libraries: libpython3.6m.so.1.0: cannot open shared object file: No such file or directory

复制该.so到/usr/lib

cp /usr/local/python3/lib/libpython3.6m.so.1.0 /usr/lib

后面才发现已经有python 3.5了

.pro添加

静态库

libpython3.6m.a,本方法有个报错没解决,故最终选用动态链接库

Qt Creator右键工程目录,Add library

DISTFILES += \

build-eye_tracking/testPython.py

unix:!macx: LIBS += -L$$PWD/../../../../usr/local/python3/lib/ -lpython3.6m

INCLUDEPATH += $$PWD/../../../../usr/local/python3/include/python3.6m

DEPENDPATH += $$PWD/../../../../usr/local/python3/include/python3.6m

unix:!macx: PRE_TARGETDEPS += $$PWD/../../../../usr/local/python3/lib/libpython3.6m.a

/usr/bin/ld: /home/ccl/Projects/eye_tracking/…/…/…/…/usr/local/python3/lib//libpython3.6m.a(dynload_shlib.o): undefined reference to symbol 'dlsym@@GLIBC_2.2.5’

加-ldl,没解决

gcc -ldl 选项作用

如果你的程序中使用dlopen、dlsym、dlclose、dlerror 显示加载动态库,需要设置链接选项 -ldl

//如果动态库使用g++编译,那么动态库定义函数的时候加上extern “C”,否则会提示undefined symbol错误。

加载动态链接库,首先为共享库分配物理内存,然后在进程对应的页表项中建立虚拟页和物理页面之间的映射。

你可以认为系统中存在一种引用计数机制, 每当一个进程加载了共享库(在该进程的页表中进行一次映射),引用计数加一;

一个进程显式卸载(通过dlclose等)共享库或进程退出时,引用计数减 一,

当减少到0时,系统卸载共享库。

(1)打开动态链接库:dlopen,函数原型void *dlopen (const char *filename, int flag);

dlopen用于打开指定名字(filename)的动态链接库,并返回操作句柄。

(2)取函数执行地址:dlsym,函数原型为: void *dlsym(void *handle, char *symbol);

dlsym根据动态链接库操作句柄(handle)与符号(symbol),返回符号对应的函数的执行代码地址。

(3)关闭动态链接库:dlclose,函数原型为: int dlclose (void *handle);

dlclose用于关闭指定句柄的动态链接库,只有当此动态链接库的使用计数为0时,才会真正被系统卸载。

(4)动态库错误函数:dlerror,函数原型为: const char *dlerror(void);

当动态链接库操作函数执行失败时,dlerror可以返回出错信息,返回值为NULL时表示操作函数执行成功。

//lib/x86_64-linux-gnu/libdl.so: error adding symbols: DSO missing from command line

追加 -lavutil 库便解决

动态链接库

准备

由于Qt中的slots关键字与python重复,这里我们需要修改一下文件

/usr/local/python3/include/python3.6m/object.h,从

typedef struct{

const char* name;

int basicsize;

int itemsize;

unsigned int flags;

PyType_Slot *slots; /* terminated by slot==0. */

} PyType_Spec;

(用gedit查找PyType_Spec)改为

typedef struct{

const char* name;

int basicsize;

int itemsize;

unsigned int flags;

#undef slots// 这里取消slots宏定义

PyType_Slot *slots;/* terminated by slot==0. */

#define slots Q_SLOTS// 这里恢复slots宏定义与QT中QObjectDefs.h中一致

} PyType_Spec;

工程中配置

(1).pro添加

INCLUDEPATH += -I /usr/local/python3/include/python3.6m

LIBS += /usr/local/python3/lib/libpython3.6m.so

(2)头文件

#include

demo && 解析

C++调用py脚本

Add New…新建一个python文件,移到工程的构建目录下,/home/ccl/Projects/eye_tracking/build-eye_tracking

#!/usr/bin/env python

# -*- coding: utf-8 -*-

def usePython():

print("2020/2/7")

print("Welcome to use Python in Qt")

def add(a,b):

print(a+b)

return a+b

//初始化Python解释器

Py_Initialize();

if (!Py_IsInitialized()) {

return;

}

/*************************************

* PyRun_SimpleString

把输入的字符串作为Python代码直接运行,返回0表示成功,-1表示有错。

大多时候错误都是因为字符串中有语法错误。

**************************************/

PyRun_SimpleString("import sys");

PyRun_SimpleString("sys.path.append('./')");//把当前路径加入python的默认搜索路路径

//导入一个Python模块,参数name可以是*.py文件的文件名,相当于import

PyObject* pModule = PyImport_ImportModule("testPython");//导入要调用的testPython.py

if (!pModule) {

qDebug()<

return;

}

/*************************************

* PyObject* PyObject_GetAttrString(PyObject *o, char*attr_name)

返回模块对象o中的attr_name 属性或函数,相当于Python中表达式语句,o.attr_name

**************************************/

PyObject* pFunHello = PyObject_GetAttrString(pModule,"usePython");

if (!pFunHello) {

qDebug("get function hello failed");

return;

}

//调用Python函数

PyObject_CallFunction(pFunHello,NULL);

PyObject* pFunAdd = PyObject_GetAttrString(pModule,"add");

if (!pFunAdd) {

qDebug("get function add failed");

return;

}

//两种调用方式

PyObject_CallFunction(pFunAdd,"(i,i)",5,7);

PyObject* pRet = PyEval_CallObject(pFunAdd,Py_BuildValue("(ii)",5, 7));

int result=0;

//解析python返回值

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

qDebug()<

//释放Python解释器所占用的资源

Py_Finalize();

C++向python传递参数

C++向Python传参数是以元组(tuple)的方式

(1)PyEval_CallObject,参数为PyObject*

PyObject* PyEval_CallObject(PyObject* pfunc, PyObject* pargs)

(2)PyObject_CallFunction,直接设置格式和参数

PyObject * PyObject_CallFunction(PyObject *callable_object,const char *format, …);

PyObject_CallFunction(pFunAdd,"(i,i)",5,7);

PyEval_CallObject(pFunAdd,Py_BuildValue("(ii)",5, 7));

创建元组

(1)PyTuple_New

//用PyTuple_New()创建一个元组

PyObject* pyParams = PyTuple_New(2);

//设置参数

PyTuple_SetItem(pyParams,0, Py_BuildValue("i",5));

PyTuple_SetItem(pyParams,1, Py_BuildValue("i",7));

PyEval_CallObject(pFunc, pyParams);

(2)PyObject* Py_BuildValue(char *format, …)

直接使用Py_BuildValue构建

PyObject* pyParams = Py_BuildValue("(ii)",5, 7);

示例

Py_BuildValue("")   //None

Py_BuildValue("i",123) //123

Py_BuildValue("iii",123, 456, 789) //(123, 456, 789)

Py_BuildValue("s","hello") //'hello'

Py_BuildValue("ss","hello", "world") //('hello', 'world')

Py_BuildValue("s#","hello", 4) //'hell'

Py_BuildValue("()") //()

Py_BuildValue("(i)",123) //(123,)

Py_BuildValue("(ii)",123, 456) //(123, 456)

Py_BuildValue("(i,i)",123, 456) //(123, 456)

Py_BuildValue("((ii)(ii))(ii)",1, 2, 3, 4, 5, 6) //(((1, 2), (3, 4)), (5, 6))

Py_BuildValue("[i,i]",123, 456) //[123, 456]

Py_BuildValue("{s:i,s:i}", "abc", 123, "def", 456) //{'abc': 123, 'def': 456}

格式化字符

转换Python的返回值

python返回的都是PyObject对象,常用PyArg_Parse解析,指定格式。如果返回为元组,则使用PyArg_ParseTuple

int result=0;

//解析python返回值

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

python调用C/C++

python2的方法

官网Extending Python with C or C++

//C部分

#define min(a,b) (((a) < (b)) ? (a) : (b))

char data[1024];

void SetData(const char *str)

{

//把str的内容复制到data中

strncpy(data, str, min(strlen(str) + 1, 1024));

}

const char *GetData()

{

return data;

}

封装成Python调用的函数,就是增加调用时解析 python传进来的参数的功能,再调用C的函数

static PyObject* PySetData(PyObject *self, PyObject *args)

{

const char* str = NULL;

//解析出参数到str

if ( !PyArg_ParseTuple(args, "s", &str) )

{

return 0;

}

SetData(str);

Py_RETURN_NONE;

}

static PyObject* PyGetData(PyObject *self, PyObject *args)

{

const char* str = NULL;

return PyString_FromString(GetData());

}

PyMethodDef 是一个C结构体,用来完成一个映射,也就是便于方法查找,把需要被外面调用的方法都记录在这表内。

结构体成员说明:

第一个字段:在 Python 里面使用的方法名;

第二个字段:C 模块内的函数名;

第三个字段:方法参数类型,是无参数(METH_NOARGS) , 还是有位置参数(METH_VARARGS), 还是其他等等;

第四个字段:方法描述,就是通过 help() 或者 doc 可以看到的;

需要注意的是,这个列表的最后必须以 {NULL, NULL, 0, NULL} 的形式来代表声明结束

//函数注释,使用print(pycallc.py_set_data.__doc__)可以查看

PyDoc_STRVAR(PySetData_doc__, "\

测试\n\

\n\

PySetData(str)\n\

str: 出入的字符串\n\

返回: \n\

null \n\

");

PyDoc_STRVAR(PyGetData_doc__, "\

打印数据\n\

\n\

PyGetData()\n\

返回: \n\

data \n\

");

static PyMethodDef module_methods[] = {

{"py_set_data", PySetData, METH_VARARGS, PySetData_doc__},

{"py_get_data", PyGetData, METH_VARARGS, PyGetData_doc__},

{NULL, NULL, 0, NULL}

};

生成模块,python文件中使用import pycallc可以就可以使用了。

void InitCCallPy()

{

//Py_InitModule3在python3已被弃用

PyObject *module = Py_InitModule3("pycallc", module_methods,"python call c");

}

testPython.py里有import pycallc,需在前面InitCCallPy()生成

testPython.py

#!/usr/bin/env python

# -*- coding: utf-8 -*-

import pycallc

def usePython():

print("2020/2/7")

print("Welcome to use Python in Qt")

def add(a,b):

print(a+b)

return a+b

def testC():

pycallc.py_set_data("change hello world!")

print 'in python : ',pycallc.py_get_data()

print(pycallc.py_set_data.__doc__)

python3的方法

Python 3.x中不再使用Py_InitModule

官网Extending Python with C or C++

reference

linux qt 调用python简单例子

Qt+Python混合编程 windows

Qt下调用python OSX系统

C++调用Python浅析

PS:

PyQt5

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值