pyjexl
模块:
import pyjexl
jexl = pyjexl.JEXL()
jexl.add_transform("lowercase", lambda x: str(x).lower())
我想使用 Python C API 做同样的事情。像这样的东西:
Py_Initialize();
PyObject* pyjexlModule = PyImport_ImportModule("pyjexl");
PyObject* jexl = PyObject_CallMethod(pyjexlModule, "JEXL", NULL);
const char* myLambda = "lambda x: str(x).lower()";
PyObject* lambda = ... /* something using myLambda */
PyObject_CallMethod(jexl, "add_transform", "sO", "lowercase", lambda);
(简化版代码,例如
NULL
检查和Py_XDECREF()
已被省略)
我要解决的问题是如何获得表示 lambda 函数的
PyObject
,该函数的 Python 代码包含在 C 字符串myLambda
中。
我怎样才能实现这个目标?
我已经尝试使用@DavidW 的建议:
PyObject* globals = PyDict_New();
PyObject* locals = PyDict_New();
PyObject* lambda = PyRun_String(myLambda, Py_eval_input, globals, locals);
但我认为它不起作用,因为生成的
lambda
变量(使用调试器检查)的类型为 PyNone
:
PyRun_String
:
PyObject *lambda = PyRun_String(lambda, Py_eval_input, some_dict, some_dict);
其中
some_dict
可以是一个空字典。 (我认为在某些较旧版本的 Python 上,您需要在字典中包含 str
,因此可能需要使用 PyEval_GetBuiltins
,但现在应该没有必要了)。
我测试的确切功能是
PyObject *makeLambda() {
const char* myLambda = "lambda x: str(x).lower()";
PyObject* globals = PyDict_New();
PyObject* locals = PyDict_New();
PyObject* lambda = PyRun_String(myLambda, Py_eval_input, globals, locals);
return lambda;
}
请注意,我省略了
PyDict_New()
的错误处理 - 理想情况下,在每一个之后都应该有一个 NULL 检查。
为了测试它,我将其构建到 Cython 模块中 - 这只是因为它提供了一种编译和调用 C 函数的简单方法,因此这是一种快速测试它的方法:
cdef extern from *:
"""
PyObject *makeLambda() {
const char* myLambda = "lambda x: str(x).lower()";
PyObject* globals = PyDict_New();
PyObject* locals = PyDict_New();
PyObject* lambda = PyRun_String(myLambda, Py_eval_input, globals, locals);
return lambda;
}
"""
object makeLambda()
def callMakeLambda():
return makeLambda()
Cython 模块是用
cythonize -if modulename.pyx
编译的
然后您可以使用
进行测试>>> import modulename
>>> modulename.callMakeLambda()
第二行返回
<function <lambda> at 0x7f72c0d8bc40>
(当然 lambda 的确切地址会有所不同)。