【问题标题】:how to prepare cython submodules如何准备 cython 子模块
【发布时间】:2017-10-18 00:34:30
【问题描述】:

我有三个问题,但相关,我不知道如何很好地拆分它们。我找到了很多关于这些问题的信息,比如submodule extension、hierarchy、关于empty __init__.py file,以及如何cythonize multiple pyx files。但是当我一起尝试时,我无法让它们发挥作用。

我准备了一份small repo 一起思考已解决问题的代码示例。我什至检查了一些使用 cython 的 projects listed 的代码,但仍然不知道如何同时做三件事。

  • 空的 __init__.py 文件:

在一个项目中(所有文件都是 pyx(和 pxd ifneedbe)),__init__.pyx 包含所有他们,当有一个 __init__.py 文件时,然后导入它不会加载“.so”而是空的init。

  • cythonize 多个文件:

而不是准备一个包含模块所有元素的 __init__.py。喜欢:

cythonize(['factory.pyx', 'version.pyx'])

生成的“.so”导入引发异常:

>>> import barfoo
(...)
ImportError: dynamic module does not define init function (PyInit_barfoo)

如果需要在__init__.py中写一些东西,那就和上一个问题有关了。

  • 子模块:

事实上,这是主要问题。 singleton.pyx 将成为子模块的一部分,让我们说 utils 从模块中的其他元素中使用。

对于示例,在 setup.py 中添加了一个子模块(简称为 subm)作为另一个扩展。我放的早于主要的(不知道这是否真的有什么区别,我没看到)。

>>> import barfoo
>>> import barfoo.subm
(...)
ImportError: No module named 'barfoo.subm'

单独地,这些食谱有效,但我不能一起使用。当“py”和“pyx”文件混合在一起时,“__init__.py”似乎是必要的。这些示例解释了如何对多个文件进行 cythonize,但不包括导入的最后一个关键点。并且子模块没有完成关于如何从一个地方或另一个地方导入它们(在导入基本模块时导入子模块,或者在指定它们时可选导入)。

【问题讨论】:

  • 您能描述一下您的文件布局(编译前后)吗?我不是 100% 清楚这个问题,但我认为您正在尝试将多个 .pyx 文件编译为一个 .so 文件,但这是行不通的。每个 .pyx 文件都需要生成自己的 .so 文件

标签: cython


【解决方案1】:

昨晚看到你的问题,根据wiki做了一个简单的例子。但是这个问题很快就被删除了。

示例如下:https://github.com/justou/cython_package_demo

确保C编译器和python环境设置正确,运行编译pyx文件:

python setup.py build_ext --inplace

用法同python包:

from dvedit.filters import flip, inverse, reverse
flip.show()       # print: In flip call Core function
inverse.show()    # print: In inverse call Core function
reverse.show()    # print: In reverse call Core function

顺便说一句,不需要创建__init__.pyx,您可以在__init__.py 文件中进行ext_module 导入

【讨论】:

  • 昨天发帖后,我想自己再做一次迭代,试着写得更好。对不起,谢谢。
  • 差不多,我想我已经得到了一些东西。 inplace 将 so 文件留在了 dvedit 目录中,但在我的尝试中将它留在了下面(设置所在的位置)。
  • @srgblnch 我过去在 windows 下也遇到过同样的问题。更新setuptools,改目录,重启电脑,问题就消失了,不知道是不是bug,也不知道是什么原因,甚至现在都无法重现!我非常怀疑这是关于“路径”的问题。
  • 对于这个问题的评论,我想,我们已经得到了关于目录和 __init__.py 的关键。 import dvedit 指的是 python,但 import dvedit.core 指的是从 core.pyx 来的。
  • 作为后续,我正在尝试做类似的事情,除了我想创建一个包含 cdef 定义和 pxd 文件的子模块。现在我想在另一个使用这些 cdef 定义的模块中使用这个子模块。不幸的是,我没有这样做,并且似乎无法在没有 cpdef 的情况下访问它们。
【解决方案2】:

感谢oz1 和DavidW 的cmets,我得到了solution。是的,这三件事结合在一起。

  • 非常重要是setup.py中导入时的顺序。即使PEP8 也没有说导入应该按字母顺序排序,还有其他指导方针(如reddit's)会这样做,我通常会遵循:

当先导入cythonize再setup时,会导致调用cythonize(find_pyx())时,结果会是distutils.extension.Extension 对象列表。

from setuptools import setup, find_packages
from Cython.Build import cythonize

setuptools 必须在 cython 之前导入,然后 cythionize() 的结果将是 setuptools.extension 的列表。可以传递给 setup() 调用的扩展 对象。

  • 了解 __init__ 的含义的重要:

所有带有包含的 __init__.pyx 文件都已被删除,每个 .pxy 文件都会生成自己的 .so 二进制文件。

只要它们的目录包含 __init__.py 文件,主模块和子模块就会存在,就像纯 Python 代码一样。

在我链接的示例中,文件 barfoo/__init__.py 不是空的,因为我希望 import barfoo 提供对 version 等元素的访问() 或 Factory()。然后,这个 __init__.py 就像普通的纯 python 一样导入它们。

  • 对于子模块:

submodule 和它自己的 __init__.py 文件类似。在这个例子中,import barfoo 将执行一个 from .factory import Factory,它会调用 from barfoo.subm import Bar,然后是 subm 将可用。

但是如果子模块不是以这种辅助方式导入的,用户将可以通过像 import barfoo.subm 这样的调用来访问它。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-02-06
    • 2020-10-08
    • 1970-01-01
    • 1970-01-01
    • 2016-12-03
    • 2015-07-22
    • 2019-12-15
    • 2018-09-26
    相关资源
    最近更新 更多