5

私たちはいくつかの Python/C-API コードに取り組んでおり、コールバックを渡されたいメソッドに遭遇しました。このメソッドは、定期的な更新をフィードバックとしてコールバックに送信します。結局のところ、私たちは定期的なフィードバックにはあまり関心がありません。メソッドのデフォルトのフィードバック メカニズムを無効にする唯一の方法は、何らかのコールバックを渡すことです。

私たちが採用した手法は、None を返すだけのモジュール レベル関数を宣言することです。つまり、次のようになります。

static PyObject*
donothing(PyObject* self, PyObject* args) {
    return Py_None;
    }

しかしもちろん、この関数もモジュールのメソッド テーブルに登録する必要があります。

static PyMethodDef methods[] = {
    {"donothing", donothing, METH_VARARGS, "do nothing"},
     ...
    {NULL}
    };

次に、メソッドを呼び出すときに、このメソッドへの参照を取得する必要があります。つまり、次のようになります。PyObject_GetAttrString(module_reference, "donothing").

これらすべては、私たちが何もしないために車輪を回転させるのにあまりにも多くの時間を費やしているように感じます. それから、それは私に起こりました..ちょっと、 lambda x: Noneの完璧な使い方のようです。しかし、Python/C-API ドキュメントに 1 時間費やした後、ラムダを作成する方法がわかりません。

ページhttp://docs.python.org/2/c-api/function.htmlにクロージャーへの参照があることがわかりますが、それらを作成する方法の詳細を整理することはできません。

ポインタ (または RTFM への参照) は大歓迎です。

4

1 に答える 1

4

ラムダ式は、単純な無名関数を作成するために使用されます。これらには、実行可能コードのチャンクであるPyFunction_Typeのオブジェクトがラップされています。PyCode_Typeしかし、あなたはすでに C 側にいるので、Python 関数を作成するのは少しやりすぎです。代わりに、 のオブジェクトを作成する必要がありますPyCFunction_Type。これは、モジュール メソッドでやろうとしたことと似ています。

C のボイラープレートもそれほど大きくはありませんが、ほんの数行です。

static PyObject *
donothing(PyObject *self, PyObject *args) {
    Py_RETURN_NONE;
}
static PyMethodDef donothing_ml = {"donothing", donothing, METH_VARARGS, "doc"};

次に、PyCFunction_New(&donothing_ml, NULL)を生成するオブジェクトが作成され<built-in function donothing>ます。この関数はモジュールとは独立しており、他の と同様に使用できますPyObject

厳密には高レベルlambdaではなく、低レベルの実装ですlambda *args: None


ただし、本当に高レベルを作成したい場合は、提案されたdastrobulambdaのような単一のステートメントでこれを行うことができます

l = PyRun_String("lambda *args: None", Py_eval_input, PyEval_GetGlobals(), NULL);

または、自分で組み立てたい場合は、

PyCodeObject *c = (PyCodeObject *) Py_CompileString("None", "fn", Py_eval_input);
#if PY_MAJOR_VERSION >= 3
c->co_name = PyUnicode_FromString("<c-lambda>"); // function name
#else
c->co_name = PyString_FromString("<c-lambda>"); // function name
#endif
c->co_flags |= CO_VARARGS; // accept *args
c->co_nlocals = 1; // needed in Python 3
l = PyFunction_New((PyObject *) c, PyEval_GetGlobals());

どちらの場合も、逆アセンブルされたコードdis(l)と同等の関数が得られlambdaます。

  1           0 LOAD_CONST               0 (None)
              3 RETURN_VALUE        
于 2015-08-01T16:30:28.480 に答える