Python setuptools:导入时执行函数但脚本运行时不执行?
我来帮你搞定这个问题,分单文件和包结构两种场景详细说明解决方案:
单文件 pysome.py 的实现方案
你之前踩的坑是:通过console_scripts调用时,模块的__name__是pysome而非__main__,导致if __name__ != '__main__'的判断会误触发some_fun()。我们可以通过检查sys.argv[0]的名称来区分「用户主动导入」和「控制台命令运行」两种场景:
# pysome.py import sys import os def some_fun(): print("执行了 some_fun(模块导入场景)") def main(): print("执行了 main(控制台运行场景)") # 核心判断:仅当模块被主动导入(不是直接运行脚本,也不是控制台命令调用)时执行 some_fun if __name__ != '__main__' and not sys.argv[0].endswith(('pysome', 'pysome.exe')): some_fun()
对应的setup.py配置保持不变:
# setup.py from setuptools import setup setup( name="pysome", version="0.1", py_modules=["pysome"], entry_points={ 'console_scripts': [ 'pysome=pysome:main' ] } )
原理说明
- 当用户执行
import pysome时,sys.argv[0]是用户脚本的名称(比如test.py),不满足后缀判断,条件成立,执行some_fun()。 - 当用户在控制台运行
pysome时,sys.argv[0]是console_scripts生成的脚本名称(Windows下是pysome.exe,Linux/macOS下是pysome),条件不成立,不会执行some_fun()。 - 当用户直接运行
python pysome.py时,__name__是__main__,条件也不成立,符合预期。
包结构的实现方案
你的包结构中,__init__.py的代码会在任何导入包内模块的场景下执行(包括__main__.py导入子模块时)。我们可以用环境变量标记来区分控制台运行和正常导入:
1. 调整包内文件内容
pysome/__init__.py:添加环境变量判断,仅在非控制台模式下执行some_fun()
# pysome/__init__.py import os from .pysome import * # 仅当没有控制台标记时,执行 some_fun if not os.environ.get('PYSOME_CONSOLE'): some_fun()
pysome/__main__.py:先设置控制台标记,再导入子模块
# pysome/__main__.py import os # 设置环境变量,标记当前是控制台运行模式 os.environ['PYSOME_CONSOLE'] = '1' from .pysome import main # 控制台入口函数 def main(): print("执行了 main(控制台运行场景)")
pysome/pysome.py:保持你的业务逻辑
# pysome/pysome.py def some_fun(): print("执行了 some_fun(模块导入场景)")
2. 调整 setup.py 配置
确保entry_points指向__main__.py的main函数:
# setup.py from setuptools import setup, find_packages setup( name="pysome", version="0.1", packages=find_packages(), entry_points={ 'console_scripts': [ 'pysome=pysome.__main__:main' ] } )
原理说明
- 当用户执行
import pysome时,没有设置PYSOME_CONSOLE环境变量,__init__.py里的条件成立,执行some_fun()。 - 当用户在控制台运行
pysome时,__main__.py先设置环境变量,再导入子模块,此时__init__.py执行时会检测到环境变量,跳过some_fun()的执行。
内容的提问来源于stack exchange,提问作者Roland Puntaier
相关产品推荐
相关产品推荐

