如何从 C 字符串中的 Python 代码创建 lambda PyObject?

问题描述 投票:0回答:1

我在Python中有以下代码,它使用

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
:

python python-c-api
1个回答
0
投票

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 的确切地址会有所不同)。

© www.soinside.com 2019 - 2024. All rights reserved.