301

Python アプリケーションから C ライブラリを呼び出したい。API 全体をラップするのではなく、自分のケースに関連する関数とデータ型だけをラップします。私が見る限り、私には 3 つの選択肢があります。

  1. C で実際の拡張モジュールを作成します。おそらくやり過ぎです。拡張機能の記述を学習するオーバーヘッドも避けたいと思います。
  2. Cythonを使用して、関連する部分を C ライブラリから Python に公開します。
  3. ctypes外部ライブラリとの通信に使用して、すべてを Python で実行します。

2) と 3) のどちらがより良い選択なのかはわかりません。3) の利点は、それctypesが標準ライブラリの一部であり、結果のコードが純粋な Python になることです。ただし、その利点が実際にどれほど大きいかはわかりません。

どちらを選んでもメリット/デメリットはありますか? どのアプローチをお勧めしますか?


編集:すべての回答に感謝します。似たようなことをしたい人に良いリソースを提供します. もちろん、その決定はまだ 1 つのケースに対して行われる必要があります。「これが正しいことです」というような答えはありません。私の場合は、おそらく ctypes を使用しますが、他のプロジェクトで Cython を試すことも楽しみにしています。

真の答えは 1 つではありません。私は FogleBird の回答を選択しました。これは、ctypes に関するいくつかの優れた洞察を提供し、現在最も投票数の多い回答でもあるためです。ただし、すべての回答を読んで概要を把握することをお勧めします。

再度、感謝します。

4

12 に答える 12

171

警告: Cython コア開発者の意見が先行しています。

ほとんどの場合、ctypes よりも Cython をお勧めします。その理由は、アップグレード パスがはるかにスムーズだからです。ctypes を使用すると、最初は多くのことが単純になります。FFI コードをプレーンな Python で記述し、コンパイルや依存関係の構築などを一切行わないのは確かに素晴らしいことです。ただし、ある時点で、ループまたは相互に依存する長い一連の呼び出しのいずれかで、C ライブラリを何度も呼び出さなければならないことがほぼ確実にわかり、その速度を上げたいと思うでしょう。それが、ctypes ではできないことに気付くポイントです。または、コールバック関数が必要で、Python コールバック コードがボトルネックになっていることがわかった場合は、それを高速化したり、C に移行したりしたいと考えています。繰り返しますが、ctypes ではそれを行うことはできません。

Cython と OTOH を使用すると、ラッピングと呼び出しのコードを自由に細くしたり太くしたりできます。通常の Python コードから C コードへの単純な呼び出しから始めることができます。Cython は、追加の呼び出しオーバーヘッドなしで、Python パラメーターの変換オーバーヘッドを非常に低く抑えて、それらをネイティブ C 呼び出しに変換します。C ライブラリへの高価な呼び出しが多すぎるある時点で、さらにパフォーマンスが必要であることに気付いた場合は、周囲の Python コードに静的な型で注釈を付け始め、Cython に直接 C に最適化してもらうことができます。または、Cython で C コードの一部を書き直して、呼び出しを回避し、ループをアルゴリズム的に特化して強化することもできます。迅速なコールバックが必要な場合は、適切なシグネチャを持つ関数を作成し、それを C コールバック レジストリに直接渡すだけです。繰り返しになりますが、オーバーヘッドはなく、単純な C 呼び出しのパフォーマンスが得られます。また、Cython で十分な速度でコードを取得できない可能性が非常に低い場合でも、その真に重要な部分を C (または C++ または Fortran) で書き直して、Cython コードから自然かつネイティブに呼び出すことを検討できます。しかし、これは唯一の選択肢ではなく、本当に最後の手段になります。

そのため、ctypes は単純なことを行い、何かをすぐに実行するのに適しています。ただし、物事が成長し始めるとすぐに、最初から Cython を使用したほうがよいことに気付く可能性が高くなります。

于 2011-04-16T13:41:45.280 に答える
105

Cython はそれ自体が非常に優れたツールであり、学ぶ価値があり、驚くほど Python 構文に近いものです。Numpy を使用して科学計算を行う場合は、Numpy と統合して行列演算を高速化できる Cython を使用することをお勧めします。

