如何在Python模块中嵌套c-api扩展并在该模块中使用它们?

如何在Python模块中嵌套c-api扩展并在该模块中使用它们?,python,setuptools,python-c-api,python-c-extension,Python,Setuptools,Python C Api,Python C Extension,我想创建一个名为“mypack”的Python3包,它可以与pip一起安装。它有一些c扩展和一些调用这些扩展的python代码。以下是我的目录结构: setup.py mypack/__init__.py mypack/mypack.py foopkg/foo.cpp setup.py文件包含以下代码: from setuptools import setup, Extension PACKAGE_NAME = 'mypack' module = Extension('foo',

我想创建一个名为“mypack”的Python3包,它可以与pip一起安装。它有一些c扩展和一些调用这些扩展的python代码。以下是我的目录结构:

setup.py
mypack/__init__.py
mypack/mypack.py
foopkg/foo.cpp
setup.py文件包含以下代码:

from setuptools import setup, Extension

PACKAGE_NAME = 'mypack'

module = Extension('foo',
                language = "c++",
                sources = ['foopkg/foo.cpp'])

setup(name=PACKAGE_NAME,
      version='1.0',
      packages=[PACKAGE_NAME],
      ext_package=PACKAGE_NAME,
      ext_modules=[module],
      include_package_data=True)
我根据另一个相关问题改编了这段代码,用户希望像我一样使用
mypack.xxx
导入扩展。在c-api扩展中,我已经成功地编译了它,并使它作为一个独立的扩展模块工作,但是我在将它合并到一个更大的包中时遇到了困难。它定义了两个函数
make_array
print_array
。为了简洁起见,我删除了函数代码,只包含Python需要的东西:

...

static PyMethodDef FooMethods[] = {
    { "make_array", make_array, METH_VARARGS, "Put number in array"},
    { "print_array", print_array, METH_VARARGS, "Print number from array"},
    { NULL, NULL, 0, NULL}
};

static struct PyModuleDef foomodule = {
    PyModuleDef_HEAD_INIT,
    "foo",
    "Make/Print array",
    -1,
    FooMethods
};

PyMODINIT_FUNC PyInit_foo(void)
{
    return PyModule_Create(&foomodule);
}
我希望能够在包中导入此扩展以使用它(这是
mypack.py
):

最后,我的
\uuuu init\uuuu.py
文件包含来自.mypack import dostuff的


但是,当我使用pip安装并尝试运行导入
mypack
的测试脚本时,无论我使用的是
foo.xx
还是
mypack.xx
,它都会抱怨
mypack.py
中的导入。我构建了其他具有嵌套结构的包,这些包使用模块中其他python文件的代码,使用
\uuuu init\uuuu.py
并使用导入。但是对于如何使用c扩展实现这一点,我感到有点困惑。

模块是从c编译的,这一事实对于如何编写导入语句没有任何影响。那条线

import mypack.make_array
尝试导入在名为“mypack”的包中找到的名为“make_array”的模块。那不是你所拥有的。在名为“mypack”的包中有一个名为“foo”的模块,在该模块中有两个名为“make_array”和“print_array”的对象(方法)

如果您从
\uuuu init\uuuuuu.py
中删除所有内容并使其正常工作,那么就简单多了。如果希望改进import语句的语法,可以稍后将内容添加到init文件中。你想要

from mypack.foo import make_array, print_array

在第一种情况下,方法现在位于全局命名空间中;在第二种情况下,您可以通过
MYPACK.make_array
MYPACK.print_array
访问它们

此外,我还发现了命名C扩展名文件
mypack
和命名python文件
mypack.py
的问题。中只能有一个具有该名称的模块 包裹。一种解决方案是在C文件名前加下划线。然后在mypack.py中编写,例如

from ._mypack import make_array

这将
make_array
放入
myarray
的命名空间中,客户机代码不必知道或关心它是用C编写的。

模块是用C编译的,这一事实与您编写导入语句的方式没有任何区别。那条线

import mypack.make_array
尝试导入在名为“mypack”的包中找到的名为“make_array”的模块。那不是你所拥有的。在名为“mypack”的包中有一个名为“foo”的模块,在该模块中有两个名为“make_array”和“print_array”的对象(方法)

如果您从
\uuuu init\uuuuuu.py
中删除所有内容并使其正常工作,那么就简单多了。如果希望改进import语句的语法,可以稍后将内容添加到init文件中。你想要

from mypack.foo import make_array, print_array

在第一种情况下,方法现在位于全局命名空间中;在第二种情况下,您可以通过
MYPACK.make_array
MYPACK.print_array
访问它们

此外,我还发现了命名C扩展名文件
mypack
和命名python文件
mypack.py
的问题。中只能有一个具有该名称的模块 包裹。一种解决方案是在C文件名前加下划线。然后在mypack.py中编写,例如

from ._mypack import make_array

这将
make_array
放入
myarray
的名称空间中,客户机代码不必知道或关心它是用C编写的。

感谢对包和模块名称的澄清!我对你的建议不屑一顾。如果我错了,请纠正我的错误,但c-api代码似乎创建了模块
foo
,然后我将该模块归因于setup.py中的包
mypack
。因此,当我从mypack.foo导入make_数组时,可以在
mypack.py
中打印数组。但是,从mypack.mypack导入make\u array、print\u array执行
操作不起作用。现在我了解了命名的过程,我应该能够在我的主代码中解决这个问题。你可能想编辑你的答案,所以它使用mypack.foo中的
。我会编辑我的答案,但我还不太明白。编译foo.cpp后,将得到一个名为foo.pyd的文件。通常它与foo.cpp位于同一目录中。将其导入python程序时,其完整导入名称取决于文件在目录结构中的位置。编译后是否将文件复制或移动到mypack目录?或者你的安装文件就是这样做的?我不清楚你所说的“包mypack的属性”是什么意思。据我所知,唯一可行的方法是,如果物理文件位置和导入语句一致。好吧,是的,也许我弄错了。我对制作模块还是相当陌生的。好的,这很有趣,所以我检查了一下,pip install将
.pyc
初始化
文件放在
mypack
目录下,而不是
foopkg
foopkg
是cpp文件所在的位置。共享库文件也在
mypack
下。我做过很多扩展模块,但从未编写过pip安装脚本。不幸的是,我们有点超出了我的专业范围。但是也许你可以从这里开始,或者重新问一个更有针对性的问题。谢谢你对包和模块名称的澄清!我对你的建议不屑一顾。如果我错了,请纠正我,但c-api代码似乎创建了该模块<