2012-01-19 12 views
19

Tôi có một lớp C++. Nó được tạo thành từ một tệp .ccp và một tệp .h. Nó biên dịch (tôi có thể viết một phương thức chính sử dụng nó thành công trong C++). Làm thế nào để bọc lớp này với Cython để làm cho nó có sẵn trong Python?Làm cách nào để bọc một lớp C++ bằng Cython?

Tôi đã đọc tài liệu và không theo dõi. Họ nói về việc tạo ra tệp cpp. Khi tôi đã cố gắng làm theo các tài liệu, cpp đã tồn tại của tôi bị thổi bay đi ...

Tôi có ý nghĩa gì để đưa vào tệp pyx? Tôi đã được nói với định nghĩa lớp học nhưng bao nhiêu? Chỉ là phương pháp công cộng?

Tôi có cần tệp .pxd không? Tôi không hiểu khi nào tệp này là hoặc không bắt buộc.

Tôi đã thử hỏi những câu hỏi này trong kênh IRC#python và không thể nhận được câu trả lời.

+0

Nếu câu hỏi của bạn đã được trả lời, vui lòng đánh dấu câu hỏi này là đã trả lời. Nếu không, vui lòng chỉ định câu hỏi của bạn một lần nữa. –

+0

@NiklasR Câu trả lời của bạn bao gồm một số lĩnh vực của tôi về sự nhầm lẫn nhưng không giúp tôi có được tất cả các cách. Tôi đã cho bạn một cuộc bỏ phiếu nhưng dự định viết một câu trả lời đầy đủ của các bit khác tôi đã làm việc ra khi tôi có thời gian rảnh rỗi. – Endophage

Trả lời

6

Vì vậy, sau nhiều lần chọc, thử và sai, la hét và xé tóc ra, cuối cùng tôi cũng đã làm việc này. Đầu tiên, tôi phải viết lại C++ của mình thành C, mà tôi thực sự chỉ chuyển đổi tất cả các biến số std::string thành char* và theo dõi một số độ dài.

Sau khi hoàn tất, tôi có các tệp .h và .c. Tôi muốn tạo một hàm duy nhất từ ​​mã C có sẵn bằng Python. Nó chỉ ra rằng Cython có thể biên dịch các tập tin C của bạn vào phần mở rộng cho bạn và liên kết bất kỳ thư viện tất cả trong một đi, vì vậy bắt đầu với thiết lập của tôi.py, nó đã kết thúc tìm kiếm như thế này:

from distutils.core import setup 
from distutils.extension import Extension 
from Cython.Distutils import build_ext 

ext_modules=[ 
    Extension("myext", 
    ["myext.pyx", "../stuff.c"], 
    libraries=["ssl", "crypto"] 
) 
] 

setup(
    name = "myext", 
    cmdclass = {"build_ext": build_ext}, 
    ext_modules = ext_modules 
) 

Như bạn có thể thấy, đối số thứ hai đến mở rộng chỉ đơn giản là liệt kê tất cả các tập tin mà cần phải được biên dịch, Cython làm việc ra làm thế nào để biên dịch chúng tùy thuộc vào phần mở rộng tập tin của họ theo như tôi có thể nói. Các mảng thư viện cho trình biên dịch Cython những gì cần phải được liên kết trong (trong trường hợp này tôi đã gói một số công cụ mã hóa mà tôi dường như không thể bắt chước trực tiếp thông qua các thư viện Python hiện có).

Để thực sự làm cho hàm C của tôi khả dụng trong tệp .pyx, bạn viết một trình bao bọc nhỏ trong tệp .pxd. myext.pxd của tôi trông như dưới đây:

cdef extern from "../stuff.h": 
    char* myfunc(char* arg1, char* arg2, char* arg3) 

Trong .pyx sau đó bạn sử dụng tờ khai nhập khẩu cimport chức năng này, mà sau đó có sẵn để sử dụng như thể nó là bất kỳ chức năng Python khác:

cimport myext 

def my_python_func(arg1, arg2, arg3): 
    result = myext.myfunc(arg1, arg2, arg3) 
    return result 

Khi bạn xây dựng này (trên Mac ít nhất) bạn nhận được một .so mà bạn có thể nhập khẩu trong python và chạy các chức năng từ .pyx. Có thể có cách tốt hơn, chính xác hơn để làm cho tất cả điều này hoạt động nhưng điều đó xuất phát từ kinh nghiệm và đây là lần gặp gỡ đầu tiên mà tôi đã cố gắng giải quyết. Tôi sẽ rất quan tâm đến các con trỏ mà tôi có thể đã đi sai.

Cập nhật:

Sau khi tiếp tục sử dụng Cython, tôi thấy đó là siêu đơn giản để tích hợp nó với C++ quá, một khi bạn biết những gì bạn đang làm. Làm cho string của C++ có sẵn đơn giản như from libcpp.string cimport string trong pyx/pyd của bạn. Khai báo lớp C++ là dễ dàng tương tự như:

cdef extern from "MyCPPClass.h": 
    cdef cppclass MyCPPClass: 
     int foo; 
     string bar; 

Chắc chắn bạn phải về cơ bản redeclare định nghĩa .h của lớp học của bạn trong một định dạng Pythonic, nhưng đó là một giá nhỏ để trả cho việc tiếp cận đã viết chức năng của C++ .

+0

Xin hãy giúp tôi! Tôi thực sự muốn sử dụng Python 3.3 với Cython & C++, bạn có thể có một số tập tin ví dụ? Tôi đã cài đặt Cython và Python mới nhất. – PascalVKooten

