2016-04-06 5 views
3

Ich versuche, eine Cython-Klasse in eine C++ - Klasse einzubetten. Das Erstellen eines Cython-Wrappers für diese C++ - Klasse ist aufgrund der Einschränkungen des Projekts nicht möglich. Und aufgrund der Anzahl der Methoden in den Cython-Klassen und der langen Vererbungen der Cython-Klassen ist das vollständige Entfernen der Methode aus einer Klasse keine attraktive Lösung. Ich muss eine Cython-Klasseninstanz erstellen und ihre Methode aus C++ aufrufen. Jedoch kann ich nicht scheinen, es nicht segfault zu machen. Hier ist ein Beispiel für das Problem:Einbetten von Cython-Klassenmethoden in C++

< < < Datei: fooClass.pyx >>>

from math import sin 
cdef public class Foo[object Foo, type fooType]: 
    cdef double a,b 
    def __cinit__(self, double a, double b): 
     self.a = a 
     self.b = b 
    cdef double bar(self, double c): 
     return sin(self.a*c) 
cdef api double foobar(Foo foo, double d): 
    return foo.bar(d) 

< < < Datei: foo.cpp >>>

#include "fooClass_api.h" 
#include <iostream> 

int main(){ 
    Py_Initialize(); 
    import_fooClass(); 
    Foo foo; 
    foo.a = 1.0; 
    foo.b = 10.0; 
    std::cout << foobar(&foo,5.0) << "\n"; 
    Py_Finalize(); 
} 

< < < Datei: setup.py >>>

from distutils.core import setup 
from Cython.Build import cythonize 
setup (ext_modules = cythonize ("cyClass.pyx")) 

Ich baue mit python setup.py build_ext --inplace und kompilieren mit g ++. Durch Tests weiß ich, dass Py_Initialize() und import_fooClass erfolgreich ist. Und ich weiß, dass ich die Werte von foo.a und foo.b innerhalb von foobar() drucken, aber sobald ich einen Anruf mit dem Foo Objekt innerhalb foobar(), das Programm segfaults machen. Selbst ein Anruf an foo.__dict__ oder foo.callable() innerhalb foobar() verursacht es zu segfault. Ändern der public oder api Schlüsselwörter haben Wirkung gehabt, noch hat das Umschalten zwischen __init__ und __cinit__. Wenn jemand weiß, wie das zu beheben ist, würde ich sehr dankbar sein. Ich vermute, dass es etwas mit Zeigern zu tun hat oder die Python C API missbraucht. Vielen Dank!

+0

In Teil es ist, weil Sie nicht 'foo' sind Initialisierung - es hat einen Zeiger namens ' VTAB 'was zB nie gesetzt ist (siehe" FooClass.h "). Ich denke, du brauchst eine Capi-Funktion, die ein 'Foo' zurückgibt. Aber das wird den Segmentierungsfehler für mich immer noch nicht los und ich kann nicht sofort sehen, was nötig ist, um ihn zu reparieren ... – DavidW

Antwort

0

Nachdem die zuvor erwähnte Technik in einer komplizierteren Einstellung verwendet wurde und wiederholt Segfaults erhalten wurde, ist hier die alternative Methode, die ich verwendet habe. Der wesentliche Unterschied liegt in den api und public Schlüsselwort in der pyx Datei und wie die Klasse in foo.cpp aufgenommen und verwendet wird.

< < < Datei: fooClass.pyx >>>

from math import sin 

cdef public class Foo[object Foo, type fooType]: 
    cdef double a,b 
    def __cinit__(self, double a, double b): 
     self.a = a 
     self.b = b 
    cdef double bar(self, double c): 
     return sin(self.a*c) 

cdef public Foo buildFoo(double a, double b): 
    return Foo(a,b) 

cdef public double foobar(Foo foo, double d): 
    return foo.bar(d) 

< < < Datei: foo.cpp >>>

#include <Python.h> 
#include "fooClass.h" 
#include <iostream> 

int main(){ 
    Py_Initialize(); 
    initfooClass(); 
    Foo *foo = buildFoo(10.0,5.0); 
    std::cout << foobar(foo,5.0) << std::endl; 
    Py_Finalize(); 
} 
1

Ich habe es geschafft, das Problem zu beheben. Basierend auf dem, was David W sagte (danke David!), Erstellte ich eine weitere cdef api Klasse, die als Wrapper für den Konstruktor fungierte. cdef api Foo buildFoo (double a, double b): Das gibt einen Foo* Zeiger zurück, was von foobar(Foo foo, double d) in der .pyx-Datei benötigt wird. Die resultierenden Dateien wie folgt aussehen:

< < < Datei: fooClass.pyx >>>

from math import sin 

cdef public class Foo[object Foo, type fooType]: 
    cdef double a,b 

    def __cinit__(self, double a, double b): 
     self.a = a 
     self.b = b 

    cdef double bar(self, double c): 
     return sin(self.a*c) 

cdef api Foo buildFoo(double a, double b): 
    return Foo(a,b) 

cdef api double foobar(Foo foo, double d): 
    return foo.bar(d) 

< < < Datei: foo.cpp >>>

#include "fooClass_api.h" 
#include <iostream> 

int main(){ 
    Py_Initialize(); 
    import_fooClass(); 
    Foo *foo = buildFoo(10.0,5.0); 
    std::cout << foobar(foo,5.0) << "\n"; 
    Py_Finalize(); 
} 

Mit dem gleichen setup.py Skript.

diese Ergebnisse in -0.262375 Laufen zu stdout gedruckt, die das richtige Ergebnis. Ich hoffe, eine kompliziertere Version dieser Idee zu verwenden, um einige Aufrufe von boost :: python durch meinen Code zu ersetzen, um die Leistung zu verbessern.

+0

Das ist ziemlich genau das, was ich versucht habe und es versäumt habe, zur Arbeit zu kommen! Freut mich, dass du es lösen konntest ... – DavidW