Подтвердить что ты не робот

ImportError: динамический модуль не определяет функцию init (initfizzbuzz)

Я попытался скомпилировать fizzbuzz.c для импорта из python. Для построения fizzbuzz.c я использовал python setup.py build_ext -i.

После его создания я попытался импортировать fizzbuzz.c, но произошла ошибка. Как я могу решить эту проблему?

Ошибка

>>> 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],
)
4b9b3361

Ответ 1

Python не поддерживает и не может поддерживать произвольные файлы C в качестве модулей. Вам нужно будет следовать определенным соглашениям, чтобы Python знал, какие функции поддерживает ваш модуль.

Для этого Python будет искать функцию init<name>, где <name> - имя модуля. Python искал initfizzbuzz, но не смог найти его, поэтому загрузка модуля не удалась.

Помимо инициализатора, вам также необходимо предоставить структуру, подробно описывающую, какие функции доступны, и вашей функции нужно будет обрабатывать типы Python в качестве аргументов. Python предоставляет вам необходимые функции утилиты и определяет, чтобы сделать это достаточно легко.

Я настоятельно рекомендую вам следовать Расширению и встраиванию учебника по интерпретации Python. Он учит вам все, что вам нужно знать, чтобы ваш код fizzbuzz C работал как модуль Python.

Ответ 2

Ошибка также возникает при использовании boost:: python, если имя модуля отличается от скомпилированного имени файла .so. Например:

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

команда компиляции:

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

При включении в python с import libfoo возникает следующая ошибка:

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

Это из-за "libhello" и "libfoo" не совпадают.

Ответ 3

Worth notify - такая же ошибка может возникнуть, если библиотека скомпилирована для разных версий python. Например, если общий объект для python 3, но вы пытаетесь импортировать модуль из python 2.

Ответ 4

Вы должны определить функцию с именем init_fizzbuzz, которая должна содержать код для инициализации модуля. Эта функция также должна вызвать Py_InitModule, чтобы установить привязки для c-функций в Python. Для получения дополнительной информации просмотрите этот учебник.

В любом случае ваш код должен быть адаптирован к следующему:

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

}

Ответ 5

Если вы используете python 3, вам необходимо внести следующие изменения в свой код:

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

Ответ 6

сделать python3./yourpythonscript

вместо

python./yourpythonscript

даже если у вас есть python aliased как python3

Имя должно быть точным, с которым вы компилируете boost и boost-python: brew переустановить boost --with-python3 --without-python brew переустановить boost-python --with-python3 --without-python