假设我们需要让Python调用的C++代码如下(文件名为demo.h
):
#ifndef DEMO_H
#define DEMO_H
using namespace std;
namespace demo {
class MyDemo {
public:
int a;
MyDemo();
MyDemo(int a );
~MyDemo();
int mul(int m );
int add(int b);
void sayHello(char* name);
};
}
#endif
对应的C++实现代码如下(demo.cpp
):
#include "demo.h"
#include
namespace demo {
MyDemo::MyDemo () {}
MyDemo::MyDemo (int a) {
this->a = a;
}
MyDemo::~MyDemo () {}
int MyDemo::mul(int m) {
return this->a*m;
}
int MyDemo::add (int b) {
return this->a+b;
}
void MyDemo::sayHello(char* name){
cout<<"hello "<<name<<"!"<<endl;
}
}
pxd
文件pxd
文件可以看成是Cython
(即pyx
文件)的头文件,关于pxd
和pyx
文件可以简单如下来理解:
pxd
文件是pyx
与C/C++
之间的桥梁。
pyx
是C/C++
与Python
之间的桥梁。
既然pxd
是头文件,那就是跟demo.h
长的很像,创建cdemo.pxd
文件,内容如下。
cdef extern from "demo.cpp":
pass
# Decalre the class with cdef
cdef extern from "demo.h" namespace "demo":
cdef cppclass MyDemo:
MyDemo() except +
MyDemo(int) except +
int a
int mul(int )
int add(int )
void sayHello(char*)
pyx
文件前面说过,pyx
文件是C/C++
与Python
之间的桥梁,也就是pyx
文件会将C/C++
代码做一层包装,方便Python直接调用,创建adapter.pyx
文件,代码如下。
# distutils: language = c++
from cdemo cimport MyDemo
# Create a Cython extension type which holds a C++ instance
# as an attribute and create a bunch of forwarding methods
# Python extension type.
cdef class PyMyDemo:
cdef MyDemo c_mydemo # Hold a C++ instance which we're wrapping
def __cinit__(self,a):
self.c_mydemo = MyDemo(a)
def mul(self, m):
return self.c_mydemo.mul(m)
def add(self,b):
return self.c_mydemo.add(b)
def sayHello(self,name ):
self.c_mydemo.sayHello(name)
其中,第一行# distutils: language = c++
会指定当前文件生成C++
文件。创建PyMyDemo类用于将C/C++
代码做一层封装,使得Python能直接调用。
setup.py
文件setup.py
文件相对比较简单,代码如下。
from distutils.core import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize("adapter.pyx"))
在控制台输入如下命令:
python setup.py build_ext --inplace
执行命令后,在当前目录会生成adapter.cpp
,这个文件是根据adapter.pyx
生成的。同时还会生成adapter.cp36-win_amd64.pyd
文件(Linux
环境下对应so
文件)。 这里的pyd
文件是windows平台对应文件,这就是我们需要的文件。
测试结果如下
>>> from adapter import PyMyDemo
>>> demo=PyMyDemo(2)
>>> demo.add(1)
3
>>> demo.mul(2)
4
>>> demo.sayHello(b'HuaChao')
hello HuaChao!