You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用importlib导入setuptools安装的含下划线Python包

问题

用setuptools创建名称含下划线的Python包时,下划线会被自动替换为横杠(比如foo_bar变成foo-bar),但自动导入时遇到问题:pkg_resources.working_set返回的是带横杠的名称,用这个名称调用importlib.import_module()会报错ModuleNotFoundError,但手动用下划线版本import foo_bar可以正常工作。

包结构:

foo_bar
├─ foo_bar
|  ├─ __init__.py
|  ├─ foo_bar.py
└─ setup.py

执行开发安装命令:

python3 setup.py develop --user

pip3 list输出:

pip3 list | grep foo
foo-bar                      0.1                       /home/XYZ/foo_bar

自动导入报错代码及输出:

import pkg_resources
import importlib

for d in pkg_resources.working_set:
    if('foo' in d.project_name):
        print(d.location, d.project_name, d.version, d.key)
        libstr = d.key
        print('Importing lib',libstr)
        testlib = importlib.import_module(libstr)

输出:

/home/XYZ/foo_bar foo-bar 0.1 foo-bar
Importing lib foo-bar
Traceback (most recent call last):
  File "/home/XYZ/foo_bar/test/import_foo_bar.py", line 10, in <module>
    testlib = importlib.import_module(libstr)
  File "/usr/lib/python3.10/importlib/__init__.py", line 126, in import_module
    return _bootstrap._gcd_import(name[level:], package, level)
  File "<frozen importlib._bootstrap>", line 1050, in _gcd_import
  File "<frozen importlib._bootstrap>", line 1027, in _find_and_load
  File "<frozen importlib._bootstrap>", line 1004, in _find_and_load_unlocked
ModuleNotFoundError: No module named 'foo-bar'

手动导入正常:

In [1]: import foo_bar

In [2]: foo_bar.foo_bar
Out[2]: <module 'foo_bar.foo_bar' from '/home/XYZ/foo_bar/foo_bar/foo_bar.py'>
解决方案

方法1:从包元数据读取真实导入名

pkg_resources的Distribution对象可以获取包的top_level.txt内容,这个文件记录了可导入的顶级模块名(即下划线版本的名称)。修改代码如下:

import pkg_resources
import importlib

for d in pkg_resources.working_set:
    if 'foo' in d.project_name:
        print(d.location, d.project_name, d.version, d.key)
        # 获取顶级模块名
        top_levels = d.get_metadata('top_level.txt').strip().split('\n')
        for module_name in top_levels:
            if module_name:  # 跳过空行
                print('Importing lib', module_name)
                testlib = importlib.import_module(module_name)
                print(f'Successfully imported {module_name}')

方法2:手动转换横杠为下划线

如果确定包名的横杠都是由下划线转换而来,直接将d.key中的横杠替换为下划线即可:

import pkg_resources
import importlib

for d in pkg_resources.working_set:
    if 'foo' in d.project_name:
        print(d.location, d.project_name, d.version, d.key)
        libstr = d.key.replace('-', '_')
        print('Importing lib', libstr)
        testlib = importlib.import_module(libstr)

这种方法简单直接,但需确保包的导入名和项目名的转换规则一致。

方法3:在setup.py中明确指定packages参数

确保setup.py里的packages参数正确指向可导入的模块名,避免元数据生成错误:

from setuptools import setup, find_packages

setup(
    name="foo-bar",  # PyPI显示的项目名称
    version="0.1",
    packages=find_packages(),  # 自动发现foo_bar模块
    # 也可手动指定:packages=["foo_bar"],
)

配置后top_level.txt会正确生成foo_bar,后续通过元数据获取的导入名就是正确的。


内容的提问来源于stack exchange,提问作者pholter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 19:20:40