2012-01-19 13 views
19

私はC++クラスを持っています。 1つの.ccpファイルと1つの.hファイルで構成されています。コンパイル(私はそれをC++でうまく使用するメインメソッドを書くことができます)。このクラスをCythonでラップしてPythonで利用できるようにするにはどうすればよいですか?CythonでC++クラスをラップするにはどうすればよいですか?

私はドキュメントを読んだ後に従いません。彼らはcppファイルの生成について話します。私がドキュメントに従おうとすると、私の既存のcppが吹き飛ばされてしまいます...

私はpyxファイルに何を入れるつもりですか?私はクラスの定義を聞いたことがありますが、どれくらいですか?ちょうど公共の方法ですか?

.pxdファイルが必要ですか?私はこのファイルがいつ必要なのか分からないのですか?

私はこれらの質問を#python IRCチャンネルで試してみましたが、回答を得られませんでした。

+0

質問に答えられた場合は、この質問に回答としてマークしてください。それ以外の場合はもう一度質問をしてください。 –

+0

@NiklasRあなたの答えは私の混乱の領域の一部をカバーしましたが、私をすべて邪魔しませんでした。私はあなたに投票を与えましたが、私は余裕があるときに私が取り組んだ他のビットの完全な答えを書くことを意図しました。 – Endophage

答えて

6

私は泣き叫んで私の髪を裂いてしまったので、ついにこれを働かせました。まず、私はC++をCに書き直さなければなりませんでした。実際には、すべてのstd::string変数をchar*に変換し、いくつかの長さを記録していました。

完了したら私の.hと.cファイルがありました。私は、Pythonで利用可能なCコードから単一の関数を作成したかったのです。 CythonはあなたのC言語のファイルをあなたのためのエクステンションにコンパイルし、すべてのライブラリを一度にリンクすることができます。PY、それはこのように見てしまった:

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 
) 

あなたが見ることができるように、拡張への2番目の引数は単にコンパイルする必要があるすべてのファイルを一覧表示し、Cythonは、そのファイルの拡張子に応じて、それらをコンパイルする方法をうまくいきます私の知る限り。ライブラリ配列は、Cythonコンパイラに何をリンクする必要があるのか​​を伝えます(この場合、私は既存のPythonライブラリをそのまま模倣することができなかった暗号のものをラッピングしています)。

実際に.pyxファイルでC関数を使用できるようにするには、.pxdに小さなラッパーを記述します。私myext.pxdは、以下のように見えた:あなたは、それが他のPythonの関数であるかのように使用するために利用可能である、この機能をインポートするcimport宣言を使用し.pyxで

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

cimport myext 

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

これを(少なくともMac上で)ビルドすると、Pythonでインポートして.pyxから関数を実行できる.soが得られます。このすべての作業を得るには、より良い、より正しい方法があるかもしれませんが、それは経験から来ており、これは私がうまくいった最初の遭遇でした。私は間違っている可能性のあるポインタに非常に興味があります。

更新:Cythonのさらなる使用後

、私はあなたが何をやっている知っていれば、あまりにもC++と統合するために、超簡単でした。 C++のstringを利用可能にすることは、pyx/pydのfrom libcpp.string cimport stringと同じくらい簡単です。 C++クラスを宣言することも同様に容易である:

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

確かに、あなたは基本的にPython的形式でクラスの.hの定義を再宣言する必要があり、それはあなたの既に書かれてC++の機能へのアクセスを得るために支払うために小さな価格です。

+0

私を助けてください! CythonとC++でPython 3.3を使いたいのですが、いくつかのサンプルファイルがありますか?私は最新のCythonとPythonをインストールしました。 – PascalVKooten

+0

Python 3のサンプルファイルはありませんが、コンパイラフラグを正しく設定していることを確認してください。http://wiki.cython.org/FAQ#WhatPythonversionsdoesCythonsupport.3F 発生している特定の問題あなたがここでコメントにリンクすれば、私は一見することができます。 – Endophage

+0

例としてこれが特に役立つかどうかわかりませんが、私は[このPython 3.3のC++ライブラリのラッパー](https://github.com/wmayner/pyemd)と書いています。 – Will

3

Cythonは主にC開発用です.C++とPythonを統合するには、Boost.Pythonをお勧めします。彼らの優れたドキュメンテーションはあなたがかなり早く始めるはずです。

+0

Boost.Python、Shinboken(PySideプロジェクトから)、SIP(PyQTプロジェクトから)に加え、SWIGはC++オブジェクトをラップすることもできると思います。あなたは理論的にはCythonでC++コードをラップすることができますが、手書きで多くのことをする必要があります。 – synthesizerpatel

+0

私はブーストとそのライブラリの多くの品質について非常に高い評価を受けていますので、通常はオプションのリストが与えられたときの最初の選択です。あなたが提示したオプションに関しては、PySideは比較的新しいものであり、私が関係する限り、証明されていません。 SIPは一部の人を抑えるGPLライセンスに基づいています。私はSWIGと不快な経験をしていますので、私はそれを自分で推薦することはできません。いつものように、YMMVですが、私の意見ではBoostで間違っていることはほとんどありません。 – spatz

+0

@spatz申し訳ありませんが、Boost.Pythonの優れたドキュメント、あるいはBoostの一般的なドキュメントには同意できません。私は彼らのドキュメントが過去に完全に誤解を招くか、完全に失われていることを発見しました。私は数ヶ月前にネットワーク/ソケットライブラリを使って作業していましたが、試行錯誤の大量でした。 – Endophage

14

偶数Cythonは一般にCで使用するため、C++コードも生成できます。コンパイル時に、--cplusフラグを追加します。

クラスのラッパーを作成するのは簡単で、構造をラップすることとほとんど変わりません。主にexternの宣言とは異なりますが、それほど大きな違いはありません。

MyCppClassmycppclass.hにあるとします。 newキーワード--cplusフラグが設定されている場合にのみ利用可能であること

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 

注、そうでなければそれをexterningにより<stdlib.h>からmallocを使用します。

また、メソッドを呼び出すためにポインタ(->)を逆参照する必要はありません。 Cythonはオブジェクトのタイプを追跡し、適切なものを適用します。

.pxdファイルは、実装からの宣言の分離、または名前空間の衝突を避けるためのものです。 C++クラスのようなPythonラッパーの名前を付けたいとします。単に.pxdファイルにextern宣言を入れ、cimport .pyxにpxdファイルを入れるだけです。

cimport my_pxd 
cdef my_pxd.SomeExternedType obj 

実装を.pxdファイルに書き込むことはできません。

+1

ご不明な点がございましたら、お気軽にお問い合わせください。 :) –

+0

私のC++はOpenSSLの機能を使用しています。私のpxdで宣言する必要がある機能ですか? – Endophage

+0

また、私はC++をCに変換することができますが、それは実際に私が問題をさらに深める手助けをしていませんでした。 – Endophage

関連する問題