45

I tried to compile fizzbuzz.c, in order to import it by python. For building fizzbuzz.c,I used python setup.py build_ext -i.

After building it, I tried to import fizzbuzz.c but the error below occurred. How can I solve this problem ?

Error

>>> import fizzbuzz
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ImportError: dynamic module does not define init function (initfizzbuzz)

fizzbuzz.c

#include <stdio.h>

void fizzbuzz(int n){

    for (int i=1; i <= n; i++){
        if (i % 3 == 0 && i % 5 ==0){
            printf("fizzbuzz %d \n", i);
        }
        else if (i % 3 == 0){
            printf("fizz %d \n", i);
        }
        else if(i % 5 == 0){
            printf("buzz %d \n", i);
        }
    }
}

setup.py

from distutils.core import setup, Extension
module = Extension('fizzbuzz', ['fizzbuzz.c'])
setup(
      name='fizzbuzz',
      version='1.0',
      ext_modules=[module],
)
Hari
  • 1,561
  • 4
  • 17
  • 26
SamuraiT
  • 992
  • 3
  • 12
  • 31
  • 4
    That's nowhere near a suitable Python extension module. – Martijn Pieters Jun 15 '14 at 02:18
  • 1
    I suggest you first read the [C-API tutorial](https://docs.python.org/2/extending/extending.html). – Martijn Pieters Jun 15 '14 at 02:20
  • 8
    For posterity, if you have two files `fizzbuzz.so` and a (properly written ctypes wrapper) `fizzbuzz.py` in the same directory, and you try to `import fizzbuzz`, Python seems to prefer the `.so`, which also produces this error message. – Cuadue Sep 23 '15 at 20:30
  • Porting C extensions from python 2 to 3: https://docs.python.org/3/howto/cporting.html – benjimin Jun 14 '19 at 00:13

6 Answers6

70

The error also occurs, when using boost::python, if the module name is different to the compiled .so file name. For example:

hello.cpp

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace std;
using namespace boost::python;

int helloWorld(){
    cout << "Hello world!" << endl;
    return 0;
}

BOOST_PYTHON_MODULE(libhello) {
    def("hello_world", helloWorld);
}

compilation command:

g++ -fpic -shared -o libfoo.so -Wl,-soname,"libfoo.so" hello.cpp -I<path/to/python> -L/usr/local/lib  -lboost_python-py34

When including in python with import libfoo the following error occurs:

ImportError: dynamic module does not define init function (PyInit_libfoo)

This is because of "libhello" and "libfoo" do not match.

philosopher
  • 871
  • 1
  • 7
  • 16
37

Worth notify - same error can occur if library is compiled for different python version. For example, if shared object is for python 3, but you try to import module from python 2.

Ivan Klass
  • 6,407
  • 3
  • 30
  • 28
  • 9
    `initfizzbuzz` is the python2 naming scheme, python3 needs `PyInit_libfizzbuzz`. So if you know your library is built for python3 and you get the error msg. in in the original question, probably some python2 interpreter got into the way. That's what happened to me with a conda env. with python 3.6 and a system python2.7 when building documentation for my module with sphinx. – Fred Schoen Jul 07 '17 at 11:06
  • That was my case too. I have compiled the python wrapper using python3.6 and was trying to import my lib using python2.7. Thank you for this comment! – Carlos Ost Mar 06 '19 at 13:17
25

Python doesn't and cannot support arbitrary C files as modules. You'll have to follow certain conventions to let Python know what functions your module supports.

To do so, Python will look for a init<name> function, where <name> is the module name. Python was looking for initfizzbuzz but failed to find it, so loading the module failed.

Apart from an initialiser, you also need to provide a structure detailing what functions are available, and your function will need to handle Python types as arguments. Python provides you with the necessary utility functions and defines to make that easy enough.

I strongly urge you follow the Extending and Embedding the Python Interpreter tutorial. It teaches you everything you need to know to make your fizzbuzz C code work as a Python module.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
6

do python3 ./yourpythonscript

instead of

python ./yourpythonscript

even if you have python aliased as python3

The name must be exact with which you compile boost and boost-python: brew reinstall boost --with-python3 --without-python brew reinstall boost-python --with-python3 --without-python

Aditya Mittal
  • 1,681
  • 16
  • 12
5

You should define a function named init_fizzbuzz, that should contain the code to initialize the module. This function should also call Py_InitModule, to setup the bindings for the c functions in Python. For further info, check out this tutorial.

In yor case, your code should be adapted to something like this:

static PyObject* py_fizzbuzz(PyObject* self, PyObject* args)
{
    int value;
    if (!PyArg_ParseTuple(args, "i", &value))
        return NULL;
    for (int i=1; i <= n; i++){
        if (i % 3 == 0 && i % 5 ==0){
            printf("fizzbuzz %d \n", i);
            }
        else if (i % 3 == 0){
            printf("fizz %d \n", i);
            }
        else if(i % 5 == 0){
            printf("buzz %d \n", i);
            }
        }

    // Return value.
    return Py_BuildValue("i", 0);

}

// Mapping between python and c function names. 
static PyMethodDef fizzbuzzModule_methods[] = {
    {"fizzbuzz", py_fizzbuzz, METH_VARARGS},
    {NULL, NULL}
    };

// Module initialisation routine.
void init_fizzbuzz(void)
{
    // Init module.
    (void) Py_InitModule("fizzbuzz", fizzbuzzModule_methods);

}
metasequoia
  • 7,014
  • 5
  • 41
  • 54
lackadaisical
  • 1,628
  • 18
  • 21
  • −1`import _fizzbuzz`yields`dynamic module not initialised properly` when`initfizzbuzz`is corrected with`init_fizzbuzz`. – user2284570 Jul 31 '16 at 21:51
4

If you use python 3 then you need to have the following changes on your code,

static struct PyModuleDef fizzbuzzModuleDef =
{
    PyModuleDef_HEAD_INIT,
    "fizzbuzz", /* name of module */
    "",          /* module documentation, may be NULL */
    -1,          /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */
    fizzbuzzModule_methods
};

PyMODINIT_FUNC PyInit_exmod(void) {
    return PyModule_Create(&fizzbuzzModuleDef);
}
kar
  • 495
  • 1
  • 8
  • 19