2012-12-02 40 views
7

Tôi đang cố gắng hiển thị các lớp C++ tới python bằng cách sử dụng cython. Tôi đã viết các định nghĩa của chúng trong tệp * .pxd và triển khai trình bao bọc trong các tệp * .pyx. Nhưng tôi đã bị mắc kẹt cố gắng để vượt qua một con trỏ hàm vào loại mở rộng. Đây là ví dụ đơn giản.chuyển đổi đối tượng python sang con trỏ cython

foo.pyx

from c_foo cimport cFoo 
cdef class Foo: 
    cdef cFoo* _impl 

c_foo_holder.pxd

cdef extern from "FooHolder.h": 
    cdef cppclass cFooHolder: 
     cFooHolder(cFoo* foo)  

foo_holder.pyx

from c_foo_holder cimport cFooHolder 
from c_foo cimport cFoo 

cdef class FooHolder: 
    cdef cFooHolder* _impl 
    def __init__(self, foo): 
     self._impl = new cFooHolder(<cFoo*>(foo._impl)) # error here  

Nhưng trên l dòng ast tôi nhận được lỗi "Đối tượng Python không thể được truyền tới con trỏ của các kiểu nguyên thủy". Tôi cũng đã thử một số cách tiếp cận khác, nhưng không làm việc:

# error: 'Foo' is not a type identifier 
from foo import Foo 
def __init__(self, Foo foo): 
    self._impl = new cFooHolder(foo._impl) 

# error: 'Foo' is not a type identifier 
def __init__(self, foo): 
    self._impl = new cFooHolder(<Foo>(foo)._impl) 

Trả lời

3

Tôi tìm thấy giải pháp. Bạn phải nói với cython rằng foo._impl thực sự là cFoo *. Điều đó có thể đạt được bằng cách cung cấp định nghĩa Foo (ví dụ: trong foo.pxd). Sau đó bạn có thể đưa đối tượng python vào Foo và cython sẽ biết rằng trường _impl của nó có kiểu cFoo *.

foo.pxd

from c_foo cimport cFoo 
cdef class Foo: 
    cdef cFoo* _impl 

foo.pyx

from c_foo cimport cFoo 
cdef class Foo: 
    # methods implementation 

c_foo_holder.pxd

cdef extern from "FooHolder.h": 
    cdef cppclass cFooHolder: 
     cFooHolder(cFoo* foo)  

foo_holder.pyx

from c_foo_holder cimport cFooHolder 
from c_foo cimport cFoo 
from foo cimport Foo 

cdef class FooHolder: 
    cdef cFooHolder* _impl 
    def __init__(self, foo): 
     self._impl = new cFooHolder((<Foo?>foo)._impl) 
0

__init__ constructor có thể chỉ chấp nhận đối tượng trăn tinh khiết, đó cũng là __cinit__ nhưng nó có thể chỉ chấp nhận các kiểu dữ liệu C.

Khi bạn vượt qua Foo đến __init__ nó không thể nhìn thấy thành viên _impl, chỉ thành viên của các loại trăn mới có thể được nhìn thấy.

Các giải pháp sẽ được vượt qua cFoo* rõ ràng để một phương pháp Init() mà giả lập một constructor:

cdef class FooHolder: 
    cdef cFooHolder* _impl 
    cdef void Init(self, cFoo* foo_impl): 
     self._impl = new cFooHolder(foo_impl) 

Gọi nó theo cách này:

fooHolder = new FooHolder() 
fooHolder.Init(foo._impl) 
+0

Dường như, tôi không thể làm điều đó trong khi foo là đối tượng python. Tui bỏ lỡ điều gì vậy? Tôi nhận được 'không thể chuyển đổi đối số đối tượng Python để gõ' cFoo * 'nếu tôi xác định chức năng với' def ', và tôi không thể gọi nó từ python nếu tôi định nghĩa nó với' cdef '. – DikobrAz

+1

@DikobrAz Hmm có vẻ như bạn không thể gọi các phương thức cdef bên ngoài một lớp, hãy thử thiết lập các thành viên lớp thông qua một hàm toàn cục thay vì phương thức 'Init()', xem ví dụ sau: http://stackoverflow.com/a/ 12205374/623622 –

+0

Không may mắn.Theo hiểu biết của tôi, tôi không thể gọi các thành viên cdef từ python chút nào, chúng chỉ có thể truy cập được bên trong mô đun cython. Và tôi không thể (không biết làm thế nào) chuyển đổi đối tượng python sang con trỏ con trỏ, vì vậy đó thực sự là vấn đề. – DikobrAz

Các vấn đề liên quan