2016-06-23 3 views
10

私は、Cythonを使ってPython用のCライブラリ用の高水準インタフェースを作成しています。
私はより複雑なCコンテキスト構造体へのポインタでライブラリを初期化するタイプAを持っていますc_context。ポインタはAに保存されます。
Adef関数を持ちます。これは、別のC構造体をライブラリ関数呼び出しで初期化するタイプBを作成します。この構造体は、Bで作成されたそれ以降のライブラリ呼び出しに必要です。
BBから__cinit__にそれを渡すために、拡張タイプpy_context内私によって包まれAからc_contextポインタ必要があります:正しいCのコンテキストでラッパーを渡すCythonを使ってC Structの周りに完全なPythonラッパーを書くには?

#lib.pxd (C library definitions) 
cdef extern from "lib.h": 
    ctypedef struct c_context: 
     pass 

#file py_context.pxd 
from lib cimport c_context 

cdef class py_context: 
    cdef c_context *context 
    cdef create(cls, c_context *context) 
    cdef c_context* get(self) 

#file py_context.pyx 
def class py_context: 
    @staticmethod 
    cdef create(cls, c_context *c): 
     cls = py_nfc_context() 
     cls.context = c 
     return cls 

    cdef c_context* get(self): 
     return self.context 

を完璧に動作します。

今度は、py_contextからC構造体を再度取得し、Bに保存する必要があります。私はcdef c_context get(self)py_context.pxd/pyxを加えました。 アメニティー__cinit__結果からpy_context.get()を呼び出す:Cythonでcdef関数を呼び出すときに私は周りに私の頭を取得しないように思えAttributeError: py_context object has no attribute get.

私の質問は:ラッパークラスからC構造体を再度抽出する最良の方法は何ですか?

+0

これはお使いになりましたか? http://docs.cython.org/src/tutorial/clibraries.html – chrisb

答えて

6

問題は、Cythonはコンパイル時に変数py_contextのデータ型を知らないということです。 cdef関数の呼び出しはコンパイル時に解決され、(通常のPython関数のように)属性参照によって実行時にそれを把握する仕組みが存在しません。

[Cython以内に書かれdef機能がまだコンパイルされ、データ型を指定することができますので、彼らは正しい情報を持っている場合cdef関数を呼び出す完全に可能であることに注意してください。]

あなたは、関連するコード場所を与えていませんそれは、(タイプBのコンストラクタ)間違っているが、ここでうまくいけば、あなたにそれを修正するにはいくつかの方法を与える非常に単純化した例ですです:

cdef class A: 
    cdef f(self): 
     return 

def f1(var): 
    var.f() 

#f1(A()) # will fail at runtime with an attribute error 

f1varのタイプが不明であるため、次のことができますcdef関数に呼び出します。

def f2(A var): 
    var.f() 

f2(A()) # will work 
f2(1) # will fail, int can't be converted to A 

f2varのタイプは、Aに制限され、したがって、それは喜んAに関連付けられcdef関数を呼び出すことができます。 Aでないものを渡すと、実行時にTypeErrorが返されます。

def f3(var): 
    cdef A another_reference_to_var = var # this does test that the types match 
    another_reference_to_var.f() 

f3(A()) # will work 
f3(1) # will fail, int can't be converted to A 

機能f3は任意のタイプの変数を取ります。ただし、another_reference_to_varに割り当てた場合、cdefAになります。タイプが一致するかどうかがチェックされます(一致しない場合は実行時例外が発生します)。コンパイル時にanother_reference_to_varAであることがわかっているので、Acdef関数を呼び出すことができます。

本質的には、__cinit__関数に関連する入力のタイプを指定する必要があります。

+2

+1これはより良い回答ですので、少し誤解を招いていたので速やかに削除しました。 [Here](https://github.com/cythonbook/examples/tree/master/07-wrapping-c/02-wrap-c-structs-mt-random)は、次のような構造体をラップする完全な例のURLです。彼が必要かどうかを知るためのOP。 –

+0

魅力的な作品です。 Bs '__cinit__'の欠落している型情報が問題でした。 'py_context'を追加することで問題が解決されます。 あなたの情報はCythonのドキュメントに追加する必要があります。なぜならそれらは時には少し曖昧ですからです。 –

関連する問題