⚙️ 第八章 从源文件到可执行文件
📄 一句话概括

main 不是入口——在它之前还有启动代码:备好栈、传好参数、初始化运行环境;结束后也由它收尾。

📝 本节和前面几节的关系

8.4 拼出了完整链条,这一节补上链条最前面那一小段。

一、main 不是第一个跑的

一个常见的误会是【程序从 main 开始跑】。 其实在 main 之前,还有一段启动代码要先执行。 它的活儿不难理解,但一件都不能少——少了任何一件,你的 main 就跑不起来。 所以严格地说:main 是被调用的,不是被启动的。

二、启动代码做三件事

备好环境——把栈准备好,把全局数据初始化好。 传好参数——把命令行参数整理成 main 能接着的形式。 调用并收尾——调 main,等它返回,然后刷新输出、把退出码报给系统。 换句话说:跟系统打交道的那部分活儿,全被它包了。

三、Python 里的同一个套路

Python 没有 main 函数,但有一个一模一样的机制:__name__。 被别的文件 import 时,__name__ 是模块名;被直接运行时,它变成 __main__。 所以那句最常见的写法:if __name__ == "__main__": 它的意思就是:只有当我是被直接跑的那个文件时,才执行下面这段。 原理和 C 的启动代码一样:入口由环境决定,不由你决定。

四、为什么要有这一段

因为它把【跟环境有关的那部分琐事】集中到了一处。 如果每个程序都要自己准备栈、自己接收参数、那写程序的人会被这些杂事淹没。 把它们抽出来放进启动代码,你的代码就只管业务逻辑。 这种【把和平台打交道的事抽到一边】的做法,贯穿整本书——从驱动到虚拟机,都是同一个思路。

五、动手 Demo:启动代码与库文件

一个常见的误会是【程序从 main 开始跑】。 其实在它之前还有一段启动代码要先跑。

import sys, os
print("被 import 进来时   math.__name__ = math")
print("被直接运行时       __name__ 会变成 __main__")
print("命令行第一个参数  ", os.path.basename(sys.argv[0]))
# if __name__ == "__main__":
#     只有被直接运行时才走这里

实跑输出:

--------------------------------------------------------------------
启动代码与库文件
--------------------------------------------------------------------

一个常见的误会是【程序从 main 开始跑】。
**其实 main 不是入口**——在它之前还有一段**启动代码**要先跑。

  顺序     谁在跑       做什么
  -------------------------------------------------------------
  先       启动代码     准备好栈、把参数收拢好、初始化运行环境
  再       启动代码     调 main,把控制权交给你的代码
  后       main         执行你写的那部分逻辑
  最后     启动代码     收尾:刷新输出、返回退出码

  Python 里也有同一个套路——**模块先被执行,其中 `__name__` 决定它自己是谁:**

    被 import 进来时   math.__name__ = math
    被直接运行时       __name__ 会变成 __main__
    命令行第一个参数   _demos_27.py

  所以那句最常见的写法:

    if __name__ == "__main__":

  **它的意思就是【只有当我是被直接跑的那个文件时,才执行下面这段】。**
  被别的文件 import 时,`__name__` 变成模块名,那段就不执行了。
  **道理和 C 语言的启动代码一样:入口那件事由环境决定,不由你决定。**

入口由环境决定,不由你决定:开机的第一段代码永远是启动代码。 Python 里用 __name__ 判断,C 语言里则由启动代码来调 main。

30 秒实验

  1. 把一段代码写进 if name == "main" 里,分别用直接运行和 import 两种方式试。
  2. 想一想:如果启动代码不准备栈,函数调用会发生什么。

常见误区

  1. 以为 main 是第一个执行的。启动代码在它之前。
  2. 以为 name 只是个小技巧。它就是【我是不是入口】这个判断本身。
自测三问(点开对答案) 1. main 之前还有谁在跑? —— 启动代码——准备栈与全局数据、整理参数,然后才调用 main。 2. 启动代码在 main 返回后还做什么? —— 收尾:刷新输出、把退出码报给操作系统。 3. Python 里对应的机制是什么? —— __name__:被直接运行时是 __main__,被 import 时是模块名。

相关笔记