Cython は Python 言語のスーパーセットです。有効な Python ファイルを投げると、有効な C プログラムが吐き出されます。この場合、Cython は Python 呼び出しを基礎となる CPython API にマップするだけです。これにより、コードが解釈されなくなるため、おそらく 50% 高速化されます。

いくつかの最適化を行うには、型宣言など、コードに関する追加の事実を Cython に伝え始める必要があります。つまり、Python の for ループは C の for ループになります。ここでは、大幅な速度の向上が見られます。ここで外部の C プログラムにリンクすることもできます。

Cython コードの使用も信じられないほど簡単です。説明書は難しそうに思いました。あなたは文字通りただ行う:

$ cython mymodule.pyx
$ gcc [some arguments here] mymodule.c -o mymodule.so

次にimport mymodule、Python コードで、C にコンパイルされることを完全に忘れることができます。

いずれにせよ、Cython は簡単にセットアップして使い始めることができるので、自分のニーズに合うかどうか試してみることをお勧めします。探しているツールでなかったとしても、それは無駄ではありません。

于 2009-12-21T20:32:22.000 に答える
43

Python アプリケーションから C ライブラリを呼び出すには、 ctypesの新しい代替手段であるcffiもあります。FFI に新鮮な外観をもたらします。

  • ( ctypesとは対照的に)魅力的でクリーンな方法で問題を処理します。
  • Python以外のコードを書く必要はありません(SWIG、Cythonなどのように)
于 2013-02-18T17:33:30.420 に答える
22

私はそこに別のものを投げます: SWIG

習得が容易で、多くのことを正しく行い、より多くの言語をサポートしているため、習得に費やす時間は非常に役立ちます。

SWIG を使用すると、新しい python 拡張モジュールを作成することになりますが、SWIG がほとんどの面倒な作業を行ってくれます。

于 2009-12-21T20:09:31.287 に答える
12

ctypesは、処理するコンパイル済みライブラリ blob (OS ライブラリなど) が既にある場合に最適です。ただし、呼び出しのオーバーヘッドは深刻なので、ライブラリに対して多くの呼び出しを行い、とにかく C コードを作成する (または少なくともコンパイルする) 場合は、サイトン。作業はそれほど多くなく、結果のpydファイルを使用する方がはるかに高速でPythonicになります。

私は個人的に cython を使用して Python コードを高速化する傾向があります (ループと整数比較は cython が特に優れている 2 つの領域です)。さらに複雑なコードや他のライブラリのラッピングが必要な場合は、Boost.Pythonを使用します。Boost.Python はセットアップが難しい場合がありますが、いったん機能するようになると、C/C++ コードのラッピングが簡単になります。

cython はnumpyのラッピングにも優れています ( SciPy 2009の議事録から学んだことです) が、numpy を使用したことがないため、コメントできません。

于 2009-12-27T15:13:27.583 に答える
9

cython ではなく ctypes を使用し、他の回答では言及されていない問題が 1 つあります。

ctypes を使用すると、結果は使用しているコンパイラにまったく依存しません。ネイティブ共有ライブラリにコンパイルできる言語であれば、多かれ少なかれ任意の言語を使用してライブラリを作成できます。どのシステム、どの言語、どのコンパイラーかは大した問題ではありません。ただし、Cython はインフラストラクチャによって制限されます。たとえば、Windows で intel コンパイラを使用したい場合、cython を機能させるのは非常にトリッキーです。コンパイラを cython に「説明」し、この正確なコンパイラで何かを再コンパイルする必要があります。これにより、移植性が大幅に制限されます。

于 2013-06-12T14:15:18.040 に答える
6

これは古い質問だと思いますが、Google で のようなものを検索すると出てきます。ctypes vs cythonここでの回答のほとんどは、既に熟達している人によって書かれているcythonc、それらを学ぶために費やした実際の時間を反映していない可能性があります。ソリューションを実装します。どちらも全くの初心者です。私はこれまで触れたことがなくcython、経験もほとんどありませんc/c++

この 2 日間、コードのパフォーマンスの高い部分を Python よりも低レベルのものに委譲する方法を探していました。基本的に 2 つの単純な関数で構成されるctypesとの両方にコードを実装しました。Cython

処理が必要な巨大な文字列リストがありました。注意事項liststring. cPython の文字列はデフォルトで Unicode であり、文字列はそうではないため、両方の型が の型に完全に対応してcいるわけではありません。Python のリストは単に c の配列ではありません。

