使用Python包捆绑Cython模块
我正在用Cython包装C++库,我想将它作为Python包分发。我一直在使用this tutorial作为指导。使用Python包捆绑Cython模块
以下是事情的组织方式。
.
├── inc
│ └── Rectangle.h
├── rect
│ ├── __init__.py
│ └── wrapper.pyx
├── setup.py
└── src
└── Rectangle.cpp
我贴这些文件的内容在文章的底部,以及在此GitHub repo。
我没有问题编译和安装与python setup.py install
,我可以import rect
从解释器没有问题。但它似乎是一个空的类:我无法用以下任何一种方法创建一个Rectangle
对象。 - Rectangle
- rect.Rectangle
- wrapper.Rectangle
- rect.wrapper.Rectangle
我在做什么错在这里?
Rectangle.h
的内容,从本教程复制并粘贴。
namespace shapes {
class Rectangle {
public:
int x0, y0, x1, y1;
Rectangle();
Rectangle(int x0, int y0, int x1, int y1);
~Rectangle();
int getArea();
void getSize(int* width, int* height);
void move(int dx, int dy);
};
}
Rectangle.cpp
的内容。
#include "Rectangle.h"
namespace shapes {
Rectangle::Rectangle() { }
Rectangle::Rectangle(int X0, int Y0, int X1, int Y1) {
x0 = X0;
y0 = Y0;
x1 = X1;
y1 = Y1;
}
Rectangle::~Rectangle() { }
int Rectangle::getArea() {
return (x1 - x0) * (y1 - y0);
}
void Rectangle::getSize(int *width, int *height) {
(*width) = x1 - x0;
(*height) = y1 - y0;
}
void Rectangle::move(int dx, int dy) {
x0 += dx;
y0 += dy;
x1 += dx;
y1 += dy;
}
}
Cython包装代码wrapper.pyx
。
# distutils: language = c++
# distutils: sources = src/Rectangle.cpp
cdef extern from "Rectangle.h" namespace "shapes":
cdef cppclass Rectangle:
Rectangle() except +
Rectangle(int, int, int, int) except +
int x0, y0, x1, y1
int getArea()
void getSize(int* width, int* height)
void move(int, int)
cdef class PyRectangle:
cdef Rectangle c_rect # hold a C++ instance which we're wrapping
def __cinit__(self, int x0, int y0, int x1, int y1):
self.c_rect = Rectangle(x0, y0, x1, y1)
def get_area(self):
return self.c_rect.getArea()
def get_size(self):
cdef int width, height
self.c_rect.getSize(&width, &height)
return width, height
def move(self, dx, dy):
self.c_rect.move(dx, dy)
这个setup.py
脚本我已经适应这个文件组织。
from distutils.core import setup, Extension
from Cython.Build import cythonize
setup(
name='rect',
packages=['rect'],
ext_modules=cythonize(Extension(
'Rectangle',
sources=['rect/wrapper.pyx', 'src/Rectangle.cpp'],
include_dirs=['inc/'],
language='c++',
extra_compile_args=['--std=c++11'],
extra_link_args=['--std=c++11']
)),
)
在这种情况下,问题原来是.pyx
文件和扩展名没有相同的基本名称。当我将wrapper.pyx
重命名为Rectangle
并重新安装时,我可以在Python解释器中运行以下代码。
>>> import Rectangle
>>> r = Rectangle.PyRectangle(0, 0, 1, 1)
>>> r.get_area()
1
>>>
你import语句作用于__init__.py
这可能是空的 但你的安装脚本应创建是一个.so
文件。因此,你必须运行它不install
但build_ext
(和--inplace
)它给你.so
文件,然后可以导入。但要注意您在setup.py
中的姓名,当致电import rect
时,您最终会输入几个可能的项目。避免扩展名与包相同(或相应地修改__init__.py
文件)
运行'python setup.py install'时调用'build_ext'任务,并创建一个'.so'文件(在'build /'目录中)并安装。运行'python setup.py build_ext --inplace'会在根目录下创建文件。你能澄清这对我有什么帮助吗? –
我怀疑基本问题仍然是名称的选择。你有一个'rect.so'文件和一个带有__init __。py'文件的'rect'文件夹。最后导入空模块而不是'rect.so'文件。正如我所说,我认为改变扩展名将解决这种模糊性,并用'python setup.py build_ext --inplace'在根目录下有模块,所以不需要扩展PYTHONPATH或做任何事情。 – ChE
好吧,事实证明我可以在运行'python setup.py install'后导入Rectangle',但是我得到以下警告:'ImportError:动态模块没有定义模块导出函数(PyInit_Rectangle)'。当我在没有安装的情况下安装就位时也是如此。 –
你看过[Thearn的简单的cython示例](https://github.com/thearn/simple-cython-example)。部分看起来像你的'setup.py'可能有问题,因为你的'Extension'为'Rectangle',导致在'python/site-packages'中创建了'Rectangle.so'。你也会想改变你的'__init __。py',这样它就可以从你的'Rectangle.so/wrapper'中导入你的类,并且将这个扩展名称作为'rect.Rectangle'或者其他的东西。 –