首页 > 编程语言 >将Python文件发布成DLL并调用

将Python文件发布成DLL并调用

时间:2023-01-11 10:56:48浏览次数:60  
标签:文件 调用 Python DLL int pch

如何将Python文件发布成DLL供C/C++调用,试过两种思路:

一种是用Cython将Python文件转为.c文件,但是简简单单4行代码,由于调用了NumPy,生成.c文件有5000+行,而且完全找不到原python函数的入口,无奈放弃;

另一种思路是用CPython API给原Python函数写一个C/C++接口调用原函数,再打包成DLL,也是这篇文章的主要内容。

先讲一下我使用的环境:

Python Interpreter: Anaconda3 Python 3.8.5

Python Library: Numpy,目前只试了这一个库,其他应该差不多

IDE: 宇宙最强VS2019 on Windows10

1. 如何生成调用Python函数的DLL

用一个简单的Python函数作为例子,放在test_numpy.py中

 
  import numpy as np       def func(my_list1, my_list2):   list_np1 = np.array(my_list1)   list_np2 = np.array(my_list2)   return list(list_np1 + list_np2)       # if __name__ == "__main__":   # print(func([1, 2, 3], [4, 5, 6]))   # 输出:>> 5 7 9
 
 

打开VS2019,新建DLL项目,VS会自己生成几个.h和.cpp文件,只需要用到pch.h和pch.cpp两个文件,其他的不用管

首先将本地调试器换成Release x64模式,使用Debug模式需要python38_d.lib文件,有需要可以自行搜索

配置项目属性:给项目添加Python.h的包含目录和库目录,需要将路径换成自己的Python安装路径,在链接器中添加python38.lib,这个取决于你的Python解释的版本,可以在PythonPath\libs里面找到这个文件

配置好环境以后编写函数,主要是用CPython API将C的数组转换成Python的list对象,然后调用原Python函数,得到结果后转换成C的数组,CPython API里面函数很多

附个参考手册Python/C API 参考手册 — Python 3.8.12 文档

pch.h

 
  // pch.h: 这是预编译标头文件。   // 下方列出的文件仅编译一次,提高了将来生成的生成性能。   // 这还将影响 IntelliSense 性能,包括代码完成和许多代码浏览功能。   // 但是,如果此处列出的文件中的任何一个在生成之间有更新,它们全部都将被重新编译。   // 请勿在此处添加要频繁更新的文件,这将使得性能优势无效。       #ifndef PCH_H   #define PCH_H       // 添加要在此处预编译的标头   #include "framework.h"       extern "C" _declspec(dllexport) long* listAdd(int a[], int b[], int n); // 将两个数组相加,并返回新数组       #endif //PCH_H
 
 

pch.cpp

 
  // pch.cpp: 与预编译标头对应的源文件       #include "pch.h"   #include <Python.h>   #include <iostream>       using namespace std;       // 当使用预编译的头时,需要使用此源文件,编译才能成功。       long* listAdd(int a[], int b[], int n)   {   Py_SetPythonHome(L"C:\\Users\\10262\\miniconda3\\"); //这里地址一定要写对啊!   // 这句语句是在添加python.exe所在路径,不添加虽然编译没有问题,但是会在运行时出现   // Fatal Python error: initfsencoding: unable to load the file system codec   // ModuleNotFoundError: No module named 'encodings'   // 这种很无厘头的错误       //***python调用***//   //初始化python模块   Py_Initialize();   // 检查初始化是否成功   if (!Py_IsInitialized())   {   cout << "初始化失败" << endl;   Py_Finalize();   }   PyObject* pModule;   PyObject* pFunc = NULL;   PyObject* pArg = NULL;   PyRun_SimpleString("import sys");   PyRun_SimpleString("sys.path.append('./')");//设置python模块,搜寻位置,文件放在.cpp文件一起           pModule = PyImport_ImportModule("test_dll");//Python文件名   if (!pModule) {   cout << "py文件导入失败" << endl;   Py_Finalize();   return NULL;   }   else {   pFunc = PyObject_GetAttrString(pModule, "func");//Python文件中的函数名   if (!pFunc) {   cout << "函数导入失败" << endl;   Py_Finalize();   return NULL;   }       PyObject *pyParamsA = PyList_New(n), *pyParamsB = PyList_New(n); //c++类型转python类型       for (int i = 0; i < n; i++) {   PyList_SetItem(pyParamsA, i, PyLong_FromLong(a[i]));   PyList_SetItem(pyParamsB, i, PyLong_FromLong(b[i]));   }       long *result = new long(n);   pArg = PyObject_CallFunction(pFunc, "OO", pyParamsA, pyParamsB); //调用函数   for (int i = 0; i < n; i++) { // python类型转C++数组   result[i] = PyLong_AsLong(PyList_GetItem(pArg, i));   cout << result[i] << " ";   }   cout << endl;       return result;   }   }
 
 

