7

私はPythonC拡張機能を使い始めたばかりで、Pythonから呼び出し可能なC関数が2つのPyObject*引数を取りPyObject*を返さなければならない理由に興味があります。次の「HelloWorld」拡張機能を作成しました。

#include <Python.h>

static PyObject *
hello_world(PyObject *self, PyObject *noargs)
{
   printf("Hello World\n");
   return Py_BuildValue("");
}


// Module functions table.

static PyMethodDef
module_functions[] = {
    { "hello_world", hello_world, METH_NOARGS, "hello world method" },
    { NULL }
};


// This function is called to initialize the module.
PyMODINIT_FUNC
inittesty2(void)
{
    Py_InitModule("testy2", module_functions);
}

(特にMETH_NOARGSで)次のhello_worldメソッドを使用できないのはなぜですか。

static void
hello_world()
{
   printf("Hello World\n");
}

4

3 に答える 3

10

さまざまなPyObjectポインタについて言うべきことがいくつかあります。

  1. 戻り型として必要なものは、例外処理メカニズムに使用されます。具体的には、関数がnullポインターを返す場合、Pythonインタープリターは例外をスローします。PyErr_..(これは、特定の例外を設定するために関数の1つを呼び出した後でのみ実行する必要があります。)

    これは、例外をスローしたくない場合は常に、実際のへのポインタを返す必要があることも意味しますPyObject関数が返すことになっているものが特にない場合は、単に返す(マクロを使用して参照カウントを正しく取得するPy_Noneのが最適)か、「true」(を使用)します。Py_RETURN_NONEPy_RETURN_TRUE

  2. 最初の引数は、PyObject *self関数の呼び出し元のオブジェクト、または関数が属するモジュールインスタンスを指します。定義するすべての関数は、クラスメソッドまたはモジュールメソッドのいずれかであることに注意してください。完全に独立した機能はありません。

  3. 2番目の引数PyObject *args、関数の引数(タプルまたは複数の引数のリストの場合があります)を指します。あなたは、引数をとらない関数はこれを必要としないはずだと指摘するのは正しいです—そして、私が知る限り、あなたは正しいです。定義する必要はありません。関数を次のように定義するだけです。

    static PyObject *PyMyClass_MyFunc(PyObject *self) {
      /* ..do something.. */
      Py_RETURN_TRUE;
    }
    

    定義するデータ型のにこれを入れるときに、これをキャストするPyCFunction必要がありますが、フラグPyMethodDefを使用する限り、キャストは安全であると思います。ただし、起こりうるリスクについては、以下のコメントに注意してください。METH_NOARGS

  4. 最後に、関数には実際には次のような3番目の引数があります。

    static PyObject *PyMyClass_Func(PyObject *self, PyObject *args, PyObject *kwds)
    {
      /*...*/
    }
    

    3番目の引数は、名前付きのオプションの引数に使用されます。この場合も、関数ポインタをにキャストPyCFunctionMETH_KEYWORDSする必要がありますが、メソッドテーブルで関数に正しいフラグ()を設定すれば、これも安全です。

于 2012-04-21T10:04:28.587 に答える
4

モジュールレベルの関数の最初の引数は、モジュールオブジェクトです。Cでクラスを定義する場合(同じPyMethodDef構造がメソッドに使用されます)、最初の引数はインスタンスです(selfPythonの場合と同様)。

を使用する場合METH_NOARGS、PythonはNULL2番目の引数として渡します。彼らはそれを1つの引数を持つ関数にキャストできましたが、それが必要だとは思わなかったと思います。

戻り値は簡単に説明できます。すべてのPython関数には戻り値があります。returnPythonで明示的に使用しない場合、関数はを返しNoneます。

もちろん、Cでは戻り値を明示する必要があるため、使用しない場合はNone自分で返す必要があります。Pythonはこのためのマクロを提供します:

Py_RETURN_NONE;

Noneまたは、自分でグローバルインスタンスにアクセスすることもできます。

Py_INCREF(Py_None);
return Py_None;

ただし、マクロの方が使いやすいです。

NULLreturnは同等である必要があるNoneと考えることができますがNULL、関数が例外を発生させたことを示すために使用されます。

于 2012-04-21T10:07:22.513 に答える
2

Python関数は、stdoutに出力するだけの些細な関数でさえ、C関数の単なるラッパーではありません。

最も単純なケースでは、Pythonのイントロスペクション機能について考えてみてください。Python関数は、クエリできる本格的なオブジェクトです。

>>> def hello():
...     print 'hello'
... 
>>> dir(hello)
['__call__', '__class__', '__closure__', '__code__', '__defaults__', '__delattr__', '__dict__', '__doc__', '__format__', '__get__', '__getattribute__', '__globals__', '__hash__', '__init__', '__module__', '__name__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'func_closure', 'func_code', 'func_defaults', 'func_dict', 'func_doc', 'func_globals', 'func_name']

もちろん、C関数をラップしたばかりの拡張機能を想像することもできます。SWIGをチェックしてください。これにより、Pythonを含む多くのスクリプト言語の拡張機能を記述できます。最小公分母になるため、のような関数をラップできますhello_worldが、もちろん、多くの電力も失われます。

于 2012-04-21T05:18:46.273 に答える