如何将C++制作为python扩展文件(.pyd,动态链接库)

2024-04-30 21:18

本文主要是介绍如何将C++制作为python扩展文件(.pyd,动态链接库),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Python提供的许多标准模块支持C或者C++接口。我们自己也可以制作自己的模块来提供给python使用。

include文件和lib文件在python的安装目录下,如果只是普通安装的python程序,那么是没有调试用的lib文件的。只用release就可以了。

建立dll文件
VS2005-新建项目-win32-win32项目,选择dll。

在住文件cpp里,增加如下代码:

#include<Python.h>

std::string Recognise_Img(const std::string url)
{
//返回结果
return "从dll中返回的数据… : " +url;
}
static PyObject* Recognise(PyObject *self, PyObject *args)
{
const char *url;
std::string sts;
if (!PyArg_ParseTuple(args, “s”, &url))
{
printf(“error\n”);
return NULL;
}

sts = Recognise_Img(url);
return Py_BuildValue(“s”, sts.c_str() );
}
static PyMethodDef AllMyMethods[] = {
{“Recognise”, Recognise, METH_VARARGS},//暴露给Python的函数
{NULL, NULL} /* Sentinel */
};
extern “C” PYUTIL_API void initpyUtil()
{
PyObject *m, *d;
m = Py_InitModule(“pyUtil”, AllMyMethods); //初始化本模块,并暴露函数
d = PyModule_GetDict(m);
}

如果出现编译头错误(VS2005超级喜欢出这个问题,把临时文件都删除了还是解决不了)
就在cpp文件上右键-属性-C++ -预编译头-创建使用预编译头,选择不使用预编译头。

在工具-选项-项目和解决方案-C++目录-包含文件-增加D:\python\Python25\include(看你自己的python安装目录)
库文件增加D:\python\Python25\libs

正常安装的python是没有debug调试库的,如果要用debug方式编译,可以修改头文件pyconfig.h中的pragma comment(lib,“python25_d.lib”)为pragma comment(lib,“python25.lib”),仍然调用release的库文件。

编译成功。
把后缀名修改成pyd。放在D:\python\Python25\Dlls目录下,或者放在你的py文件的同级目录下,优先读取本目录的pyd文件。

import pyUtil
data=“123456”
result = pyUtil.Recognise(data)
print "the result is: "+ result

运行正常。

但是有个问题,如果我们使用带有\0的字符串,比如网络收报数据。
data = struct.pack(’=cI41s’,chr(60),0,‘123456’)
那么在传入的时候,就会在\0的位置被截断。
我们需要把参数改变,从s改为s#

