用cython将python程序打包成C++动态库(windows+Vistual Studio2017平台)
作为一名程序员我们都知道Python的库可能要比C++的丰富的多特别是在算法方面,但是有的时候我们的工程是用C++开发的,我们又像用Python的这个库那怎么办呢?如果直接调.py程序,工程中代码有.py又有.cpp显得工程很杂乱。那么我么可以借助cython来帮助我们将python程序封装成C++动态库。最近正好用到jieba分词工具,接下来让我们基于结巴一起探讨如何完成python程序封装成C++库。
1.开发环境
- 操作系统:Windows10
- 开发IDE:PyCharm、Vistual Studio 2017
- 开发工具:Python3.6.3、C++编译器MSVC14.10
前提条件已经安装了cython和jieba库如果没有安装,可以按照下面方式经行安装
pip install cython
pip install jieba
# 如果安装慢,可以用国内python镜像源
# pip install cython -i https://repo.huaweicloud.com/repository/pypi/simple/
# pip install jieba -i https://repo.huaweicloud.com/repository/pypi/simple/
2.创建安装脚本和cython代码
2.1 创建setup.py脚本呢
在网上看了很多文章,感觉都很复杂,对于我们学习来说可以先从简单开始。我们先创建一个简单的setup.py安装脚本,如下:
# setup.py
from setuptools import setup
from Cython.Build import cythonizesetup(ext_modules=cythonize("text_segment.pyx"),zip_safe=False,
)
2.2 创建Cython脚本
创建一个.pyx格式的文件text_segment.pyx,如下:
# text_segment.pyx
from datetime import datetime
import jieba
import os
import loggingcdef void init_logging(log_dir):if not os.path.exists(log_dir):os.makedirs(log_dir)log_filename = os.path.join(log_dir, datetime.now().strftime("%Y_%m_%d") + ".log")logging.basicConfig(filename=log_filename, level=logging.DEBUG,format='%(asctime)s [%(filename)s Line %(lineno)d] - %(levelname)s - %(message)s')cdef bint check_file_exists(str filename):return os.path.isfile(filename)cdef str read_last_line(str filename):if not check_file_exists(filename):return Nonewith open(filename, 'r', encoding='utf-8') as file:lines = file.readlines()if lines:return lines[-1].strip()return ""cdef void write_segmented_words(list segmented_words, str output_filename):with open(output_filename, 'w', encoding='utf-8') as file:for word in segmented_words:if word.strip() != "":file.write(word + '\n')def segment_text_full(sentence: str):logging.info(f"原始句子:{sentence} ")cdef list full_list = list(jieba.cut(sentence, cut_all=True))logging.info(f"全模式: 【{'/'.join(full_list)}】")write_segmented_words(full_list, "words_txt/cut_all_segmented_words.txt")return full_listdef segment_text_accurate(sentence: str):logging.info(f"原始句子:{sentence} ")cdef list accurate_list = list(jieba.cut(sentence, cut_all=False))logging.info(f"精确模式: 【{'/'.join(accurate_list)}】")write_segmented_words(accurate_list, "words_txt/cut_segmented_words.txt")return accurate_listdef segment_text_search(sentence: str):logging.info(f"原始句子:{sentence} ")cdef list search_list = list(jieba.cut_for_search(sentence))logging.info(f"搜索引擎模式: 【{'/'.join(search_list)}】")write_segmented_words(search_list, "words_txt/cut_search_segmented_words.txt")return search_listdef init_data():init_logging("log")jieba.load_userdict("dict/dict.txt")
3.生成C++动态库
在终端项目目录下执行下面命令:
E:\jieba_segmentation> python setup.py build
命令成功后会生成build文件夹和text_segment.cp36-win_amd64.pyd(同.dll文件结构一样)文件,build的目录结构如下:
└─build├─lib.win-amd64-3.6└─temp.win-amd64-3.6└─Release
Release目录下会生成text_segment.cp36-win_amd64.lib库文件。
4.C++程序调用
前面步骤顺利的话会生成text_segment.cp36-win_amd64.pyd和text_segment.cp36-win_amd64.lib两个库文件,接下来我们就开始通过C++程序调用Cython生成的C++动态库。
4.1 配置项目依赖
4.1.1配置Python依赖
配置Python头文件:
项目右键属性—>VC++目录—>包含目录,添加Python头文件路径(C:\Users\XXX\AppData\Local\Programs\Python\Python36\include)
配置Python依赖库(.lib静态库):
(1)项目右键属性—>VC++目录—>引用目录,添加Python静态库路径(C:\Users\XXX\AppData\Local\Programs\Python\Python36\libs)
(2)项目右键属性—>链接器—>输入—>附加依赖项,添加python36.lib
4.1.1配置Cython生成的动态库依赖
4.1.1配置Python依赖
因为Cython生成的库我们没有选择生成.h和.cpp文件,所以不用配置包含目录,之后我们在C++程序中直接调用就可以。
配置依赖库(.lib静态库):
(1)项目右键属性—>VC++目录—>引用目录,添加Cython生成的text_segment.cp36-win_amd64.lib静态库路径(我的放在这个下面$(ProjectDir)\jieba_cpython\lib)
(2)项目右键属性—>链接器—>输入—>附加依赖项,添加Cython生成的text_segment.cp36-win_amd64.lib名称
4.2 C++测试函数
我们在上边配好的VS2017工程里添加源码文件main.cpp,内容如下:
#include <iostream>
#include <string>
#include <vector>
#include <Windows.h>
#include <Python.h>bool cutPy(const std::string& sentence, std::vector<std::string>& result, int cutType);
int main()
{// 调用python接口std::vector<std::string> pythonFullCutResultVector;bool ok = segmenter.cutPy("我爱自然语言处理", pythonFullCutResultVector, 0);if (!ok){std::cout << "Python 分词失败" << std::endl;}std::cout << "Python 分词: ";result << pythonFullCutResultVector;std::cout << result << std::endl;
}bool cutPy(const std::string& sentence, std::vector<std::string>& result, int cutType)
{// 初始化Python解释器Py_Initialize();// 导入Python模块PyObject *pModule = PyImport_ImportModule("text_segment");if (pModule == NULL){PyErr_Print();std::cerr << "加载python分词模块失败!" << std::endl;Py_Finalize();return false;}PyObject *pInit = PyObject_GetAttrString(pModule, "init_data");if (pInit && PyCallable_Check(pInit)) {PyObject_CallObject(pInit, NULL);}else {if (PyErr_Occurred())PyErr_Print();std::cerr << "不能找到init_data方法" << std::endl;Py_XDECREF(pInit);Py_DECREF(pModule);Py_Finalize();return false;}// 获取python模块中的方法PyObject *pFunc;switch (cutType){case 0:pFunc = PyObject_GetAttrString(pModule, "segment_text_full");break;case 1:pFunc = PyObject_GetAttrString(pModule, "segment_text_accurate");break;case 2:pFunc = PyObject_GetAttrString(pModule, "segment_text_search");break;default:pFunc = PyObject_GetAttrString(pModule, "segment_text_full");break;}if (pFunc == NULL || !PyCallable_Check(pFunc)){if (PyErr_Occurred())PyErr_Print();std::cerr << "不能找到segment_text_full方法" << std::endl;Py_XDECREF(pFunc);Py_DECREF(pModule);Py_Finalize();return false;}// 准备调用函数的输入参数const char* input_sentence = u8"我爱自然语言处理"; // 输入的句子if (input_sentence == NULL){std::cerr << "输入句子为空!" << std::endl;Py_DECREF(pFunc);Py_DECREF(pModule);Py_Finalize();return false;}// 创建Python字符串PyObject *pInput = PyUnicode_FromString(input_sentence);if (pInput == NULL){PyErr_Print();std::cerr << "创建Python字符串失败!" << std::endl;Py_DECREF(pFunc);Py_DECREF(pModule);Py_Finalize();return false;}// 封装参数PyObject *pArgs = PyTuple_Pack(1, pInput); // 将输入封装为元组if (pArgs == NULL){PyErr_Print();std::cerr << "参数封装失败!" << std::endl;Py_DECREF(pInput);Py_DECREF(pFunc);Py_DECREF(pModule);Py_Finalize();return false;}// 调用Python方法PyObject *pValue = PyObject_CallObject(pFunc, pArgs);Py_DECREF(pArgs); // 释放参数引用计数Py_DECREF(pInput); // 释放输入的Python对象if (pValue != NULL){// 处理返回值(假设返回的是一个列表)if (PyList_Check(pValue)){Py_ssize_t size = PyList_Size(pValue);std::cout << "分词结果:";for (Py_ssize_t i = 0; i < size; ++i){PyObject *pItem = PyList_GetItem(pValue, i);const char* c_str = PyUnicode_AsUTF8(pItem);if (!c_str) {PyErr_Print();std::cerr << "转换Unicode到UTF-8失败" << std::endl;continue; // 或其他处理}std::string str(c_str);std::cout << " " << i << ":" << str << " ";result.push_back(str);}std::cout << std::endl;}else{std::cerr << "返回值不是列表类型!" << std::endl;}Py_DECREF(pValue); // 释放返回值引用计数}else{PyErr_Print();std::cerr << "调用Python方法失败!" << std::endl;}// 清理Py_XDECREF(pFunc);Py_DECREF(pModule);Py_Finalize();return true;
}
生成解决方案,运行程序,终端显示如下内容,整个动态库调用完成
Building prefix dict from the default dictionary ...
Loading model from cache C:\Users\THS\AppData\Local\Temp\jieba.cache
Loading model cost 0.506 seconds.
Prefix dict has been built successfully.
分词结果: 0:我 1:爱 2:自然 3:自然语言 4:语言 5:处理
Python 分词: ["我", "爱", "自然", "自然语言", "语言", "处理"]
相关文章:
用cython将python程序打包成C++动态库(windows+Vistual Studio2017平台)
作为一名程序员我们都知道Python的库可能要比C的丰富的多特别是在算法方面,但是有的时候我们的工程是用C开发的,我们又像用Python的这个库那怎么办呢?如果直接调.py程序,工程中代码有.py又有.cpp显得工程很杂乱。那么我么可以借助…...
三层交换机SVI功能(交换机虚拟接口)实现各个实训室电脑网络可互通,原本是独立局域网
三层交换机 SVI功能(交换机虚拟接口) 实现VLAN路由 需求 :各实训室使用独立局域网,即每个实训有自己的IP网段, 每个实训室只有内部互相访问。 需求:为了加强各实训室学生的交流,学校要求我们…...
class的访问器成员
class的访问器成员 本质是 class 的语法糖 等价于对象的defineProperty对象里面也能使用 class Product{constructor(count, price){this.count count;this.price price;}get total(){ // 相当于getterreturn this.count * this.price;}}const product new Product(10, 10…...
vue入门:路由 router
文章目录 介绍安装配置路由模式嵌套路由路由传参编程式导航路由懒加载 底层原理 介绍 vue2 vue router API vue3 vue router API Vue Router 是 Vue.js 的官方路由管理器,它允许你通过不同的 URL 显示不同的组件,从而实现单页面应用(SPA&a…...
JVM详解(曼波脑图版)
(✪ω✪)ノ 好哒!曼波会用最可爱的比喻给小白同学讲解JVM,准备好开启奇妙旅程了吗?(๑˃̵ᴗ˂̵)و 📌 思维导图 ━━━━━━━━━━━━━━━━━━━ 🍎 JVM是什么?(苹果式比…...
Prometheus thanos架构
Thanos 是一个用于扩展 Prometheus 的高可用性和长期存储的解决方案。它通过整合多个 Prometheus 实例,提供了全局查询、长期存储、以及高可用性的能力。Thanos 的架构主要由以下几个核心组件组成: 1. Sidecar 功能: Sidecar 是与每个 Prom…...
进程(Process)和进程管理
李升伟 整理 进程和进程管理是操作系统的核心概念之一,涉及计算机资源的分配、调度和执行控制。以下是详细的解释: 1. 进程的定义 进程(Process)是正在执行的程序实例,是操作系统进行资源分配和调度的基本单位。它包…...
更强的视觉 AI!更智能的多模态助手!Qwen2.5-VL-32B-Instruct-AWQ 来袭
Qwen2.5-VL-32B-Instruct 是阿里巴巴通义千问团队于 2025 年 3 月 24 日开源的多模态大模型,基于 Apache 2.0 协议发布。该模型在 Qwen2.5-VL 系列的基础上,通过强化学习技术优化,以 32B 参数规模实现了多模态能力的突破。 核心特性升级&…...
Linux系统中的Perf总结
Linux系统中的Perf总结 Perf 是一个集成在 Linux 内核中的强大性能分析工具,在 Ubuntu 系统上尤为实用。它可以帮助用户监控和分析 CPU、内存、I/O 等性能指标。本文将一步步详解 Perf 在 Ubuntu 系统中的安装、使用方法及进阶技巧,带你从入门走向精通。…...
每日算法-250417
每日算法 - 20250417 记录今天的算法学习过程,包含三道 LeetCode 题目。 1005. K 次取反后最大化的数组和 题目 思路 贪心 解题过程 想要获得最大的数组和,我们的目标是尽可能地增大数组元素的总和。一种有效的贪心策略是:每次选择数组中绝…...
16.4B参数仅激活2.8B!Kimi-VL-A3B开源:长文本、多模态、低成本的AI全能选手
近日,月之暗面(Moonshot AI)开源了Kimi-VL系列模型,包含Kimi-VL-A3B-Instruct(指令调优版)和Kimi-VL-A3B-Thinking(推理增强版)。这两款模型以总参数16.4B、激活参数仅2.8B的轻量化设…...
山东大学软件学院创新项目实训开发日志(17)之中医知识历史问答历史对话查看功能完善
本次完善了历史对话的查看功能,可以让其正常显示标题 后端:在conversationDTO功能构造方法添加title 前端:在历时会话按钮添加标题title即可 前端效果展示,成功(^-^)V:...
关于Java集合中对象字段的不同排序实现方式
📊 关于Java集合中对象字段的不同排序实现方式 #Java集合 #排序算法 #Comparator #性能优化 一、排序基础:两种核心方式对比 方式Comparable接口Comparator接口实现位置目标类内部实现独立类或匿名内部类排序逻辑自然排序(固定规则…...
ZKmall开源商城静态资源管理:Nginx 配置与优化
ZKmall开源商城作为电商平台,其商品图片、前端资源等静态内容的高效管理与分发直接影响用户体验和系统性能。基于Nginx的静态资源管理方案,结合动静分离、缓存优化、安全加固、性能调优四大核心策略,可显著提升平台响应速度与稳定性。以下是具…...
Google Gemini 系列AI模型 的详细解析,涵盖其技术特点、版本差异、应用场景及优势
以下是 Google Gemini 系列AI模型 的详细解析,涵盖其技术特点、版本差异、应用场景及优势: 1. Gemini 系列概述 发布背景: Google于2023年推出 Gemini 系列模型,作为其多模态大模型的里程碑,旨在结合文本、图像、音频…...
量子通信应用:量子安全物联网(三)协议融合
第一部分:引言与概述 1.1 量子安全物联网的背景与必要性 随着物联网(IoT)设备的爆炸式增长(预计2030年全球连接设备超750亿台),传统安全机制(如RSA、ECC加密)正面临量子计算的颠覆性威胁。量子计算机的Shor算法可在多项式时间内破解非对称加密体系,而Grover算法则对…...
鸿蒙API15 “一多开发”适配:解锁黄金三角法则,开启高效开发新旅程
一、引言 在万物互联的时代浪潮中,鸿蒙操作系统以其独特的 “一多开发” 理念,为开发者打开了一扇通往全场景应用开发的新大门。“一多开发”,即一次开发,多端部署 ,旨在让开发者通过一套代码工程,就能高效…...
量子计算:开启未来科技之门的钥匙
在当今科技飞速发展的时代,量子计算正逐渐从实验室走向实际应用,成为全球科技领域的焦点之一。它有望为众多行业带来前所未有的变革,从密码学、药物研发到金融风险评估等,量子计算的潜力不可限量。 一、量子计算的原理 量子计算基…...
k230学习笔记-疑难点(1)
1.出现boot failed with exit code 19: 需要将k230开发板的btoot0拨到ON 2.出现boot failed with exit code 13: 说明k230开发板的固件烧录已经丢失,需要重新烧录 *** 注意重新烧录时需要将btoot0重新拨到OFF,才会弹出加载固件需要的通用串行总线&…...
驱动-自旋锁
前面原子操作进行了讲解, 并使用原子整形操作对并发与竞争实验进行了改进,但是原子操作只能对整形变量或者位进行保护, 而对于结构体或者其他类型的共享资源, 原子操作就力不从心了, 这时候就轮到自旋锁的出场了。 两个…...
10.(vue3.x+vite)div实现tooltip功能(css实现)
1:效果截图 2:代码实现 <template><div><div class="tooltip" style="margin-top: 20%; margin-left: 20%; background-color: blueviolet; color: white;...
使WebSocket 稳定可靠,需要考虑的方向
文章目录 1. 连接管理2. 心跳检测3. 重连机制4. 消息队列5. 错误处理6. 资源管理7. 安全性8. 状态同步 示例代码1. 添加依赖2. WebSocket 客户端实现代码注释功能标注3. 安卓端使用MainActivity.java布局文件(activity_main.xml) 4. 后端(Fla…...
Linux:进程:进程调度
进程在CPU上运行具有以下特性: 竞争、独⽴、并⾏、并发 竞争性:系统进程数⽬众多,⽽CPU资源很少甚至只有一个,所以进程之间是具有竞争属性的。为 了⾼效完成任务,更合理竞争相关资源,便具有了优先级 独⽴性: 为了避…...
Stable Diffusion 图像生成 GUI 应用:图像缩放等五个优化——SD界面学习记录
本篇续前面Stable DiffusionPyqt5实现图像生成和管理界面,链接如下: Stable DiffusionPyqt5: 实现图像生成与管理界面(带保存 历史记录 删除功能)——我的实验记录(结尾附系统效果图)-CSDN博客…...
职坐标解码互联网行业转型发展新动能
当前,互联网行业正以前所未有的速度重塑全球产业格局。工信部最新数据显示,我国互联网企业营收连续三年保持双位数增长,其中百强企业在人工智能、物联网等领域的投入强度同比提升40%,展现出强劲的技术引领力。与此同时,…...
【含文档+PPT+源码】基于微信小程序的非遗文化黄梅戏宣传平台的设计与实现
课程目标: 教你从零开始部署运行项目,学习环境搭建、项目导入及部署,含项目源码、文档、数据库、软件等资料 课程简介: 本课程演示的是一款基于微信小程序的非遗文化黄梅戏宣传平台的设计与实现,主要针对计算机相关…...
Causal Attention的底层原理
Causal Attention Transformer的Decoder中最显著的结构是Casual Attention。 通过本篇文章,你将学会 Casual Attention的机制原理 Casual Attention在TensorFlow中的实现原理 如何快速地保存并打印TensorFlow中模型已经训练好的参数 如何实现Transformer的Dec…...
深入理解类:ArkTS面向对象编程的核心概念
# 深入理解类:ArkTS面向对象编程的核心概念 在编程世界里,面向对象编程(OOP)是一种强大的编程范式,而类则是OOP的核心构建块。在ArkTS语言中,类的设计和使用对于构建复杂、可维护的应用程序至关重要。今天…...
AI 驱动下的后端开发架构革命:从智能协同体系
AI 驱动下的后端开发架构革命:从智能协同体系 一、引言:AI 重构后端开发范式 在 2025 年的企业级技术演进中,人工智能正从辅助工具升级为核心架构要素。根据 Gartner《2025 智能技术栈成熟度报告》,传统 "人力编码 硬规则…...
vue3 Ts axios 封装
vue3 Ts axios 封装 axios的封装 import axios, { AxiosError, AxiosInstance, InternalAxiosRequestConfig, AxiosResponse, AxiosRequestConfig, AxiosHeaders } from axios import qs from qs import { config } from ./config import { ElMessage } from element-plus// …...