这里需要注意一下一定要记得Py_SetPythonHome设为Python的安装路径,否则会报错。

OK,以上都搞定了只需要生成DLL即可,生成的dll和lib在SolutionPath\x64\Release里面

2. 调用DLL

在调用DLL之前,最好先建立另一个空项目将pch.cpp里面的代码复制过去测试一下直接调用listAdd函数能不能成功,在这里我省略了这一步

新建空项目,将生成dll和lib文件以及原Python文件test_numpy.py复制到新项目的路径下,新建main.cpp,用于调用dll

main.cpp

 
  #include<iostream>   #include <Windows.h>   using namespace std;       int main()   {   // 加载DLL文件   HINSTANCE hDllInst;   hDllInst = LoadLibrary(L"test_numpy.dll"); //调用DLL   if(hDllInst) {   typedef long* (*PLUSFUNC)(int* a, int* b, int n); //后边为参数,前面为返回值   PLUSFUNC plus_str = (PLUSFUNC)GetProcAddress(hDllInst, "listAdd"); //GetProcAddress为获取该函数的地址   int a[3] = { 1, 2, 3 }, b[3] = { 4, 5, 6 };   long* result = plus_str(a, b, 3);   cout << "调用完成" << endl;   }   else {   cout << "DLL加载失败" << endl;   }       return 0;   }
 
 

运行之前,需要配置一下项目属性,将之前生成的lib文件加入到链接器里面

再运行程序,输出5 7 9,完结撒花!

 

标签:文件,调用,Python,DLL,int,pch
From: https://www.cnblogs.com/lidabo/p/17043115.html

相关文章

  • python BeautifulReport库 案例失败时报告无法正常换行解决
    python使用BeautifulReport出的测试报告对比其他的一些出报告的工具来说还是挺好看的;BeautifulReport用起来也很方便;但是git上下载的BeautifulReport,当测试案例失败时,案例......
  • Python变量
    1.变量介绍变量分为变量名、变量值、内存地址id()获取变量的内存地址作用:判断两个数据是否是同一个数据变量的作用:存储数据更方便的管理和使用例:print(id(name))#......
  • Python解释器
    Python解释器目录Python解释器Python程序的运行字节码_codeobject_基本控制语句顺序语句条件语句循环语句栈参考资料Python程序的运行首先执行词法分析、语法解析和编......
  • python文件头部#/usr/bin/env python和#coding:utf-8的作用
    一、声明作用#!/usr/bin/python#!/usr/bin/envpython#coding:utf-8以上代码,放在python文件的头部,仅作为声明作用如果是python3,则改为python3#!/usr/bin/envpython......
  • Python将str转为int型或float型
    string转化为int型int转化为string型string转化为float型float转化为string型含小数点的string分割为整数部分和小数部分string转化为int型string转化为int型——10进制:in......
  • Python+ Flask轻松实现Mock Server
    每天进步一点点,关注我们哦,每天分享测试技术文章本文章出自【码同学软件测试】码同学公众号:自动化软件测试,领取资料可加:magetest码同学抖音号:小码哥聊软件测试1、什么是......
  • python利用matplotlib生成迷宫
    起因我想要写一个项目叫python迷宫游戏,需求是玩家能和机器对抗率先走出迷宫,至少要有两个等级的电脑。慢慢来,首先迷宫游戏需要有一个迷宫并展示出来,这便是这篇博客的目的......
  • python操作mysql数据库,增删查改等需要执行后加commit()
    p1:关于commit方法第一感觉是这个方法只用来提交“数据”,比如插入数据、更新数据需要在execute()后面跟上一个commit();现在看来,commit()方法需要跟在增(insert)、删(delete)、......
  • MySQL UPDATE:修改数据-更新数据-在原有表基础上增加列--python
    使用UPDATE语句修改单个表,语法格式为:UPDATE<表名>SET字段1=值1[,字段2=值2…][WHERE子句][ORDERBY子句][LIMIT子句]语法说明如下:<表名>:用于指定要......
  • Python爬虫-第三章-4-利用BeautifulSoup模块爬取某网壁纸图库图片
    思路:1.提取子页面链接2.访问子链接页面,提取下载地址3.访问下载地址下载内容到本地#DemoDescribe:数据解析bs4importtimeimportrequestsimportrandomimportstringfr......