2012-04-21 8 views
7

Python Cの拡張機能を使い始めたばかりで、Pythonから呼び出し可能なC関数は2つのPyObject *引数PyObject *を返します。私は、次の "Hello World" の拡張子を書いた:Python C Extensions - 呼び出し可能なC関数が引数をとり、PyObjectを返す理由*

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

#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付き)I以下hello_worldメソッドを使用することはできませんか?

答えて

10

さまざまなPyObjectポインターについていくつかのことが言えます。

  1. 戻り型として必要な1は、例外処理機構に使用されます。具体的には、関数がヌルポインタを返した場合、Pythonインタプリタは例外をスローします。 (あなただけPyErr_..関数のいずれかを呼び出した後に特定の例外を設定することを行う必要があります。)これはまた、あなたが例外をスローしたくない時はいつでも、あなたはいくつかの実際のPyObjectへのポインタを返す必要があることを意味し

    あなたの関数が返すものが何もない場合は、Py_NonePy_RETURN_NONEマクロを使用して参照カウントを取得するのが最善)または "true"(Py_RETURN_TRUEを使用)を返すだけです。

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

  3. 引数(複数の引数のタプルまたはリストであってもよい)関数の引数にPyObject *argsポイント。引数をとらない関数は—を必要としないはずであると指摘するのは間違いありません。あなたはそれを定義する必要はありません。データは、ユーザーが定義するタイプのためにあなたがPyMethodDefにそれを置くとき、あなたは単にあなたがまだPyCFunctionキャストこれになります

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

    としての機能を定義することができますが、私はキャストがあなた限り安全であると信じていますMETH_NOARGSフラグを使用します。 ただし、考えられるリスクについては以下のコメントを参照してください。

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

    3番目の引数は名前ののために使用され、オプションの引数

  4. 最後に、関数は、実際にこのような第三引数を有することができます。この場合も、の関数ポインタをPyCFunctionにキャストする必要がありますが、メソッドテーブルの関数に正しいフラグ(METH_KEYWORDS)を設定しても安全です。

+0

Py_Noneで、PyNoneではありません。 'Py_RETURN_TRUE'や' Py_RETURN_FALSE'に似た 'Py_RETURN_NONE'もあります。 – yak

+0

私は間違っていれば私を修正しますが、コードがすべての引数がスタックに渡され、呼び出し先(関数)がそれらをスタックからポップする呼び出し規約を使用していた場合、未使用の引数を削除すると、クラッシュはPythonが常に2番目のargとしてNULLを渡し、関数がポップしないためです。 – yak

+0

@yak私のコードでクラッシュすることはありません。 – jogojapan

2

Pythonの機能は、単にstdoutに印刷するだけのものでも、Cの関数を包むラッパーではありません。

最も単純なケースでは、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関数をラップ拡張機能を想像することができます:Pythonの機能を使用すると、照会することができ、フル育てるオブジェクトです。 SWIGをチェックしてください。これにより、Pythonを含むたくさんのスクリプト言語のための書き込み拡張が可能になります。最小公約数になるので、hello_worldのような関数をラップすることができますが、もちろんあなたは多くの力を失います。

4

モジュールレベル関数の第1引数はモジュールオブジェクトです。 Cでクラスを定義するとき(そこではPyMethodDef構造体が使われます)、最初の引数はインスタンスです(Pythonではselfに似ています)。

METH_NOARGSを使用する場合、PythonはNULLを第2引数として渡します。 1つの引数で関数にキャストできますが、必要とは思わないと思います。

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

もちろん、Cでは戻り値を明示する必要があります。使用しない場合は、Noneを返さなければなりません。 Pythonは、このためのマクロが用意されています

Py_RETURN_NONE; 

また、あなたがグローバルNoneインスタンスを自分にアクセスできます。

Py_INCREF(Py_None); 
return Py_None; 

をしかし、マクロを使用する方が簡単です。

戻り値NULLNoneと等しくなりますが、NULLは関数が例外を発生させたことを示すために使用されます。

関連する問題