如何检测当前代码是否被 import 而不是直接运行

最可靠的方式是检查 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 inspect

def 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 范畴了。