Skip to content

__name__ 与程序入口 ​

同一个 Python 文件既可能被其他文件导入,也可能作为脚本直接运行。两种启动方式都会执行模块的顶层代码,但程序通常需要区分它们:被导入时只提供功能,直接运行时才启动测试或业务流程。

如何判断当前文件的启动方式,并把只应执行一次的代码放在正确位置?Python 通过模块的特殊变量 __name__ 提供判断依据。

案例:区分模块导入与直接运行 ​

需求: 让 tools.py 既能被 main.py 导入,也能单独运行并执行简单测试,同时观察两种启动方式下 __name__ 的值。

功能分析: 先在工具模块中定义可复用函数,再用入口判断包裹测试代码;随后分别直接运行工具模块和运行入口文件,对比输出结果。

创建下面两个文件:

text
01-direct-and-imported/
├── main.py
└── tools.py

在 tools.py 中编写:

python
print(f"tools.py 中的 __name__:{__name__}")


def add_numbers(left, right):
    return left + right


if __name__ == "__main__":
    print("正在直接运行 tools.py")
    print(add_numbers(10, 20))

直接运行 tools.py:

shell
python3 tools.py

运行结果:

text
tools.py 中的 __name__:__main__
正在直接运行 tools.py
30

当一个文件作为程序入口直接运行时,它的 __name__ 等于字符串 "__main__"。

直接运行与导入模块的区别

接着在 main.py 中导入 tools:

python
import tools

print(f"main.py 中的 __name__:{__name__}")
print(tools.add_numbers(1, 2))

运行入口文件:

shell
python3 main.py

运行结果:

text
tools.py 中的 __name__:tools
main.py 中的 __name__:__main__
3

这次 tools.py 是被导入的模块,所以其中的 __name__ 是模块名 "tools";直接运行的 main.py 仍然是程序入口,因此它的 __name__ 是 "__main__"。

入口判断机制 ​

案例中的 if __name__ == "__main__": 用来区分文件是被直接运行,还是作为模块被导入。

下面这段结构通常称为入口判断:

python
if __name__ == "__main__":
    print("只在直接运行当前文件时执行")

它的执行规则是:

当前文件的使用方式__name__ 的值判断内的代码
直接运行"__main__"执行
被其他模块导入模块名不执行

需要注意,入口判断只会保护缩进在判断内部的代码。tools.py 顶层的下面这行代码仍然会在导入时执行:

python
print(f"tools.py 中的 __name__:{__name__}")

如果某段代码在导入时不应该运行,就要把它放进函数或入口判断中。

程序入口组织 ​

当入口文件包含多步业务流程时,可以把流程集中到 main(),再由入口判断负责启动。

入口文件可以把主要流程放进 main() 函数,再通过入口判断启动:

python
import tools


def main():
    print(f"main.py 中的 __name__:{__name__}")
    result = tools.add_numbers(1, 2)
    print(f"计算结果:{result}")


if __name__ == "__main__":
    main()

这种结构把“定义程序流程”和“启动程序”分开。以后其他模块即使导入 main.py,也不会自动执行 main() 中的完整流程。

main 函数与入口判断

入口判断不是语法规定的强制写法。对于只有几行代码、也不会被导入的小脚本,可以直接顺序执行;当文件既可能独立运行,又可能被其他模块复用时,再使用入口判断更合适。

模块内快速测试 ​

功能模块如何保留可复用函数,同时提供一个不影响导入过程的快速检查入口?可以把少量测试代码放进入口判断。

功能模块也可以利用入口判断保留简单测试:

python
def add_numbers(left, right):
    return left + right


if __name__ == "__main__":
    print(add_numbers(10, 20))

直接运行这个文件时可以快速检查函数结果;其他文件导入 add_numbers 时,测试代码不会执行。

这种方式适合学习阶段和少量临时检查。项目中的系统化测试通常会放在独立测试文件中,不需要把大量测试逻辑堆进功能模块。

小结 ​

  • 文件直接运行时,__name__ 的值是 "__main__"。
  • 文件被导入时,__name__ 通常是它的模块名或带包路径的模块名。
  • if __name__ == "__main__": 可以区分直接运行和被导入两种情况。
  • 入口判断只保护缩进在其中的代码,其他顶层语句仍会在导入时执行。
  • 可以使用 main() 函数集中组织程序流程,再通过入口判断启动。

练习 ​

  1. 直接运行 tools.py,再通过 main.py 导入它,记录两次 __name__ 的值。
  2. 在入口判断内部和外部分别添加输出语句,观察导入模块时哪些语句会执行。
  3. 为上一章的学生系统增加 main() 函数,并使用入口判断启动程序。
  4. 在一个功能模块中编写简单测试,确认测试代码不会在模块被导入时运行。