これが私の評決です。を使用しcythonます。Python との統合がよりスムーズになり、一般的に操作が容易になります。何か問題がctypes発生して segfault がスローcythonされると、少なくとも可能な限りスタック トレースでコンパイル警告が表示され、有効な python オブジェクトを簡単に返すことができますcython

これは、同じ機能を実装するために両方に投資する必要があった時間の詳細な説明です。ちなみに、C/C++ プログラミングはほとんどしませんでした。

  • Cタイプ:

    • 私のユニコード文字列のリストをac互換タイプに変換する方法を研究するのに約2時間。
    • ac 関数から適切に文字列を返す方法についての約 1 時間。ここでは、関数を作成したら、実際にSOに独自のソリューションを提供しました。
    • C でコードを記述し、動的ライブラリにコンパイルするのに約 30 分かかります。
    • Python でテスト コードを記述して、cコードが機能するかどうかを確認するのに 10 分かかります。
    • いくつかのテストを行い、cコードを再配置するのに約 1 時間。
    • c次に、コードを実際のコードベースにプラグインしましたが、モジュールのハンドラーがデフォルトで選択できないため、モジュールctypesでうまく機能しないことがわかりました。multiprocessing
    • 約 20 分、モジュールを使用しないようにコードを再配置し、multiprocessing再試行しました。
    • 次に、コードの 2 番目の関数はc、テスト コードに合格しましたが、コード ベースで segfaults を生成しました。ええと、これはおそらくエッジケースをうまくチェックしなかった私のせいです。私は簡単な解決策を探していました。
    • 約 40 分間、これらのセグメンテーション違反の考えられる原因を突き止めようとしました。
    • 関数を 2 つのライブラリに分割して、もう一度試しました。私の2番目の機能にはまだセグメンテーション違反がありました。
    • 私は2番目の関数を手放し、cコードの最初の関数のみを使用することに決め、それを使用するpythonループの2回目または3回目の繰り返しで、UnicodeErrorすべてをエンコードおよびデコードしましたが、ある位置でバイトをデコードしないことについて話しました明示的に。

この時点で、代替案を探すことにし、以下を調べることにしましたcython

  • シトン
    • cython hello worldを 10 分間読む。
    • の代わりにcython を使用する方法についてSOを確認する 15 分間。setuptoolsdistutils
    • cython 型と python 型に関する 10 分間の読み物。組み込みの Python 型のほとんどを静的型付けに使用できることを学びました。
    • Python コードに cython 型を再注釈付けするのに 15 分。
    • setup.pyコードベースでコンパイル済みモジュールを使用するように my を変更する 10 分。
    • multiprocessingモジュールをコードベースのバージョンに直接プラグインしました。できます。

記録のために、もちろん、私は投資の正確なタイミングを測定しませんでした. 私が ctypes を扱っている間、あまりにも多くの精神的努力が必要だったために、私の時間の認識が少し注意深いものだったのかもしれません。しかし、それは扱う感覚を伝える必要がcythonありますctypes

于 2020-01-04T03:47:56.110 に答える
5

Windows を対象としており、いくつかの独自の C++ ライブラリをラップすることを選択した場合、msvcrt***.dll(Visual C++ ランタイム) の異なるバージョンがわずかに互換性がないことにすぐに気付くかもしれません。

Cythonこれは、結果が(Python 2.7)または(Python 3.x)wrapper.pydに対してリンクされているため、使用できない可能性があることを意味します。ラップしているライブラリが異なるバージョンのランタイムにリンクされている場合は、運が悪いです。msvcr90.dll msvcr100.dll

次に、C++ ライブラリの C ラッパーを作成し、そのラッパー DLL を C++ ライブラリと同じバージョンに対してリンクする必要がありますmsvcrt***.dll。そしてctypes、実行時に手巻きのラッパー dll を動的にロードするために使用します。

そのため、次の記事で非常に詳細に説明されている細かい詳細がたくさんあります。

「美しいネイティブ ライブラリ(Python で)」: http://lucumr.pocoo.org/2013/8/18/beautiful-native-libraries/

于 2014-02-23T11:31:10.273 に答える
3

GLibを使用しているライブラリにGObjectIntrospectionを使用する可能性も1つあります。

于 2011-09-01T05:19:39.427 に答える