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],
)
Ответы
Ответ 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