Python自定义库toolbox嵌套导入问题:pip安装后导入失败
问题描述
我正在创建名为toolbox的Python自定义库,期望实现from toolbox.printing import warn的导入方式。当前项目架构如下:
repo |--toolbox |----__init__.py |----printing |------__init__.py |------utils.py |--demo.py |--setup.py
toolbox/printing/utils.py代码为:
def warn(text: str): print(str)
本地运行demo.py(代码为from toolbox.printing import warn; warn("This is a warning"))时,通过在toolbox/__init__.py中写入from .printing import warn,toolbox/printing/__init__.py中写入from .utils import warn,可以正常执行。但在其他项目中通过pip install git+myRepo.git安装该库后,导入操作出现ModuleNotFoundError、循环导入等错误。我的setup.py代码如下:
import setuptools with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() setuptools.setup( name='toolbox', version='0.0.1', author='MyName', author_email='myEmail', description='Usefull functions for my personnal use', long_description=long_description, long_description_content_type="text/markdown", url='myRepo', project_urls = { "Bug Tracker": "myRepo" }, license='MIT', packages=['toolbox'], install_requires=['requests', 'boto3', 'configparser'], )
现请求解答:
- 应如何配置各个
__init__.py文件以解决该问题? - 该问题的本质是什么?是否是模块与库的差异导致的?
解决方案
1. 各文件的正确配置
首先修正setup.py
当前packages=['toolbox']只会打包toolbox根目录的文件,不会包含printing子模块,这是安装后找不到子模块的核心原因,改成自动发现所有子包:
import setuptools with open("README.md", "r", encoding="utf-8") as fh: long_description = fh.read() setuptools.setup( name='toolbox', version='0.0.1', author='MyName', author_email='myEmail', description='Usefull functions for my personnal use', long_description=long_description, long_description_content_type="text/markdown", url='myRepo', project_urls = { "Bug Tracker": "myRepo" }, license='MIT', # 替换原packages配置,自动发现所有子包 packages=setuptools.find_packages(), install_requires=['requests', 'boto3', 'configparser'], )
配置__init__.py文件
toolbox/__init__.py:如果不需要从toolbox根目录直接导出warn,可以留空;如果需要支持from toolbox import warn,则写入以下代码(不会导致循环导入):# 可选:需要从toolbox根目录导入warn时保留,否则留空 from .printing import warntoolbox/printing/__init__.py:从utils导入warn并向外导出,确保外部可以通过toolbox.printing.warn访问:from .utils import warn
修正utils.py的代码错误
原代码中print(str)会打印类型对象而非输入文本,改成:
def warn(text: str): print(text)
2. 问题本质分析
这个问题核心不是模块与库的差异,而是打包配置错误+本地与安装后运行环境的差异导致:
- 本地运行时,Python会从当前项目根目录加载
toolbox模块,此时printing子目录作为toolbox的子模块能被自动发现,所以即使setup.py配置错误,本地也能正常运行; - 当通过
pip安装时,原setup.py的packages=['toolbox']只打包了toolbox根目录文件,没有包含printing子模块,导致安装后的库中不存在toolbox.printing,直接触发ModuleNotFoundError; - 所谓的“循环导入”大概率是后续错误修复时引入的,只要打包配置正确,原始的
__init__.py导入逻辑不会产生循环导入问题。
内容的提问来源于stack exchange,提问作者Jechos
相关产品推荐
相关产品推荐

