Python 如何判断当前代码是作为脚本运行还是被 import?

12次阅读

__name__ == “__main__”是唯一可靠方式,因python语言层面保证其值在直接执行时为”__main__”、导入时为模块名,不依赖外部参数或环境变量

Python 如何判断当前代码是作为脚本运行还是被 import?

为什么 __name__ == "__main__" 是唯一可靠方式

Python 没有内置的“运行模式”变量,__name__ 的值是解释器在加载模块时自动设置的:被直接执行时为 "__main__",被 import 时为模块文件名(不含 .py)。这是语言层面保证的行为,不依赖进程参数、文件路径或环境变量,所以其他方法(比如检查 sys.argv[0] 或当前工作目录)都可能在特定场景下失效——例如通过 python -m module_name 运行时,__name__ 仍是 "__main__",但 sys.argv[0]"-m"

if __name__ == "__main__": 的典型用法和常见误写

这个判断必须出现在模块顶层(不能缩进),且只能用于控制“是否执行某段逻辑”,不能用来改变模块导出内容(如动态删函数或改 __all__)。

  • ✅ 正确:启动测试、运行 CLI 入口、触发调试代码
  • ❌ 错误:if __name__ == "__main__": def helper(): ... —— 这会让函数只在运行时存在,被 import 后无法使用
  • ⚠️ 注意:不要写成 if __name__ is "__main__": —— 字符串比较必须用 ==is 依赖字符串驻留机制,在某些 Python 实现或优化级别下可能失败

python -m 执行时的行为差异

python -m mypackage.mymodule 运行时,模块仍被视为脚本入口,__name__"__main__",但 __file__ 可能是 None(尤其对 zip 包里的模块),且 sys.path[0] 是空字符串而非文件所在目录。这意味着:

  • 依赖 __file__ 计算相对路径的代码会报 TypeError
  • 想兼容 -m 方式,应改用 pathlib.Path(__file__).resolve().parent 前加 if __file__: 判断
  • if __name__ == "__main__": 本身不受影响,照常生效

测试时如何模拟 import 场景

单元测试中常需要验证模块被 import 后的状态(比如全局变量是否初始化、函数是否可调用),而不是运行其 if __name__ == "__main__" 块。这时不能直接 import mymodule,因为模块一旦导入,__name__ 就固定了,重复 import 不会重新执行顶层代码。

立即学习Python免费学习笔记(深入)”;

  • ✅ 推荐:用 importlib.util.spec_from_file_location + importlib.util.module_from_spec 动态加载,绕过缓存
  • ✅ 简单场景:在测试前清空 sys.modules 中对应模块名(如 del sys.modules["mymodule"]),再 import
  • ⚠️ 注意:不要在测试里写 __name__ = "mymodule" —— 这只是改了局部变量,不影响解释器实际行为

实际项目里最容易忽略的是 -m 场景下的 __file__None,以及测试时没清理 sys.modules 导致判断逻辑被缓存掩盖。

text=ZqhQzanResources