static PyObject* Recognise(PyObject *self, PyObject *args)
{
const char *url;
char url2[100] = {0};
int len;
std::string sts;
if (!PyArg_ParseTuple(args, “s#”, &url,&len))
{
printf(“error\n”);
return NULL;
}
memcpy(url2,url,len);
url2[len] = 0;
sts = Recognise_Img(url);
return Py_BuildValue(“s#”, url2,len );
}

同时,输出也修改为s#。注意此时参数为2个,包括一个长度。

这样就OK了。

以前我一直以为python的字符串,也同样是\0结束,后来发现,是可以包括\0的,print的时候\0作为不可打印字符,\0后面的依然可以打印出来。
struct.pack的返回值为str类型。
这样什么结构都可以从python传递给c了,直接传内存里面的一段东西呗。

参考和学习了这2篇文章
http://www.vckbase.com/document/viewdoc/?id=1540
http://www.sqlite.com.cn/MySqlite/11/469.Html

C里面调用python也很简单,不过感觉意义不大,没什么必要的。

===================================

更新:

以前的机制换了个win7以后不好用了,不知道为什么,但是用这样的代码就行了。

Crypt = cdll.LoadLibrary("./xxxxCrypt.so")

data_buffer = create_string_buffer(len(d))

data_buffer.raw = d

rv = Crypt.xxxx_decrypt(data_buffer, len(d))

hexdump(data_buffer[:rv])

用c调用python可以参考下面的文章。
http://www.cnblogs.com/eric_lgf/archive/2009/09/02/1558495.html

#Python脚本,存为pytest.py
def add(a,b):
print “in python function add”
print "a = " + str(a)
print "b = " + str(b)
print "ret = " + str(a+b)
return a + b

// C代码调,用上面的add函数
#include <stdio.h>
#include <stdlib.h>
#include “C:/Python26/include/python.h”
#pragma comment(lib, “C:\Python26\libs\python26.lib”)

int main(int argc, char** argv)
{
// 初始化Python
//在使用Python系统前,必须使用Py_Initialize对其
//进行初始化。它会载入Python的内建模块并添加系统路
//径到模块搜索路径中。这个函数没有返回值,检查系统
//是否初始化成功需要使用Py_IsInitialized。

PyObject *pName, *pModule, *pDict, *pFunc, *pArgs, *pRetVal;Py_Initialize();
// 检查初始化是否成功
if ( !Py_IsInitialized() ) 
{return -1;
}// 载入名为pytest的脚本(注意:不是pytest.py)
pName = PyString_FromString("pytest");
pModule = PyImport_Import(pName);
if ( !pModule )
{printf("can't find pytest.py");getchar();return -1;
}
pDict = PyModule_GetDict(pModule);
if ( !pDict ) 
{return -1;
}// 找出函数名为add的函数
pFunc = PyDict_GetItemString(pDict, "add");
if ( !pFunc || !PyCallable_Check(pFunc) )
{printf("can't find function [add]");getchar();return -1;
}// 参数进栈
pArgs = PyTuple_New(2);// PyObject* Py_BuildValue(char *format, ...)
// 把C++的变量转换成一个Python对象。当需要从
// C++传递变量到Python时,就会使用这个函数。此函数
// 有点类似C的printf,但格式不同。常用的格式有
// s 表示字符串,
// i 表示整型变量,
// f 表示浮点数,
// O 表示一个Python对象。PyTuple_SetItem(pArgs, 0, Py_BuildValue("l",3)); 
PyTuple_SetItem(pArgs, 1, Py_BuildValue("l",4));// 调用Python函数
pRetVal = PyObject_CallObject(pFunc, pArgs);
printf("function return value : %ld\r\n", PyInt_AsLong(pRetVal));Py_DECREF(pName);
Py_DECREF(pArgs);
Py_DECREF(pModule);
Py_DECREF(pRetVal);// 关闭Python
Py_Finalize();
return 0;}

转载自 https://blog.51cto.com/xzq2000/1767400

这篇关于如何将C++制作为python扩展文件(.pyd,动态链接库)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/949941

相关文章

Python实现终端清屏的几种方式详解

《Python实现终端清屏的几种方式详解》在使用Python进行终端交互式编程时,我们经常需要清空当前终端屏幕的内容,本文为大家整理了几种常见的实现方法,有需要的小伙伴可以参考下... 目录方法一:使用 `os` 模块调用系统命令方法二:使用 `subprocess` 模块执行命令方法三:打印多个换行符模拟

Python实现MQTT通信的示例代码

《Python实现MQTT通信的示例代码》本文主要介绍了Python实现MQTT通信的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录1. 安装paho-mqtt库‌2. 搭建MQTT代理服务器(Broker)‌‌3. pytho

基于Python开发一个图像水印批量添加工具

《基于Python开发一个图像水印批量添加工具》在当今数字化内容爆炸式增长的时代,图像版权保护已成为创作者和企业的核心需求,本方案将详细介绍一个基于PythonPIL库的工业级图像水印解决方案,有需要... 目录一、系统架构设计1.1 整体处理流程1.2 类结构设计(扩展版本)二、核心算法深入解析2.1 自

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

Python 字典 (Dictionary)使用详解

《Python字典(Dictionary)使用详解》字典是python中最重要,最常用的数据结构之一,它提供了高效的键值对存储和查找能力,:本文主要介绍Python字典(Dictionary)... 目录字典1.基本特性2.创建字典3.访问元素4.修改字典5.删除元素6.字典遍历7.字典的高级特性默认字典

Python自动化批量重命名与整理文件系统

《Python自动化批量重命名与整理文件系统》这篇文章主要为大家详细介绍了如何使用Python实现一个强大的文件批量重命名与整理工具,帮助开发者自动化这一繁琐过程,有需要的小伙伴可以了解下... 目录简介环境准备项目功能概述代码详细解析1. 导入必要的库2. 配置参数设置3. 创建日志系统4. 安全文件名处

使用Python构建一个高效的日志处理系统

《使用Python构建一个高效的日志处理系统》这篇文章主要为大家详细讲解了如何使用Python开发一个专业的日志分析工具,能够自动化处理、分析和可视化各类日志文件,大幅提升运维效率,需要的可以了解下... 目录环境准备工具功能概述完整代码实现代码深度解析1. 类设计与初始化2. 日志解析核心逻辑3. 文件处

python生成随机唯一id的几种实现方法

《python生成随机唯一id的几种实现方法》在Python中生成随机唯一ID有多种方法,根据不同的需求场景可以选择最适合的方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习... 目录方法 1:使用 UUID 模块(推荐)方法 2:使用 Secrets 模块(安全敏感场景)方法

C++中全局变量和局部变量的区别

《C++中全局变量和局部变量的区别》本文主要介绍了C++中全局变量和局部变量的区别,全局变量和局部变量在作用域和生命周期上有显著的区别,下面就来介绍一下,感兴趣的可以了解一下... 目录一、全局变量定义生命周期存储位置代码示例输出二、局部变量定义生命周期存储位置代码示例输出三、全局变量和局部变量的区别作用域

C++中assign函数的使用

《C++中assign函数的使用》在C++标准模板库中,std::list等容器都提供了assign成员函数,它比操作符更灵活,支持多种初始化方式,下面就来介绍一下assign的用法,具有一定的参考价... 目录​1.assign的基本功能​​语法​2. 具体用法示例​​​(1) 填充n个相同值​​(2)