最可靠的方式是检查 name == "__main__",因为Python解释器在直接执行脚本时将其设为"__main__",而import时设为模块全名,该行为由解释器底层保证,语义明确且语言级支持。

Python 中判断模块是被 import 还是直接执行
最可靠的方式是检查 __name__ 变量是否等于 "__main__"。这是 Python 解释器在启动时自动设置的标识,无需额外依赖或环境判断。
为什么只靠 __name__ == "__main__" 就够了
Python 在直接运行一个脚本文件时,会把该文件的 __name__ 设为 "__main__";而当它被 import 时,__name__ 是模块的完整路径名(如 "utils.helper")。这个行为由解释器底层保证,不受 IDE、打包工具(如 PyInstaller)或调试器干扰。
- 即使你用
python -m mypackage.mymodule运行,__name__仍是"__main__"(但__package__会被设为"mypackage") - 在 Jupyter 或 IPython 中,
__name__通常是"__main__",但这属于交互式环境特例,不属于“被 import”的场景,无需特殊处理 - 不要用
sys.argv[0]或检查调用栈——它们不可靠,且在嵌入式 Python 环境中可能不存在
常见误用和边界情况
有人试图通过检测 __file__ 是否存在、或判断当前路径是否含 "site-packages" 来推断导入行为,这完全错误。例如:
# ❌ 错误示例:混淆了“来源路径”和“执行方式”
if "site-packages" in __file__:
print("被 import 了") # 实际上,直接运行 wheel 安装的脚本,__file__ 也可能在 site-packages 里
-
__name__是唯一语义明确、语言级支持的判断依据 - 如果模块里定义了
if __name__ == "__main__":块,里面的内容只会在直接运行时执行,import 时不会触发 - 注意:某些测试框架(如 pytest)会 import 模块来收集测试,此时
__name__ != "__main__",符合预期
需要动态检测的场景怎么写
如果你在函数内部需要知道“此刻所在的模块是否为主模块”,不能直接用 __name__(因为那是函数定义处的模块名),而应获取调用栈顶层模块的 __name__:
import inspectdef is_called_from_main(): frame = inspect.currentframe() try: while frame.f_back: frame = frame.f_back return frame.f_globals.get("name") == "main" finally: del frame # 避免循环引用
不过绝大多数情况下没必要这么复杂——真正需要区分 import/直接运行的逻辑,本来就该放在模块顶层的 if __name__ == "__main__": 块里。
最易被忽略的一点:这个判断只对 Python 模块有效;如果你用 Cython 编译成 .so/.pyd,或打包进可执行文件,只要入口仍是 Python 解释器启动,__name__ 行为不变。但若用 C 主程序嵌入 Python,则取决于你怎么设置 PySys_SetArgv 和初始化逻辑——那已经超出标准 Python 范畴了。










