我们正在研究一些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:无的完美用法。但是在花了一个小时使用Python / C-API文档后,我无法弄清楚如何创建lambda。
我看到页面http://docs.python.org/2/c-api/function.html上有对闭包的引用,但我无法理清有关如何创建闭包的详细信息。
非常感谢任何指针(或对RTFM的引用)。
答案 0 :(得分:3)
lambda表达式用于创建简单的匿名函数。它们有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
的低级实现。
但是,如果您真的想要创建一个高级别lambda
,则可以使用dastrobu建议的单一语句来执行此操作
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