2016-08-11 86 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)'。當我在沒有安裝的情況下安裝就位時也是如此。 –