2016-04-06 18 views
3

C++クラスにCythonクラスを埋め込みしようとしています。このC++クラス用のCythonラッパーを作成することは、プロジェクトの制約を受けては不可能です。また、Cythonクラスのメソッドの数やCythonクラスの長い継承のため、クラスからメソッドを完全に削除することは魅力的なソリューションではありません。 Cythonクラスのインスタンスを作成し、そのメソッドをC++から呼び出す必要があります。しかし、私はsegfaultではないように思えます。ここでは、問題の例である:C++でのCythonクラスメソッドの埋め込み

< < <ファイル: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) 

< < <ファイル: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(); 
} 

< < <ファイル:setup.py >>>

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

python setup.py build_ext --inplaceでビルドし、g ++でコンパイルします。テストを通して私はPy_Initialize()import_fooClassが成功していることを知っています。そして、私はfoo.afoo.bの値をfoobar()の中に印刷していますが、の中にFooオブジェクトを使って電話をすると、プログラムはsegfaultsになります。 foo.__dict__またはfoo.callable()への呼び出しでさえ、foobar()の中にセグメンテーションが発生します。 publicまたはapiキーワードを変更しても、__init____cinit__の間で切り替わることはありませんでした。誰かがこれを修正する方法を知っていれば、私は非常に感謝するだろう。私はそれがポインターやPythonのC APIを悪用する何かを持っていると思われる。本当にありがとう!

+0

あなたは 'Foo'を初期化されていないため、一部ではそれはだ - それは' vtab と呼ばれるポインタを持っています'は決して設定されません(例えば、" FooClass.h "参照)。 'Foo'を返すcapi関数が必要だと思います。しかし、それはまだ私のセグメンテーション違反を取り除くことはできません。私はすぐにそれを修正するために必要なものを見ることができません... – DavidW

答えて

0

より複雑な設定で前述の手法を使用し、繰り返しsegfaultsを取得した後、私が使用した別の方法があります。主な違いはpyxファイルのapipublicのキーワードとそのクラスが含まれており、foo.cppでどのように使用されているかです。

< < <ファイル: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) 

< < <ファイル: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

問題を解決できました。デビッドWが言ったことに基づいて(Davidに感謝します)、コンストラクタのラッパーとして動作する別のcdef apiクラスを作成しました。ポインタを返します。foobar(Foo foo, double d)が.pyxファイルに必要です。結果のファイルは次のようになります。これを利用した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(); 
} 

< < <ファイル: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) 

< < <ファイルをsetup.pyスクリプト。

これを実行すると、正しい結果である-0.262375がstdoutに出力されます。このアイデアのより複雑なバージョンを使用して、コード全体でboost :: pythonの呼び出しを置き換えて、パフォーマンスを改善したいと考えています。

+0

それは私が試したもので、動作することに失敗したものです!あなたはそれを解決することができてうれしい... – DavidW