4

既に割り当てられて初期化されている構造体からのデータがいくつかあります。これらのオブジェクトの有効期間中にデータが解放されないことを保証できます。これを Cython の Python オブジェクトにラップするにはどうすればよいですか? 以下は機能しませが、私の意図を説明してくれることを願っています:

from libc.stdlib cimport malloc

ctypedef struct Point:
    int x
    int y

cdef class _MyWrapper:
    cdef Point* foo
    def __cinit__(self, Point* foo):
        self.foo = foo

def create_eternal_MyWrapper(int x, int y):
    cdef Point* p
    p = <Point*>malloc(sizeof(Point))
    p.x = x
    p.y = y
    return _MyWrapper(p)

これで cython を実行した場合の出力:

Error compiling Cython file:
------------------------------------------------------------
...
def create_eternal_MyWrapper(int x, int y):
    cdef Point* p
    p = <Point*>malloc(sizeof(Point))
    p.x = x
    p.y = y
    return _MyWrapper(p)
                      ^
------------------------------------------------------------

examplecy.pyx:17:23: Cannot convert 'Point *' to Python object
4

1 に答える 1

0

hereで説明したように、__init____cinit__メソッドの両方がPyObject_CallAPI 関数を使用し、PyObject 型付き引数のみを受け入れることができます。したがって、FAQでも提案されているように、グローバル ファクトリ メソッド内で C 属性を初期化する必要があります。

from libc.stdlib cimport malloc

ctypedef struct Point:
    int x
    int y

cdef class _MyWrapper:
    cdef Point* fooless
    def __init__(self, *args, **kwargs):
        raise TypeError("This class cannot be instantiated from Python")

cpdef _MyWrapper create_MyWrapper(int x, int y):
    cdef _MyWrapper w = _MyWrapper.__new__(_MyWrapper)

    cdef Point* p
    p = <Point*>malloc(sizeof(Point))
    p.x = x
    p.y = y

    w.foo = p

    # initialize all other fields explicitly
    # ...

    return w

もちろん、それ自体で専用の初期化メソッドを作成することも_MyWrapperできますが、クラスがインスタンス化された後にユーザーがそのようなメソッドを呼び出すのを忘れる可能性があるため、かなり安全ではないと思います。

PS: より簡単な解決策が存在するかどうかを確認できれば幸いです

于 2013-03-11T01:53:00.950 に答える