Python中如何从egg文件中正确导入.so文件?

我写了一个包,用

python setup.py install

安装后会在site-package目录下得到一个.egg 的文件,然后可以在 python 中 import 这个包。 问题是,我在setup.py文件中包含了 package_data,是一个名为xxx.so的动态库文件,这个库文件在 install 之后也被正确包含进那个.egg 文件里了(把.egg 重命名成.zip 解压后可以确认)。 但是,如果只用这个.egg 文件,那么包里的一行代码

from . import xxx

就会报错

ImportError: cannot import name 'xxx'

奇怪的是,如果我重命名.zip 然后解压成文件夹,from . import xxx 就能正常加载那个动态库了。

请问熟悉 Python 的 V 友这种情况该如何解决?谢谢!


Python中如何从egg文件中正确导入.so文件?

5 回复

我后来在<a target="_blank" href="http://setup.py" rel="nofollow noopener">setup.py</a>中的setup()中加入了一条zip_safe=False来生成 folder 而不是 egg,解决了问题,但不知道有没有更优雅的解决方案?


在Python中从.egg文件导入.so文件,关键在于确保.so文件能被Python解释器找到。.egg文件本质上是zip压缩包,而.so文件是编译后的二进制扩展模块,Python无法直接从压缩包中加载它们。

核心解决方案:

你需要将.so文件从.egg文件中提取出来,放到Python的模块搜索路径(如site-packages目录)中,或者将包含.so文件的.egg文件路径添加到sys.path

具体操作步骤与代码示例:

  1. 检查.egg文件结构:首先,确认你的.egg文件里确实包含.so文件以及对应的__init__.py等文件。你可以将其重命名为.zip后缀后解压查看。

    import zipfile
    egg_path = 'your_package.egg'
    with zipfile.ZipFile(egg_path, 'r') as z:
        z.printdir() # 查看内部文件列表
        # 如果看到 .so 文件,例如 `package/_module.so`
    
  2. 方法一:安装.egg文件(推荐)
    使用easy_install(旧式)或pip直接安装.egg文件是最规范的方法。这会将文件解压到site-packages,.so文件会被放在正确位置。

    # 在终端中使用
    pip install your_package.egg
    # 或者
    easy_install your_package.egg
    

    安装后,即可正常导入:

    import your_package
    # 或者 from your_package import something
    
  3. 方法二:动态添加到sys.path(用于临时测试)
    如果你不想安装,可以将.egg文件路径加入sys.path,Python会将其视为一个目录来查找模块。但这通常对纯.so文件无效,因为.so需要被提取。一个变通方法是模拟安装过程:

    import sys
    import zipfile
    import tempfile
    import os
    from pathlib import Path
    
    egg_path = Path('your_package.egg')
    # 创建临时目录,模拟site-packages环境
    with tempfile.TemporaryDirectory() as tmpdir:
        # 解压.egg文件到临时目录
        with zipfile.ZipFile(egg_path, 'r') as z:
            z.extractall(tmpdir)
        # 通常解压后,包目录就在临时文件夹下
        # 假设包名为 'mypackage'
        package_path = Path(tmpdir) / 'mypackage'
        # 将这个路径加入sys.path,Python就能找到里面的.so了
        sys.path.insert(0, str(package_path.parent))
        # 现在可以尝试导入
        import mypackage
        print(mypackage.__file__)
    

    注意:这种方法在临时目录生命周期内有效,退出程序后失效,且可能遇到路径问题。

根本建议: 优先使用pip install来安装.egg文件。

import sys
import os
sys.path.append(os.path.abspath(‘xxx.egg’)) ?

用 zipimport 引用这 so

谢谢两位!不过如果通过 pip 安装,是默认生成 folder 的,并且 path 会有所变化,所以似乎 path.append 和 zipimport 都不能同时适用两种安装方式?

回到顶部