+0

Tôi không có bất kỳ tệp ví dụ nào cho Python 3, tuy nhiên, hãy đảm bảo rằng bạn đang đặt cờ trình biên dịch chính xác http://wiki.cython.org/FAQ#WhatPythonversionsdoesCythonsupport.3F Đặt câu hỏi tại đây với SO các vấn đề cụ thể mà bạn đang gặp phải. Nếu bạn liên kết nó ở đây trong các bình luận tôi có thể xem. – Endophage

+0

Không chắc chắn nếu điều này sẽ đặc biệt hữu ích như là một ví dụ, nhưng tôi đã viết [này Python 3.3 wrapper cho một thư viện C + +] (https://github.com/wmayner/pyemd). – Will

3

Cython chủ yếu cho phát triển C, để tích hợp C++ với Python, tôi khuyên bạn nên Boost.Python. Tài liệu tuyệt vời của họ sẽ giúp bạn bắt đầu khá nhanh chóng.

+0

Ngoài Boost.Python, Shinboken (từ dự án PySide), và SIP (Từ dự án PyQT) và tôi tin SWIG cũng có thể bọc các đối tượng C++. Bạn có thể trong lý thuyết gói C + + mã với Cython, nhưng bạn phải sử dụng tên mangled và làm rất nhiều thứ bằng tay - Tôi sẽ không khuyên bạn nên bản thân mình. – synthesizerpatel

+0

Vì tôi có * rất liên quan đến Boost và chất lượng của nhiều thư viện, nó thường là lựa chọn đầu tiên của tôi khi đưa ra một danh sách các tùy chọn. Đối với các tùy chọn bạn trình bày: PySide là tương đối mới và theo như tôi quan tâm, chưa được chứng minh. SIP thuộc giấy phép GPL có thể ngăn cản một số người. Tôi đã có một số kinh nghiệm khó chịu với SWIG, vì vậy tôi không thể giới thiệu nó bản thân mình. Như mọi khi, YMMV, nhưng theo ý kiến ​​của tôi, bạn khó có thể đi sai với Boost. – spatz

+0

@spatz Tôi xin lỗi nhưng tôi không thể đồng ý về tài liệu tuyệt vời cho Boost.Python, hoặc thậm chí Tăng nói chung. Tôi đã tìm thấy tài liệu của họ chỉ đơn giản là gây hiểu nhầm hoặc mất tích hoàn toàn trong quá khứ. Tôi đã làm việc với các thư viện mạng/socket của họ một vài tháng trước và đó là một lượng lớn thử nghiệm và lỗi. – Endophage

14

Ngay cả Cython thường được sử dụng với C, nó cũng có thể tạo ra mã C++. Khi biên dịch, bạn thêm cờ --cplus.

Bây giờ, việc tạo trình bao bọc cho lớp rất đơn giản và không khác nhiều so với việc gói cấu trúc. Nó chủ yếu khác với tuyên bố các extern, nhưng đó không phải là nhiều sự khác biệt cả.

Giả sử bạn có một lớp học MyCppClass trong mycppclass.h.

cdef extern from "mycppclass.h": 
    cppclass MyCppClass: 
     int some_var 

     MyCppClass(int, char*) 
     void doStuff(void*) 
     char* getStuff(int) 

cdef class MyClass: 

    # the public-modifier will make the attribute public for cython, 
    # not for python. Maybe you need to access the internal C++ object from 
    # outside of the class. If not, you better declare it as private by just 
    # leaving out the `private` modifier. 
    # ---- EDIT ------ 
    # Sorry, this statement is wrong. The `private` modifier would make it available to Python, 
    # so the following line would cause an error es the Pointer to MyCppClass 
    # couldn't be converted to a Python object. 
    #>> cdef public MyCppClass* cobj 
    # correct is: 
    cdef MyCppClass* obj 

    def __init__(self, int some_var, char* some_string): 
     self.cobj = new MyCppClass(some_var, some_string) 
     if self.cobj == NULL: 
      raise MemoryError('Not enough memory.') 

    def __del__(self): 
     del self.cobj 

    property some_var: 
     def __get__(self): 
      return self.cobj.some_var 
     def __set__(self, int var): 
      self.cobj.some_var = var 

Lưu ý rằng các từ khóa new chỉ có sẵn khi cờ --cplus được thiết lập, nếu không sử dụng malloc từ <stdlib.h> bởi externing nó.

Cũng lưu ý rằng bạn không cần phải dereference con trỏ (->) để gọi phương thức. Cython theo dõi kiểu của đối tượng và áp dụng những gì phù hợp.

tệp .pxd dành cho việc phân tách các khai báo từ việc triển khai hoặc để tránh xung đột không gian tên. Hãy tưởng tượng bạn muốn đặt tên cho bạn là trình bao bọc Python giống như lớp C++. Chỉ cần đặt tệp .pxd của bạn vào các khai báo externcimport tệp pxd trong tệp .pyx.

cimport my_pxd 
cdef my_pxd.SomeExternedType obj 

Lưu ý rằng bạn không thể ghi triển khai trong tệp .pxd.

+1

Nếu bạn có thêm bất kỳ câu hỏi nào, đừng ngại hỏi. :) –

+0

Vì vậy, C++ của tôi sử dụng chức năng từ OpenSSL. Các chức năng đó có cần khai báo trong pxd của tôi không? – Endophage

+0

Ngoài ra, tôi có thể chuyển đổi C++ thành C, nhưng điều đó đã không thực sự giúp tôi có thêm bất kỳ vấn đề nào ... – Endophage