28

次のようにCでPy_Noneを返す前にPy_INCREF(Py_None)が必要なのはなぜですか?

Py_INCREF(Py_None);
return Py_None;

Py_INCREF(Py_None)を省略すると、どうなりますか?

4

2 に答える 2

27

aが欠落しているPy_INCREFと、の参照が誤ってカウントされPy_None、インタプリタがの割り当てを解除する可能性がありますPy_None。ファイルPy_Noneに静的に割り当てられるため、次のようになります。Objects/object.c

PyObject _Py_NoneStruct = {
  _PyObject_EXTRA_INIT
  1, &PyNone_Type
};

そしてInclude/object.h、定義があります:

#define Py_None (&_Py_NoneStruct)

したがって、何が起こるかというと、インタープリターが致命的なエラーでクラッシュするということです。

Fatal Python error: deallocating None

none_deallocこれは、次の関数によって生成されObjects/object.cます。

/* ARGUSED */
static void
none_dealloc(PyObject* ignore)
{
    /* This should never get called, but we also don't want to SEGV if
     * we accidentally decref None out of existence.
     */
    Py_FatalError("deallocating None");
}

そのコメントで述べられているようにNoneType、独自の割り当て解除機能がない場合はfree、スタックで呼び出しが行われるため、セグメンテーション違反が発生します。

チュートリアルの例をコピーしてこれをテストし、関数にPy_DECREF(Py_None)への呼び出しを追加しNoddy_name、拡張機能を構築して、そのメソッドを呼び出すループを実行できます。


一般的なケースでは、の参照カウントにより0、プログラムがさまざまな方法で失敗する可能性があります。

特に、Pythonは、割り当てが解除されたオブジェクトによって使用されたメモリを自由に再利用できます。つまり、オブジェクトへのすべての参照が突然ランダムオブジェクト(または空のメモリ位置)への参照になる可能性があり、次のようなものを見ることができます。 :

>>> None   #or whatever object that was deallocated
<ARandomObjectYouNeverSawBefore object at ...>

(これは、C拡張機能を作成するときに、実際に時々発生しました。への呼び出しが欠落しているために、ランダムな時間に読み取り専用バッファーに変わるオブジェクトもありますPy_INCREF)。

他の状況では、さまざまな種類のエラーが発生したり、インタプリタがクラッシュしたり、セグメンテーション違反が発生したりする可能性があります。

于 2013-03-08T06:38:58.470 に答える
25

Py_Noneメソッドがない場合を除いて、実際には単なる別のPythonオブジェクトです。

Pythonは、任意のへの参照をカウントしますPyObject*。文字列、整数、またはなしのいずれであるかは関係ありません。

参照カウントをインクリメントしない場合、Pythonインタープリターは、0オブジェクトへのポインターがないと考えて、参照カウントがヒットした後、最終的にオブジェクトを破棄します。これは、次に戻り値を使用して何かを行おうとすると、保持が保証されていないメモリ内の場所Py_None(エラー、奇妙な値、セグメンテーション違反など)へのポインタをたどることになることを意味します。

使用することを忘れないようにする代わりの方法がありますPy_INCREF(Py_None)

return Py_BuildValue("");

また

Py_RETURN_NONE;
于 2013-03-08T06:48:12.917 に答える