2012-12-02 8 views
7

Ich versuche, C++ - Klassen zu Python mit Cython zu offenbaren. Ich schrieb ihre Definitionen in * .pxd-Datei und implementierte einen Wrapper in * .pyx-Dateien. Aber ich blieb stecken und versuchte, einen Funktionszeiger an den Erweiterungstyp zu übergeben. Hier ist ein vereinfachtes Beispiel.Python-Objekt in Cython-Zeiger konvertieren

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  

Aber auf der l ast line Ich bekomme den Fehler "Python-Objekte können nicht in Zeiger primitiver Typen umgewandelt werden". Ich habe versucht, auch einige andere Ansätze, aber nichts funktionierte:

# 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) 

Antwort

3

ich die Lösung gefunden. Sie müssen Cython sagen, dass foo._impl wirklich cFoo * -Instanz ist. Dies kann durch Bereitstellung einer Foo-Definition (z. B. in foo.pxd) erreicht werden. Danach können Sie das Python-Objekt in Foo umwandeln, und Cython weiß, dass sein _impl-Feld den Typ cFoo * hat.

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__ Konstruktor akzeptieren kann nur reine Python-Objekte gibt es auch __cinit__ aber es kann nur C Urtyp akzeptieren.

Wenn Sie Foo an __init__ übergeben, kann es das _impl Mitglied nicht sehen, nur Mitglieder von Python-Typen können gesehen werden.

Die Lösung wäre cFoo* ausdrücklich, die einen Konstruktor emuliert zu einer Init() Methode zu übergeben:

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

Anruf auf diese Weise:

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

scheint, dass ich nicht tun kann, dass entweder während foo ein Python-Objekt ist. Fehle ich etwas? Ich kann 'Python-Objekt-Argument nicht in Typ' cFoo * 'konvertieren, wenn ich Funktion mit' def 'definiere, und ich kann es nicht von Python aus aufrufen, wenn ich es mit' cdef 'definiere. – DikobrAz

+1

@DikobrAz Hmm scheint, dass Sie cdef Methoden nicht außerhalb einer Klasse aufrufen können, versuchen Sie, Klassenmitglieder über eine globale Funktion anstelle einer 'Init()' Methode zu setzen, siehe dieses Beispiel: http://stackoverflow.com/a/ 12205374/623622 –

+0

Kein Glück.Soweit ich weiß, kann ich cdef-Member nicht von Python aus aufrufen, sie sind nur im Cython-Modul zugänglich. Und ich kann nicht (weiß nicht wie) Python-Objekt in Cython-Zeiger konvertieren, so dass das eigentlich das Problem ist. – DikobrAz