【问题标题】:Cython package with __init__.pyx: Possible?带有 __init__.pyx 的 Cython 包:可能吗?
【发布时间】:2015-03-31 10:04:18
【问题描述】:

是否可以使用__init__.pyx(编译为__init__.so)创建Python 2.7 包?如果有怎么办?我没有任何运气让它工作。

这是我尝试过的:

  • setup.py:

    #!/usr/bin/env python
    
    from distutils.core import setup
    from distutils.extension import Extension
    from Cython.Distutils import build_ext
    
    foo = Extension(name='foo.__init__', sources=['foo/__init__.pyx'])
    bar = Extension(name='foo.bar', sources=['foo/bar.pyx'])
    
    setup(name='foo',
          packages = ['foo'],
          cmdclass={'build_ext':build_ext},
          ext_modules = [foo, bar])
    
  • foo/__init__.pyx:

    import foo.bar
    
    cpdef hello_world():
        print "hello world"
        foo.bar.blah()
    
  • foo/bar.pyx:

    cpdef blah():
        print "blah"
    

上面有以下行为:

$ python -c 'import foo; foo.hello_world()'
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named foo

我看到Python issue #15576 已被this Hg commit 修复。查看 Python Hg 存储库的 Git mirror 中的 equivalent Git commit,我发现可以从 Python v2.7.5 标记(以及所有后续的 v2.7.x 版本)访问提交。有回归吗?

【问题讨论】:

  • 只是出于好奇:你为什么要这样做?

标签: python python-2.7 cython python-import python-c-extension


【解决方案1】:

尝试使用相对导入。

在__init__:

from . import bar

也可能是from . import foo。好久没用过python 2 cython了。

【讨论】:

    【解决方案2】:

    根据this really old mailing list post,如果您还有一个__init__.py 文件(不使用__init__.py 文件,但似乎有必要将该目录视为一个模块,因此__init__.so要加载的文件)。

    如果我添加__init__.py:

    # an exception just to confirm that the .so file is loaded instead of the .py file
    raise ImportError("__init__.py loaded when __init__.so should have been loaded")
    

    那么您的示例适用于 Linux Python 2.7.3:

    $ python -c 'import foo; foo.hello_world()'
    hello world
    blah
    

    这有一个有问题的角落案例的所有迹象,所以可能不推荐。请注意,在 Windows 上,这对我来说似乎不起作用

    ImportError: DLL load failed: %1 is not a valid Win32 application.
    

    附录(补充一点上下文):

    这种行为似乎没有明确记录。在 Python 1.5 时代的the original description of packages 中,他们说:

    没有__init__.py,目录不会被识别为包

    和

    提示:搜索顺序由函数imp.get_suffixes()返回的后缀列表决定。通常按以下顺序搜索后缀:“.so”、“module.so”、“.py”、“.pyc”。目录没有显式出现在此列表中,但位于其中的所有条目之前。

    观察到的行为当然与此一致——__init__.py 需要将目录视为一个包,但 .so 文件优先于 .py 文件加载——但这很难明确。

    从 Cython 的角度来看,这种行为似乎被用于编译标准库(在这种情况下,__init__.py 将始终存在),或者在给定https://github.com/cython/cython/blob/master/tests/build/package_compilation.srctree 的测试用例中(以及其他一些示例) )。在这些文件中,“srctree”文件看起来被扩展为包含__init__.py(和其他文件)的各种文件夹,然后编译。有可能只有 __init__.so 从未经过测试。

    【讨论】:

    • 官方文档中提到过这个技巧吗? (显然不是在那个邮件列表线程的时候,但也许从那以后情况发生了变化)
    • 我不这么认为。 (我偶然发现了它,然后稍稍发现了新闻组帖子并意识到我做了什么。)如果我能找到更好的来源,我会稍微看看并更新我的答案。它似乎也适用于__init__.pyc 文件。
    • 改进建议:比起assert False,提高ImportError 可能会更好。或者也许有一些低级的东西可以使用 imp 模块作为后备,以防这个技巧在 Python 的未来版本中停止工作。
    • @RichardHansen 我已对其进行了更新以引发 ImportError(我同意 - 它显然更好!)并添加了指向我能找到的支持它的小文档的链接。我认为它基本上是无证的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-03-16
    • 1970-01-01
    • 2021-01-21
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 2021-12-14
    相关资源
    最近更新 更多