1

I have the following code in Python, which uses pyjexl module:

import pyjexl

jexl = pyjexl.JEXL()
jexl.add_transform("lowercase", lambda x: str(x).lower())

I want to do the same using Python C API. Something like this:

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);

(Simplified version of the code, e.g., NULL checking and Py_XDECREF() have been omitted)

The problem I'm trying to solve is how to get a PyObject representing a lambda function which Python code is contained in the C-string myLambda.

How can I achieve this?

I have tried with the suggestion by @DavidW using this:

PyObject* globals = PyDict_New();
PyObject* locals = PyDict_New();
PyObject* lambda = PyRun_String(myLambda, Py_eval_input, globals, locals);

But I think it's not working, as the resulting lambda variable (inspected using debugger) is of type PyNone:

Debugger screenshot

1 Answer 1

1

PyRun_String:

PyObject *lambda = PyRun_String(lambda, Py_eval_input, some_dict, some_dict);

where some_dict can be an empty dict. (I think on some older versions of Python you'd need to have str in the dict, so might need to use PyEval_GetBuiltins but this should be unnecessary now).


The exact function I tested with was

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;
    }

Note that I've omitted error handling for PyDict_New() - ideally there should be a NULL check after each of these.

In order to test it I built it into a Cython module - that's just because it provides an easy way to compile and call C functions so it's a quick way to test it:

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()

The Cython module is compiled with cythonize -if modulename.pyx

You can then test it with

>>> import modulename
>>> modulename.callMakeLambda()

The second line returns <function <lambda> at 0x7f72c0d8bc40> (the exact address of the lambda will vary of course).

Sign up to request clarification or add additional context in comments.

4 Comments

Thanks you for your feedback! I'm testing with your suggestions but it seems it not working... Please have a look to the EDIT section in the question post
Don't know. I just tested it now and it works for me. So I don't have any other suggestions
Can you provide the full code, please? In order to try to identify differences with my case... Thanks!
I've edited the answer to include the full code I used to test it

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.