使用Python包捆绑Cython模块

时间:2016-08-11 21:32:20

标签: python cython packaging

我在Cython中包装C ++库,我想将它作为Python包分发。我一直在使用this tutorial作为指南。

以下是事情的组织方式。

.
├── 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']
    )),
)

2 个答案:

答案 0 :(得分:0)

您的导入声明作用于__init__.py,可能为空 但是您的安装脚本应该创建一个.so文件。因此,您必须使用install而不是build_ext(以及--inplace)运行它,它会为您提供可以导入的.so文件。但请注意setup.py中的姓名,在调用import rect时最终会导入几个可能导入的项目。避免扩展名与包相同(或者相应地修改__init__.py文件)

答案 1 :(得分:0)

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

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