1

I am trying to make a simple extension in C that should be able to extend python code . I found that code on https://github.com/munirhossain/py_c_extension

#include <Python.h>

// Function 1: A simple 'hello world' function
static PyObject* helloworld(PyObject* self, PyObject* args) 
{   
    printf("Hello Munir\n");
    Py_RETURN_NONE;
    return Py_None;
}

// Function 2: A C fibonacci implementation
// this is nothing special and looks exactly
// like a normal C version of fibonacci would look
int Cfib(int n)
{
    if (n < 2)
        return n;
    else
        return Cfib(n-1)+Cfib(n-2);
}
// Our Python binding to our C function
// This will take one and only one non-keyword argument
static PyObject* fib(PyObject* self, PyObject* args)
{
    // instantiate our `n` value
    int n;
    // if our `n` value 
    if(!PyArg_ParseTuple(args, "i", &n))
        return NULL;
    // return our computed fib number
    return Py_BuildValue("i", Cfib(n));
}

// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition 
static PyMethodDef myMethods[] = {
    { "helloworld", helloworld, METH_NOARGS, "Prints Hello Munir" },
    { "fib", fib, METH_VARARGS, "Computes Fibonacci" },
    { NULL, NULL, 0, NULL }
};

// Our Module Definition struct
static struct PyModuleDef myModule = {
    PyModuleDef_HEAD_INIT,
    "myModule",
    "Test Module",
    -1,
    myMethods
};

// Initializes our module using our above struct
PyMODINIT_FUNC PyInit_myModule(void)
{
    return PyModule_Create(&myModule);
}

I would like to modify that code like when I call the helloworld func , like helloworld("max") it returns Hello max in C , but idk how can I use PyObject* args :/ Any ideas how I can do that (in C) ?

1 Answer 1

1

You should read the PyArg_ParseTuple documentation. Basically this should work:

static PyObject* helloworld(PyObject* self, PyObject* args) 
{   
    const char *name;

    if (!PyArg_ParseTuple(args, "s", &name)) {
        return NULL;
    }

    printf("Hello %s\n", name);
    Py_RETURN_NONE;
}

and you need to change the method definition in the table to

{ "helloworld", helloworld, METH_VARARGS, "Prints Hello <name>" },

naturally, as it now takes arguments. The description s says that the argument tuple must contain exactly one item and it should be of type str; it is converted to UTF-8 (each CPython string object can contain a cached copy of the string content in UTF-8 for C use), and a pointer to the first character is stored into the pointer object pointed to by the corresponding argument in the variable argument list (i.e. the &name - the output value is const char *, and the corresponding argument must be a pointer to such an object, i.e. const char **).

If PyArg_ParseTuple returns a falsy value, it means the conversion failed and a Python exception has been set. We raise the exception on Python side by returning NULL instead of Py_None from the function.

Lastly,

return Py_None; 

is not correct - you must always increment the reference counter on any such value before returning it - that's what Py_RETURN_NONE macro does in it - it is functionally equivalent to

Py_INCREF(Py_None);
return Py_None;
Sign up to request clarification or add additional context in comments.

Comments

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.