According https://realpython.com/build-python-c-extension-module/
To write Python modules in C, you’ll need to use the Python API, which defines the various functions, macros, and variables that allow the Python interpreter to call your C code. All of these tools and more are collectively bundled in the <Python.h>
header file.
This post follows up Creating Basic Python C Extensions - Tutorial and does just one update required in static PyMethodDef myMethods[] still having "METH_NOARGS" instead of "METH_VARARGS",
what, actually, confuses inexperienced learners, due to Python module runtime failure with error "fib( ) expecting no arguments , but get (1)". As of now the only version available to follow :-
static PyMethodDef myMethods[] = {
{ "fib",fib, METH_NOARGS, "Prints Hello World" },
{ NULL, NULL, 0, NULL }
};
Should be
static PyMethodDef myMethods[] = {
{ "fib",fib,METH_VARARGS, "Fibonacci" },
{ NULL, NULL, 0, NULL }
};
Following below is working code follows up the link above, but making "code sample" easy to reproduce. Notice also that outside VENV you would have problems to run `python setup install`
(.env) [boris@fedora33server FIBONACHI]$ cat test.c
#include <Python.h>
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
int result = Cfib(n);
return Py_BuildValue("i",result);
}
// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
{ "fib", fib, METH_VARARGS, "Calculate fibonacii value" },
{ 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);
}
(.env) [boris@fedora33server FIBONACHI]$ cat setup.py
from distutils.core import setup, Extension
setup(name = 'myModule', version = '1.0', \
ext_modules = [Extension('myModule', ['test.c'])])
(.env) [boris@fedora33server FIBONACHI]$ python3 setup.py install
(.env) [boris@fedora33server FIBONACHI]$ cat MyProg.py
import myModule
a = int(input("Input number:"))
print(myModule.fib(a))
(.env) [boris@fedora33server FIBONACHI]$ python MyProg.py
Input number:11
89
PyCharm Project setup
Another Sample Factorial Recursion
(.env) [boris@fedora33server FACTORIAL]$ cat test.c
#include <Python.h>
long factorial(int n)
{
if (n == 0)
return 1;
else
return(n * factorial(n-1));
}
static PyObject *Factors(PyObject* self, PyObject* args)
{
int n;
if(!PyArg_ParseTuple(args, "i", &n))
return NULL;
int result = factorial(n);
return Py_BuildValue("i",result);
}
// Our Module's Function Definition struct
// We require this `NULL` to signal the end of our method
// definition
static PyMethodDef myMethods[] = {
{ "Factors", Factors, METH_VARARGS, "Tracking factorial" },
{ 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);
}
(.env) [boris@fedora33server FACTORIAL]$ cat setup.py
from distutils.core import setup, Extension
setup(name = 'myModule', version = '1.0', \
ext_modules = [Extension('myModule', ['test.c'])])
(.env) [boris@fedora33server FACTORIAL]$ python setup.py install
running install
running build
running build_ext
building 'myModule' extension
creating build
creating build/temp.linux-x86_64-3.9
gcc -pthread -Wno-unused-result -Wsign-compare -DDYNAMIC_ANNOTATIONS_ENABLED=1 -DNDEBUG -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -O2 -fexceptions -g -grecord-gcc-switches -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -Wp,-D_GLIBCXX_ASSERTIONS -fstack-protector-strong -m64 -mtune=generic -fasynchronous-unwind-tables -fstack-clash-protection -fcf-protection -D_GNU_SOURCE -fPIC -fwrapv -fPIC -I/home/boris/FACTORIAL/.env/include -I/usr/include/python3.9 -c test.c -o build/temp.linux-x86_64-3.9/test.o
creating build/lib.linux-x86_64-3.9
gcc -pthread -shared -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g -Wl,-z,relro -Wl,--as-needed -Wl,-z,now -g build/temp.linux-x86_64-3.9/test.o -L/usr/lib64 -o build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so
running install_lib
copying build/lib.linux-x86_64-3.9/myModule.cpython-39-x86_64-linux-gnu.so -> /home/boris/FACTORIAL/.env/lib64/python3.9/site-packages
running install_egg_info
Removing /home/boris/FACTORIAL/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info
Writing /home/boris/FACTORIAL/.env/lib64/python3.9/site-packages/myModule-1.0-py3.9.egg-info
(.env) [boris@fedora33server FACTORIAL]$ cat MyModule.py
import myModule
a = int(input("Input number:"))
print(myModule.Factors(a))
(.env) [boris@fedora33server FACTORIAL]$ python MyModule.py
Input number:7
5040
(.env) [boris@fedora33server FACTORIAL]$ python MyModule.py
Input number:6
720
(.env) [boris@fedora33server FACTORIAL]$ python MyModule.py
Input number:5
120
**************************************************************
You might want to take a look at following more complicated sample then considered earlier
**************************************************************
No comments:
Post a Comment