Setuptools可编辑模式在项目目录外无法正常工作的问题排查
可编辑模式下
pip install -e .导入包模块失败问题 项目结构
setuptools_test/ ├── pyproject.toml └── setuptools_test/ ├── __init__.py ├── base.py └── module/ ├── __init__.py └── base.py
配置与代码文件
pyproject.toml
[build-system] requires = ["setuptools"] build-backend = "setuptools.build_meta" [project] name = "setuptools_test" version = "0.0.1" dependencies = [ "requests", 'importlib-metadata; python_version>="3.11"', ]
setuptools_test/init.py
from .base import FirstClass
setuptools_test/base.py
class FirstClass: ...
setuptools_test/module/init.py
from .base import SecondClass
setuptools_test/module/base.py
from setuptools_test import FirstClass class SecondClass(FirstClass): ...
问题现象
在setuptools_test/目录执行python -m pip install -e .完成可编辑模式安装后,在项目目录外启动Python Shell执行from setuptools_test.module import SecondClass时,抛出以下错误:
>>> from setuptools_test.module import SecondClass Traceback (most recent call last): File "<stdin>", line 1, in <module> File ".../setuptools_test/setuptools_test/module/__init__.py", line 1, in <module> from .base import SecondClass File ".../setuptools_test/setuptools_test/module/base.py", line 1, in <module> from setuptools_test import FirstClass ImportError: cannot import name 'FirstClass' from 'setuptools_test' (unknown location)
非可编辑模式(pip install .)下安装则一切正常。
环境信息
- 系统:Ubuntu 22.04.4
- Python版本:3.11(apt安装)
- pip版本:25.2
python -m pip freeze --all输出:
autocommand==2.2.2 backports.tarfile==1.2.0 build==1.3.0 certifi==2025.8.3 charset-normalizer==3.4.3 idna==3.10 importlib_metadata==8.7.0 jaraco.context==6.0.1 jaraco.functools==4.3.0 jaraco.text==4.0.0 more-itertools==10.7.0 packaging==25.0 pip==22.0.2 platformdirs==4.4.0 pyproject_hooks==1.2.0 requests==2.32.5 setuptools==80.9.0 setuptools_test @ file:///.../setuptools_test urllib3==2.5.0 wheel==0.45.1 zipp==3.23.0
问题原因与解决办法
这是可编辑模式下循环导入触发的初始化顺序冲突:
当module/base.py用绝对导入from setuptools_test import FirstClass时,Python会尝试加载顶层setuptools_test包的__init__.py,但此时module/base.py本身正在被加载,导致顶层包的初始化流程还没完成,FirstClass还没被导入到顶层命名空间,从而抛出导入错误。非可编辑模式下正常是因为安装后包文件被复制到site-packages,Python导入机制会优先加载完整的包,不会出现这种初始化顺序问题。
推荐两种解决方式:
方式1:改用相对导入
修改setuptools_test/module/base.py的导入语句为相对导入,直接从上级模块导入:
from ..base import FirstClass class SecondClass(FirstClass): ...
方式2:延迟导入(适合必须用绝对导入的场景)
如果业务上必须使用绝对导入,可以延迟导入FirstClass,避免在模块加载阶段触发循环导入:
# 模块级延迟导入 def __getattr__(name): if name == "FirstClass": from setuptools_test import FirstClass return FirstClass raise AttributeError(f"module {__name__} has no attribute {name}") class SecondClass(__getattr__("FirstClass")): ...
或者在类的方法内部导入(比如__init__):
class SecondClass: def __init__(self, *args, **kwargs): from setuptools_test import FirstClass super().__init__(*args, **kwargs)
内容的提问来源于stack exchange,提问作者kouign amann
相关产品推荐
相关产品推荐

