使用C/C++写Python模块
最近看开源项目时学习了一下用C/C++写python模块,顺便把学习进行一下总结,废话少说直接开始:
环境:windows、python2.78、VS2010或MingW
1 创建VC工程
(1) 打开VC6.0或VS2008,然后File-->New-->Project-->Win32 DLL Project。建立一个Empty Project,比如testClass,一路确定。
(2) 之后向工程添加python头文件目录及库文件目录,如头文件目录:F:\python278\include,库文件目录:F:\python278\libs
(3) 添加一个C++或C源文件,如工程中有用到类,则添加的必须是C++文件,这里直接添加main.cpp
#include <Python.h>
#include <iostream>
#include <sstream>
#include <structmember.h>
#include <windows.h> using namespace std; typedef struct _CScore
{
PyObject_HEAD
char *m_szName;
float m_dMath;
float m_dEnglish;
}CScore; static PyMemberDef CScore_DataMembers[] = { //类/结构的数据成员的说明.
{"m_szName", T_STRING, offsetof(CScore, m_szName), , "The Name of instance"},
{"m_dMath", T_FLOAT, offsetof(CScore, m_dMath), , "The Math score of instance."},
{"m_dEnglish", T_FLOAT, offsetof(CScore, m_dEnglish), , "The English score of instance."},
{NULL, NULL, NULL, , NULL}
}; //////////////////////////////////////////////////////////////
// CScore类的所有内置、构造方法.
//
static void CScore_init(CScore* Self, PyObject* pArgs) //构造方法.
{
const char* Name = ;
if(!PyArg_ParseTuple(pArgs, "sff", &Name, &Self->m_dMath, &Self->m_dEnglish))
{
cout<<"Parse the argument FAILED! You should pass correct values!"<<endl;
return ;
} Self->m_szName = new char[strlen(Name) + ];
strcpy(Self->m_szName, Name);
} static void CScore_Destruct(CScore* Self) //析构方法.
{
if(Self->m_szName){
delete [] Self->m_szName; //先释放其字符指针对象.
}
OutputDebugString(TEXT("destroy!!!")); //如果还有PyObject*成员的话,要一并释放之.
//如:Py_XDECREF(Self->Member);
Py_TYPE(Self)->tp_free((PyObject*)Self); //释放对象/实例.
} static PyObject* CScore_Str(CScore* Self) //调用str/print时自动调用此函数.
{
ostringstream OStr;
OStr<<"Name : "<<Self->m_szName<<endl
<<"Math : "<<Self->m_dMath<<endl
<<"English : "<<Self->m_dEnglish<<endl;
string Str = OStr.str();
return Py_BuildValue("s", Str.c_str());
} static PyObject* CScore_Repr(CScore* Self) //调用repr内置函数时自动调用.
{
return CScore_Str(Self);
} ////////////////////////////////////////////////////////////
// CScore类的所有Get方法.
//
static PyObject* CScore_GetName(CScore* Self)
{
return Py_BuildValue("s", Self->m_szName);
} static PyObject* CScore_GetMath(CScore* Self)
{
return Py_BuildValue("f", Self->m_dMath);
} static PyObject* CScore_GetEnglish(CScore* Self)
{
return Py_BuildValue("f", Self->m_dEnglish);
} ////////////////////////////////////////////////////////////
// CScore类的所有Set方法.
//
static PyObject* CScore_SetMath(CScore* Self, PyObject* Argvs)
{
Py_INCREF(Py_None);
if(!PyArg_ParseTuple(Argvs, "f", &Self->m_dMath))
{
cout<<"Parse the argument FAILED! You should pass correct values!"<<endl;
return Py_None;
} return Py_None;
} static PyObject* CScore_SetEnglish(CScore* Self, PyObject* Argvs)
{
Py_INCREF(Py_None);
if(!PyArg_ParseTuple(Argvs, "f", &Self->m_dEnglish))
{
cout<<"Parse the argument FAILED! You should pass correct values!"<<endl;
return Py_None;
} return Py_None;
} static PyObject* CScore_PrintInfo(CScore* Self)
{
cout<<"The scores as follows:"<<endl
<<"=============================="<<endl
<<"Name : "<<Self->m_szName<<endl
<<"Math : "<<Self->m_dMath<<endl
<<"English : "<<Self->m_dEnglish<<endl
<<"=============================="<<endl; Py_XINCREF(Py_None);
return Py_None;
} static PyMethodDef CScore_MethodMembers[] = //类的所有成员函数结构列表.
{
{"GetName", (PyCFunction)CScore_GetName, METH_NOARGS, "Get the name of instance."},
{"GetMath", (PyCFunction)CScore_GetMath, METH_NOARGS, "Get the math score of instance."},
{"GetEnglish", (PyCFunction)CScore_GetEnglish, METH_NOARGS, "Get the english score of isntance."}, {"SetMath", (PyCFunction)CScore_SetMath, METH_VARARGS, "Set the math score of instance."},
{"SetEnglish", (PyCFunction)CScore_SetEnglish, METH_VARARGS, "Set the english of instance."}, {"PrintInfo", (PyCFunction)CScore_PrintInfo, METH_NOARGS, "Print all information of instance."}, {NULL, NULL, NULL, NULL}
}; ////////////////////////////////////////////////////////////
// 类/结构的所有成员、内置属性的说明信息.
//
static PyTypeObject CScore_ClassInfo =
{
PyVarObject_HEAD_INIT(NULL, )
"Module.MyCppClass", //可以通过__class__获得这个字符串. CPP可以用类.__name__获取.
sizeof(CScore), //类/结构的长度.调用PyObject_New时需要知道其大小.
,
(destructor)CScore_Destruct, //类的析构函数.
,
,
,
,
(reprfunc)CScore_Repr, //repr 内置函数调用。
,
,
,
,
,
(reprfunc)CScore_Str, //Str/print内置函数调用.
,
,
,
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, //如果没有提供方法的话,为Py_TPFLAGS_DEFAULE
"MyCppClass Objects---Extensioned by C++!", //__doc__,类/结构的DocString.
,
,
,
,
,
,
CScore_MethodMembers, //类的所有方法集合.
CScore_DataMembers, //类的所有数据成员集合.
,
,
,
,
,
,
(initproc)CScore_init, //类的构造函数.
,
}; ////////////////////////////////////////////////////////////
// 此模块的说明信息. 由于我用的python2所以直接把该部分进行注释
//
/*static PyModuleDef ModuleInfo =
{
PyModuleDef_HEAD_INIT,
"My C++ Class Module", //模块的内置名--__name__.
"This Module Created By C++--extension a class to Python!", //模块的DocString.__doc__
-1,
NULL, NULL, NULL, NULL, NULL
};*/ int add(int x, int y)
{
return x+y;
} static PyObject* W_add(PyObject* self, PyObject* args) {
int x;
int y;
if(!PyArg_ParseTuple(args, "i|i", &x, &y)) {
return NULL;
} else {
return Py_BuildValue("i", add(x, y));
}
} static PyMethodDef module_methods[] = {{"add", W_add, METH_VARARGS, "a function from C"},{NULL, NULL, , NULL}}; PyMODINIT_FUNC inittestClass(void) //模块外部名称为--CppClass
{
PyObject* pReturn = ;
CScore_ClassInfo.tp_new = PyType_GenericNew; //此类的new内置函数—建立对象. /////////////////////////////////////////////////////
// 完成对象类型的初始化—包括添加其继承特性等等。
// 如果成功,则返回0,否则返回-1并抛出异常.
if(PyType_Ready(&CScore_ClassInfo) < )
return; pReturn = Py_InitModule3("testClass", module_methods, "Example module that creates an extension type.");
if(pReturn == NULL)
return;
Py_INCREF(&CScore_ClassInfo);
PyModule_AddObject(pReturn, "CScore", (PyObject*)&CScore_ClassInfo); //将这个类加入到模块的Dictionary中.
return;
}
main.cpp
之后修改VC工程导出文件后缀名为pyd
2 使用testClass模块
编译工程生成testClass.pyd模块文件,进入到导出文件目录,并启动python
导入testClass模块并查看其详细信息
模块详细使用
3 其他编译方式
下面介绍另一种用Python Script来生成.pyd文件的方法,新建一个Python脚本——CreatePyd.py,其内容如下:
from distutils.core import setup, Extension
ModuleInfo = Extension("testClass", sources = [r"main.cpp"])
setup(name = "testClass",
version = "1.0",
description = "This module created by C++ weiwei.Zhao",
author = 'weiwei.zhao',
author_email = 'weiwei22844@hotmail.com',
license = "You can copy this program to anywhere.",
url = "http://zhaoweiwei.top",
long_description = '''This is really just a demo!''',
platforms = "Windows",
ext_modules = [ModuleInfo]
)
CreatePyd.py
内容解释:先导入所需的Python模块,然后用Extension函数关联一个Cpp源文件一个要生成的模块名——注意:没有.pyd后缀。然后调用setup函数生成一个名字name为testClass的模块,版本version为1.0,描述description,作者信息author,作者邮箱author_email,还其平台platforms等等有用的信息!
最后调用:python CreateDLL.py build
经过编译后,就会新生成一个build目录,在build/lib.win32-2.7下你可以找到testClass.pyd文件。
需要注意的是编译脚本默认使用VS编译器,所以电脑上要安装VS,如果电脑上没有安装VS而是有MingW环境,则类似的可以使用MingW环境中gcc进行编译:
注意:为了使相关程序都能顺利找见,上图是在MingW的Shell命令行,而不是普通的windows Command命令行。
4 模块部署安装
一般来说,setup.py参数说明
#python setup.py build # 编译
#python setup.py install # 安装
#python setup.py sdist # 生成压缩包(zip/tar.gz)
#python setup.py bdist_wininst #生成NT平台安装包(.exe)
#python setup.py bdist_rpm #生成rpm包
或者直接"bdist 包格式",格式如下:
#python setup.py bdist --help-formats
--formats=rpm RPM distribution
--formats=gztar gzip'ed tar file
--formats=bztar bzip2'ed tar file
--formats=ztar compressed tar file
--formats=tar tar file
--formats=wininst Windows executable installer
--formats=zip ZIP file
下图说明了windows安装程序生成过程,在dist目录下有windows的安装程序testClass-1.0.win32-py2.7.exe
需要说明的是如果生成的testClass.pyd依赖于其他库文件,如在我的环境下用MingW生成的testClass.pyd要依赖libgcc_s_dw2-1.dll和libstdc++-6.dll两个文件,生成安装包时需把这两个文件和testClass.pyd放到一起,如放到build/lib.win32-2.7目录下,之后生成的安装文件testClass-1.0.win32-py2.7.exe会包含着两个文件,如果不这样做在导入testClass时会导致导入失败,提示类似:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: DLL load failed: 找不到指定的程序。
结束语
以上的总结参考了部分网友的博文,主要如下,一并感谢:
http://blog.csdn.net/arnozhang12/article/details/5409155
http://blog.csdn.net/carolzhang8406/article/details/6925745
使用C/C++写Python模块的更多相关文章
- 孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9并使用pydocx模块将结果写入word文档
孤荷凌寒自学python第七十九天开始写Python的第一个爬虫9 (完整学习过程屏幕记录视频地址在文末) 今天在上一天的基础上继续完成对我的第一个代码程序的书写. 到今天终于完成了对docx模块针对 ...
- python 写 excel 模块 : xlwt
主要来自:[ python中使用xlrd.xlwt操作excel表格详解 ] 为了方便阅读, 我将原文两个模块拆分为两篇博文: [ python 读 excel 模块: xlrd ] [ python ...
- python 学习第五天,python模块
一,Python的模块导入 1,在写python的模块导入之前,先来讲一些Python中的概念性的问题 (1)模块:用来从逻辑上组织Python代码(变量,函数,类,逻辑:实现一个功能),本质是.py ...
- 安装第三方Python模块,增加InfoPi的健壮性
这3个第三方Python模块是可选的,不安装的话InfoPi也可以运行. 但是如果安装了,会增加InfoPi的健壮性. 目录 1.cchardet 自动检测文本编码 2.lxml 用于解析 ...
- Python基础篇【第5篇】: Python模块基础(一)
模块 简介 在计算机程序的开发过程中,随着程序代码越写越多,在一个文件里代码就会越来越长,越来越不容易维护. 为了编写可维护的代码,我们把很多函数分组,分别放到不同的文件里,这样,每个文件包含的代码就 ...
- python模块学习心得
初始模块 1.什么是模块 模块是用来实现某项功能的一大堆代码,为什么会有模块呢?过程式编程的时候为了减少程序员编程代码的重复性,就利用函数的调用减少了代码的重复性,但是某些时候程序会过于的庞大,我们会 ...
- Python模块常用的几种安装方式
Python模块安装方法 一.方法1: 单文件模块直接把文件拷贝到 $python_dir/Lib 二.方法2: 多文件模块,带setup.py 下载模块包,进行解压,进入模块文件夹,执行:pytho ...
- 6.python模块(导入,内置,自定义,开源)
一.模块 1.模块简介 模块是一个包含所有你定义的函数和变量的文件,其后缀名是.py.模块可以被别的程序引入,以使用该模块中的函数等功能.这也是使用python标准库的方法. 类似于函数式编程和面向过 ...
- Python模块学习
6. Modules If you quit from the Python interpreter and enter it again, the definitions you have made ...
随机推荐
- Ubuntu 16.10 开启PHP错误提示
两个步骤: 修改php.ini配置文件中的error_reporting 和 display_errors两地方内容: sudo vim /etc/php/7.0/apache2/php.ini er ...
- Android调用微信登陆、分享、支付
前言:用了微信sdk各种痛苦,感觉比qq sdk调用麻烦多了,回调过于麻烦,还必须要在指定包名下的actvity进行回调,所以我在这里写一篇博客,有这个需求的朋友可以借鉴一下,以后自己别的项目有用到也 ...
- 如何在网页中提取Email地址
开博好久了,今天第一次发表技术文档,之前总是将一些好的事例保存在电脑,时间久了找起来也很麻烦,所以还是放在博客里进行归类比较方便,这样也能将自己在学习过程中的一些心得体会分享给大家,也能给需要的人一点 ...
- Android—万能ListView适配器
ListView是开发中最常用的控件了,但是总是会写重复的代码,浪费时间又没有意义. 最近参考一些资料,发现一个万能ListView适配器,代码量少,节省时间,总结一下分享给大家. 首先有一个自定义的 ...
- VMware下对虚拟机Ubuntu14系统所在分区sda1进行磁盘扩容
VMware下对虚拟机Ubuntu14系统所在分区sda1进行磁盘扩容 一般来说,在对虚拟机里的Ubuntu下的磁盘进行扩容时,都是添加新的分区,而并不是对其系统所在分区进行扩容,如在此链接中http ...
- Mono 3.8发布:性能进一步改进,可伸缩性提升
9月4日,Mono 3.8.0发布了.该版本的运行时带来了一些性能和可伸缩性方面的改进,同时完成了向Windows平台的移植. Mono遵循Gnome和Linux内核的版本编号策略,这意味着3.8是3 ...
- 【腾讯Bugly干货分享】基于RxJava的一种MVP实现
本文来自于腾讯bugly开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57bfef673c1174283d60bac0 Dev Club 是一个交流移动 ...
- WPF自定义控件第一 - 进度条控件
本文主要针对WPF新手,高手可以直接忽略,更希望高手们能给出一些更好的实现思路. 前期一个小任务需要实现一个类似含步骤进度条的控件.虽然对于XAML的了解还不是足够深入,还是摸索着做了一个.这篇文章介 ...
- [WinAPI] 获取窗口句柄的几种方法
1.使用FindWindow函数获取窗口句柄 示例:使用FindWindow函数获取窗口句柄,然后获得窗口大小,并且移动窗口到指定位置. 我们想获得酷我音乐盒的窗口句柄并移动它,该怎么办呢? 首先打开 ...
- C#委托使用详解(Delegates)
摘要 委托是C#编程一个非常重要的概念,也是一个难点.本文将系统详细讲解委托. 1. 委托是什么? 其实,我一直思考如何讲解委托,才能把委托说得更透彻.说实话,每个人都委托都有不同的见解,因为看问题的 ...