如何在单一位置维护Python包的__version__并规避依赖问题?
解决Python包版本单一源且不依赖第三方包的方案
以下是几种可行的解决方法,既能让__version__在__init__.py和setup.py中共享,又不会在安装前触发依赖项的导入:
方案1:独立的版本文件(推荐)
创建一个仅存放版本信息的独立文件,完全不依赖任何第三方包,让__init__.py和setup.py分别从这个文件导入版本。
- 创建版本文件:在
module_a目录下新建version.py:
__version__ = "1.0.0"
- 修改
__init__.py:先导入版本,再正常引入依赖模块:
from .version import __version__ # 这里正常导入依赖,不会影响setup.py的执行 from .bar import foo
- 修改
setup.py:直接导入版本文件的版本,无需加载整个包:
import os import sys # 将包目录添加到Python路径,确保能找到version.py sys.path.insert(0, os.path.abspath("module_a")) from version import __version__ setup( name="module_a", version=__version__, install_requires=["module_b"], # 其他包配置... )
这种方式的优势是逻辑清晰,版本维护完全独立,setup.py执行时不会触发任何依赖项的导入,彻底避免了依赖提前安装的问题。
方案2:使用__about__.py(规范式写法)
很多成熟项目(比如requests)会用__about__.py来集中存放版本、作者等元信息,本质和方案1一致,只是命名更符合社区规范:
- 创建
__about__.py:
__version__ = "1.0.0" __author__ = "Your Name" # 其他元信息可按需添加
- 修改
__init__.py:
from .__about__ import __version__ from .bar import foo
- 修改
setup.py:
import os import sys sys.path.insert(0, os.path.abspath("module_a")) from __about__ import __version__ setup( name="module_a", version=__version__, install_requires=["module_b"], # 其他配置... )
方案3:在setup.py中定义版本并同步到__init__.py
如果不想新增额外文件,可以在setup.py中定义版本,通过字符串替换自动更新__init__.py里的版本,保证单一源:
- 修改
setup.py:
import re VERSION = "1.0.0" # 自动同步版本到__init__.py with open("module_a/__init__.py", "r+", encoding="utf-8") as f: content = f.read() # 替换__version__的值 content = re.sub(r'__version__ = ".*?"', f'__version__ = "{VERSION}"', content) f.seek(0) f.write(content) f.truncate() setup( name="module_a", version=VERSION, install_requires=["module_b"], # 其他配置... )
- 修改
__init__.py:
__version__ = "1.0.0" # 此值会被setup.py自动更新,无需手动修改 from .bar import foo
这种方式无需额外文件,但要注意不要手动修改__init__.py里的版本,否则会被setup.py覆盖。
为什么不推荐用try-except?
你之前用try-except捕获导入异常的方式会隐藏真正的运行时错误——当用户正常使用包时,如果module_b安装失败或导入出错,异常会被静默处理,导致无法定位问题。上面的方案完全分离了版本读取和依赖导入,从根源上避免了这个问题。
内容的提问来源于stack exchange,提问作者Idan Miara
相关产品推荐
相关产品推荐

