if __name__ == '__main__'
这个东西,所有见过python代码的程序猿们一定都不会陌生。为方便理解,有人直接把它等同于java中的主函数。我们今天不是为了来探讨它和Java主函数的异同的(因为我已经忘了Java主函数的细节了,也懒得再回顾…),我们今天就谈一下将代码定义在if __name__ == '__main__'
前或者后,到底有什么区别
背景介绍
首先,还是介绍下我为什么又想起这个“python初学者”的问题了。背景是这样的:我有个python脚本,在其中起了一个Flask服务,同时在里面还定义了处理中断信号(SIGINT
)的语句,具体你可以认为是这样的:
from flask import Flask
import signal
from b import signal_handler # 导入b.py中定义的signal_handler函数。至于signal_handler里干了啥,其实就是close了一个数据库连接对象app = Flask(__name__)# Flask路由和其他逻辑...if __name__ == "__main__":# 注册信号处理函数signal.signal(signal.SIGINT, signal_handler) # 处理 Ctrl+Csignal.signal(signal.SIGTERM, signal_handler) # 处理 kill 命令app.run()
如上所示,这段代码极简单,就是起了个Flask服务,然后在使用Ctrl+C或Kill命令干掉该进程时,先执行signal_handler()函数里面定义的事情(就是关闭了一堆数据库连接)
那么问题来了,signal.signal(signal.SIGINT, signal_handler)
这段code,应该定义在if __name__ == "__main__"
之前还是之后呢?
问题分析
要想明白这个问题,我们只需搞清if __name__ == "__main__"
是干嘛的。
在Python中,if __name__ == "__main__"
块确定了代码块是直接作为脚本执行,还是被导入到另一个模块中。当模块被直接执行时,__name__
变量被设置为"__main__"
;当模块被导入时,它通常被设置为模块的名称,也就是说,当脚本被作为模块import时,if __name__ == "__main__"
后面的代码不会运行
对于signal.signal(...)
的调用,它的位置(在if __name__ == "__main__"
之前还是之后)会影响信号处理函数注册的时机和上下文:
- 如果
signal.signal(...)
在if __name__ == "__main__"
之前定义:- 这意味着无论模块是被直接执行还是被导入,信号处理函数都会被注册。这可能不是你想要的行为,因为如果a.py被另一个脚本导入,你可能不希望它改变全局的信号处理设置。
- 如果
signal.signal(...)
在if __name__ == "__main__"
之后定义:- 这意味着只有当当前作为主脚本直接运行时,信号处理函数才会被注册。这通常是更安全和更可控的做法,因为它避免了意外地改变导入此模块的其他脚本的信号处理行为。
问题解决
所以说,我们前面的定义位置是正确的。因为只有当直接运行该脚本时,才会执行到app.run()
,才会运行Flask服务、才需要在接受到Kill信号时进行处理、才需要让signal.signal(...)
定义生效。所以,signal.signal(...)
和app.run()
可以说是同时存在的,那么这两行代码就应该一起放在if __name__ == '__main__'
之后
emmm,有时候没遇到一定的场景,确实很难切身体会到一些相对少见用法的意义。比如 __name__
的取值,这个相信所有写python的朋友在初学时都看到过对它的解释,但真正在用到它的时候,才会让你理解它存在的意义。所以,最好的学习方式,我猜,就是在实践中学习,而在此之前,首先应该有一个爱刨根问底的精神。