ImportError:动态模块未定义初始化函数(initfizzbuzz)

45 投票
6 回答
86445 浏览
提问于 2025-04-18 09:49

我尝试编译 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],
)

6 个回答

5

你需要定义一个叫做 init_fizzbuzz 的函数,这个函数的作用是初始化这个模块。这个函数还应该调用 Py_InitModule,来设置 Python 中 C 函数的绑定。想了解更多信息,可以查看 这个教程

在你的情况下,你的代码应该调整成类似下面这样的形式:

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

}
6

用下面的方式来运行你的 Python 脚本:

do python3 ./yourpythonscript

而不是这样:

python ./yourpythonscript

即使你把 python 设置成了 python3 的别名也不行。

你在编译 boost 和 boost-python 时,名字必须完全一致:

brew reinstall boost --with-python3 --without-python

brew reinstall boost-python --with-python3 --without-python

38

值得注意的是,如果库是为不同的Python版本编译的,也可能会出现相同的错误。举个例子,如果共享对象是为Python 3编译的,但你却试图从Python 2中导入这个模块,就会出问题。

70

这个错误也会发生在使用 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" 这两个名字不匹配。

25

Python不支持随便的C文件作为模块。你需要遵循一些特定的规则,让Python知道你的模块支持哪些功能。

为了做到这一点,Python会寻找一个叫做init<name>的函数,其中<name>就是模块的名字。比如,Python在找initfizzbuzz,但没找到,所以加载模块失败了。

除了这个初始化函数,你还需要提供一个结构,说明有哪些可用的函数,并且你的函数需要能够处理Python的数据类型作为参数。Python提供了一些实用的函数和定义,让这件事变得相对简单。

我强烈建议你查看一下扩展和嵌入Python解释器的教程。这个教程会教你如何让你的fizzbuzz C代码作为Python模块正常工作。

撰写回答