2016-08-11 75 views
0

我正在用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'] 
    )), 
) 
+0

你看过[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'或者其他的东西。 –

回答

0

在这种情况下,问题原来是.pyx文件和扩展名没有相同的基本名称。当我将wrapper.pyx重命名为Rectangle并重新安装时,我可以在Python解释器中运行以下代码。

>>> import Rectangle 
>>> r = Rectangle.PyRectangle(0, 0, 1, 1) 
>>> r.get_area() 
1 
>>> 
0

你import语句作用于__init__.py这可能是空的 但你的安装脚本应创建是一个.so文件。因此,你必须运行它不installbuild_ext(和--inplace)它给你.so文件,然后可以导入。但要注意您在setup.py中的姓名,当致电import rect时,您最终会输入几个可能的项目。避免扩展名与包相同(或相应地修改__init__.py文件)

+0

运行'python setup.py install'时调用'build_ext'任务,并创建一个'.so'文件(在'build /'目录中)并安装。运行'python setup.py build_ext --inplace'会在根目录下创建文件。你能澄清这对我有什么帮助吗? –

+0

我怀疑基本问题仍然是名称的选择。你有一个'rect.so'文件和一个带有__init __。py'文件的'rect'文件夹。最后导入空模块而不是'rect.so'文件。正如我所说,我认为改变扩展名将解决这种模糊性,并用'python setup.py build_ext --inplace'在根目录下有模块,所以不需要扩展PYTHONPATH或做任何事情。 – ChE

+0

好吧,事实证明我可以在运行'python setup.py install'后导入Rectangle',但是我得到以下警告:'ImportError:动态模块没有定义模块导出函数(PyInit_Rectangle)'。当我在没有安装的情况下安装就位时也是如此。 –