4

外部 C ライブラリを Python にラップするさまざまな方法を再評価しています。私はずっと前にプレーンな Python C API を使用することを選択していました。これは高速で、シンプルで、スタンドアロンであり、私が思っていたとおり、将来も保証されていました。それからPyPy、CPython API をサポートする予定はないようですが、将来的には興味深い代替手段になる可能性がある . ctypesは遅かったので、cythonPyPy をサポートするために努力しているように見える に戻りました。

私のライブラリには同じシグネチャを持つ関数がたくさんあるので、C プリプロセッサ マクロを多用して Python モジュールを生成しました。Python言語全体にアクセスできるため、これはcythonでより快適になると思いました。ただし、関数ラッパーのファクトリを作成するのに問題があります。

import cython
from numpy cimport ndarray, double_t

cimport my_c_library

cdef my_c_library.data D

ctypedef double_t DTYPE_t

cdef parse_args(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
    D.n = P.size
    D.m = x.size
    D.P = <double*> P.data
    D.x = <double*> x.data
    D.y = <double*> y.data

def _fun_factory(name):
    cpdef fun(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
        parse_args(P, x, y)
        getattr(my_c_library, name)(&D)
        return y
    return fun

fun1 = _fun_factory('fun1')
fun2 = _fun_factory('fun2')
# ... many more function definitions ...

cpdef内部_fun_factory. _ ここで何が問題なのですか?pyxファイルは通常の python ファイルと同じだと思っていました。pyxのような別の python スクリプトから動的にファイルを生成するという明白な方法以外に、これを機能させる方法はありますsetup.pyか?

また、cython が許可しないことにも驚きました。

ctypedef ndarray[double_t, ndim=1] p_t

コードをクリーンアップします。なぜこれが機能しないのですか?

自動C -> cython翻訳機が存在することは承知していますが、そのようなサードパーティのツールに依存することには消極的です。しかし、プロダクションで使用する準備ができていると思われる場合は、遠慮なく提案してください。

4

2 に答える 2

3

pyxファイルは、C関数とPython関数を一致させることができるという意味でPythonファイルとは異なり、C(cdefまたはcpdef)関数で実行できることにはいくつかの制約があります。1つは、実行時にCコードを動的に生成することはできません。これは、コードが実行しようとしていることです。funは実際には引数の型チェック後にPythonコードを実行しているだけなので、通常のPython関数にすることもできます。

def fun(P, x, y):
    parse_args(P, x, y)
    getattr(my_c_library, name)(&D)
    return y

parse_args同じ引数チェックを行うので、何も失うことはありません。(ただし、'dでgetattrあるCライブラリで機能するかどうかはわかりません。同様に機能する可能性があります。)cimportimport

に関してはctypedef、それはおそらくCythonのいくつかの制限/バグであり、まだ誰も修正に取り掛かっていません。

于 2013-03-05T16:16:34.150 に答える
0

もう少し遊んだ後、次のように動作するように見えます。

def _fun_factory(fun_wrap):
    def fun(P, x, y):
        parse_args(P, x, y)
        fun_wrap()
        return y
    return fun

def _fun1(): my_c_library.fun1(&D)
def _fun2(): my_c_library.fun2(&D)
# ... many more ...

fun1 = _fun_factory(_fun1)
fun2 = _fun_factory(_fun2)
# ... many more...

そのため、 のような式で Python 操作を使用する可能性はないようmy_c_library.fun1(&D)です。ファクトリは、Python ラッパーの最初のセットが既に生成されている場合、2 番目のパスでのみ使用できます。これは、明らかなことよりもエレガントではありません。

cpdef fun1(ndarray[DTYPE_t] P, ndarray[DTYPE_t] x, ndarray[DTYPE_t] y):
    parse_args(P, x, y)
    my_c_function.fun1(&D)
    return y

# ... many more ...

こちら、cpdef問題なく使用できます。だから私はコピー&ペーストのアプローチに行きます... 将来、Cythonのプリプロセッサマクロにも興味がある人はいますか?

于 2013-03-05T18:12:11.837 に答える