5

ハロー、

Pythonの参照カウントを理解するのに苦労しています。私がやりたいことは、ctypes モジュールを使用して c++ から python にタプルを返すことです。

C++:

PyObject* foo(...)
{

  ...
  return Py_BuildValue("(s, s)", value1, value2);
}

パイソン:

pointer = c_foo(...) # c_foo loaded with ctypes
obj = cast(pointer, py_object).value

obj の ref カウントがよくわからなかったので、試しsys.getrefcount() てみたところ3. そうあるべきだと思います2getrefcount関数は1つの参照自体を作成します)。

Py_DECREF()オブジェクトが削除されるため、C ++で戻る前に作成できなくなりました。Pythonで参照カウントを減らすことはできますか?

編集 キャスト関数が呼び出されると、ref カウントはどうなりますか? 以下のドキュメントからはよくわかりません。http://docs.python.org/library/ctypes.html#ctypes.cast

ctypes.cast(obj, type) この関数は、C のキャスト演算子に似ています。obj と同じメモリ ブロックを指す type の新しいインスタンスを返します。type はポインター型でなければならず、obj はポインターとして解釈できるオブジェクトでなければなりません。

4

2 に答える 2

5

さらに調査したところ、関数の戻り値の型を指定できることがわかりました。 http://docs.python.org/library/ctypes.html#callback-functions これにより、キャストが廃止され、参照カウントはもはや問題になりません。

clib = ctypes.cdll.LoadLibrary('some.so')
c_foo = clib.c_foo
c_foo.restype = ctypes.py_object

追加の回答がなかったので、新しいソリューションを回答として受け入れます。

于 2010-10-17T18:26:24.887 に答える
4

あなたの c++ コードは、公式の C-APIを使用する古典的なラッパーのようです。ctypes は通常、python で古典的な c 型 (int、float など) を使用するために使用されるため、少し奇妙です。

私は個人的に C-API を「単独で」(ctypes なしで) 使用していますが、私の個人的な経験では、この場合は参照カウンターについて心配する必要はありませんPy_BuildValue。関数がオブジェクトを返す場合、返されたオブジェクトの所有権は呼び出し元の関数に与えられます。

オブジェクトの所有権を変更したい場合にのみ、/ について心配する必要があります (NULL ポインターを受け入れるためPy_XINCREF、/よりPy_XDECREFも優れています)。Py_INCREFPy_DECREF

たとえば、Python でマップのラッパーを作成したとします (型付きオブジェクト py_map を呼び出しましょう)。要素は c++ クラス Foo のものであり、それらのために別の python ラッパーを作成しました (py_Foo と呼びましょう)。[] 演算子をラップする関数を作成すると、 python で py_Foo オブジェクトが返されます。

F = py_Map["key"]

ただし、所有権は呼び出し元の関数に与えられるため、削除するFとデストラクタが呼び出され、c++ のマップには割り当て解除されたオブジェクトへのポインタが含まれます。

解決策は、 [] のラッパーに c++ で記述することです。

...
PyObject* result; // My py_Foo object
Py_XINCREF(result); // transfer the ownership
return result;
}

Pythonでの借用参照と所有参照の概念を確認する必要があります。これは、参照カウンターを正しく理解するために不可欠です。

于 2010-10-14T09:08:15.297 に答える