1 引言
有两种常见方式用于实现python调用C/C++,其一为开发动态链接库(DLL),这种通过动态链接库的方式在python中不能直接通过import导入模块,其二则为开发python扩展pyd,这种可以直接import。但两者都需要相同的配置环境,VS(2017或更新的版本,笔者用的是2017),当然python肯定是必不可少的,这个笔者用的是3.7版本的。
2 动态链接库(DLL)
2.1 开发DLL
在VS安装了C++开发组件后,就可以直接创建DLL项目,
在dllmain.cpp中加入下面的代码,
#include <iostream>
#include "pch.h"
#define EXPORT __declspec(dllexport)
using namespace std;
class Test {
public: int Hello();
};
int Test::Hello() {
int a = 45;
return a;
}
extern "C" {
Test t;
EXPORT float A() {
float c = t.Hello();
return c;
}
}
然后右键解决方案资源管理器中的项目名,点击生成就可以生成DLL库。在这一步之前还有重要的一点是,如果你的计算机是64位的,解决方案平台设置为x64,
否则生成的DLL库在你的计算机上是无法使用的。
2.2 测试
生成的DLL库可以在(项目目录)\Dll1\x64\Debug这个路径下找到,下面写一段python的测试代码进行验证。
import ctypes
lib = ctypes.cdll.LoadLibrary("Dll1.dll")
print("a", lib.A())
测试结果
a 45
3 python扩展
通过VS有两种途径用于开发python扩展,其一是直接新建C++空项目,通过设置项目属性的方式,最后生成pyd文件;其二是直接新建Python扩展模块项目。两者本质是一样的,但是第一种更容易让读者明白其中的过程。
3.1 通过C++空项目
首先新建一个空项目,
然后右键项目名->添加->新建项,新建一个cpp文件,命名为module1.cpp,
再次右键项目名->属性,在项目属性页面中,首先将配置设置为所有配置,64位的计算机则将平台设置为x64,然后按照下表的方式修改属性。
有几项是特别重要的,例如加入python的include和libs目录等,必须要进行设置,设置后大致如下,
保存设置,在module1.cpp中加入下面示例代码,
#include <Windows.h>
#include <cmath>
#include <Python.h>
const double e = 2.7182818284590452353602874713527;
double sinh_impl(double x) {
return (1 - pow(e, (-2 * x))) / (2 * pow(e, -x));
}
double cosh_impl(double x) {
return (1 + pow(e, (-2 * x))) / (2 * pow(e, -x));
}
double tanh_impl(double x) {
return sinh_impl(x) / cosh_impl(x);
}
PyObject* tanh_impl(PyObject *, PyObject* o) {
double x = PyFloat_AsDouble(o);
double tanh_x = sinh_impl(x) / cosh_impl(x);
return PyFloat_FromDouble(tanh_x);
}
static PyMethodDef superfastcode_methods[] = {
// The first property is the name exposed to Python, fast_tanh, the second is the C++
// function name that contains the implementation.
{ "fast_tanh", (PyCFunction)tanh_impl, METH_O, nullptr },
// Terminate the array with an object containing nulls.
{ nullptr, nullptr, 0, nullptr }
};
static PyModuleDef superfastcode_module = {
PyModuleDef_HEAD_INIT,
"module1", // Module name to use with Python import statements
"Provides some functions, but faster", // Module description
0,
superfastcode_methods // Structure that defines the methods of the module
};
PyMODINIT_FUNC PyInit_module1() {
return PyModule_Create(&superfastcode_module);
}
同样将解决方案平台设置为Release和x64,
然后右键项目名->生成,即可在(项目目录)\Project1\x64\Release路径下找到pyd文件。
在pyd文件生成过程中,可能会产生pythonXX_d.lib文件找不到的错误,是因为没有安装python的debug版本的问题,只需要运行python的安装程序,选择Modify->Next->勾选Download debug binaries,安装即可解决。
最后在产生的pyd文件目录下,新建python脚本测试,
import module1 as m
import math
print(m.fast_tanh(0.5))
print(math.tanh(0.5))
结果如下,
0.4621171572600098
0.46211715726000974
3.2 通过新建python扩展
在新建项目菜单可以直接选择Python扩展模块,
可能有的读者新建项目的时候没有这个选项,是因为安装VS的时候没有安装相应的组件,这时候只需要运行VS的安装程序->修改->勾选Python开发,特别是Python本机开发工具需要选中,最后修改后再次打开VS即可。
项目新建python扩展项目后,已经自动生成好了代码模板,和一些项目属性设置,就可以直接进行开发,生成pyd文件的过程也就和3.1的一致,如果生成过程产生报错,按照3.1的属性设置进行相应的修改即可,就不再赘述。