pygeta
if __name__ == "__main__”这样的语句出现。这个语句是用来干什么的?
这是一个条件判断语句,如果条件满足,就进入下面的语句。简单来说,该语句用来当文件当作脚本运行时候,就执行代码;但是当文件被当做Module被import的时候,就不执行相关代码。
那么需要考虑的是,什么时候if __name__ == “__main__”会为True,也就是__name__ 变量会等于“__main__”?__name__变量是一个Python的Module的全局变量,Python解析器会在执行过程中设置该变量。当Python解析器将代码当作顶层模块运行的时候,__name__变量就会被赋值为“__main__”。
所谓的顶层模块,就是指第一个运行的用户定义的Python的模块。这个模块由于是第一个执行的,因此在该模块运行中,将会由此模块导入imports所有其他的别的相关依赖模块。因此该模块就被当作顶层模块。
-
最顶层的__name__,将会被设置成了__main__
-
导入的模块中的__name__就被设置成了模块的名称
因此也可以用if __name__ == “__main__”来判断你的模块代码是不是被当作最顶层模块在使用。
什么时候需要避免使用if __name__ == "__main__”语句。
有些时候可以用来屏蔽掉执行测试的部分代码。比如下面的例子:
如果该模块被执行,可以用来执行测试用例,否则就当作一个模块导入,测试不会被执行。
# adder.pyimport unittestdef add(a: int, b: int) -> int:return a + bclass TestAdder(unittest.TestCase):def test_add_adds_two_numbers(self):self.assertEqual(add(1, 2), 3)if __name__ == "__main__":unittest.main()
但是这种方式不太建议,在比较规模项目的测试中,是可以这么做,但是如果代码量一大,这种将代码和测试混在一个文件的方式,不太方便代码管理。一般应该是将测试代码写在另外一个文件中。同时这也要求将
unittest模块在代码模块中导入,这也不是一个很好的实现。
另外一个不好的使用例子是用来包含一些模块使用信息,当用户导入该模块的时候,使用信息不会被执行,但是当当作脚本运行的时候,就可以打印出使用信息。
这其实也不是一个很好的实践。如果是用来打印使用信息,可以用别的更好的方法(比如编写详细的docstrings)。
第三种情况是纯脚本情况:如果你要写的代码就是一个脚本,那么你就直接写代码在全局空间中即可,不要再放到if __name__ == “__main__”下,这样做意义不大。
最后讲一下使用if __name__ == “__main__"的最佳实践。
首先这个语句只是一个判断语句,因此该语句可以被放到文件的任何地方,也可以多次使用。但是比较好的建议是大部分情况,该语句只在文件中出现一次,并且放到文件的最后。这样可以似的代码变得比较整洁,逻辑也会清晰很多。该语句放到最后还有一个好处,就是确保所有需要使用的函数或者变量都已经在前面定义好了。
但是在某些情况,也可以多次的使用if __name__ == "__main__”语句。
比如分情况导入其他模块,见如下例子:
# echo.pyif __name__ == "__main__":import sysdef echo(text: str, repetitions: int = 3) -> str:"""Imitate a real-world echo."""echoed_text = ""for i in range(repetitions, 0, -1):echoed_text += f"{text[-i:]}\n"return f"{echoed_text.lower()}."if __name__ == "__main__":text = " ".join(sys.argv[1:])print(echo(text))
在该例子中,可以利用该条件语句,是的不必要的导入一些模块。过多的解释就不在赘述。
另外的一个好的代码风格就是if __name__ == "__main__”下面的代码应该尽可能的少,如果需要放比较多的代码,
那么就应该另外定义个main函数来包含这些代码。
比如如下代码:
# echo.pyimport sysdef echo(text: str, repetitions: int = 3) -> str:"""Imitate a real-world echo."""echoed_text = ""for i in range(repetitions, 0, -1):echoed_text += f"{text[-i:]}\n"return f"{echoed_text.lower()}."def main() -> None:text = " ".join(sys.argv[1:])print(echo(text))if __name__ == "__main__":main()
后记
很多讨论将python的if __name__ == “__main__"和其他语言的入口函数main()做比较,然后得出结论说python的语法太不简洁。其实事情并不是这样的,if __name__ == "__main__"只是一个判断语句,不是程序的入口点。
python在演化过程中,对该语句的讨论也进行过很多次,但是一直也没有取消这个语句,主要原因有如下几点:
-
这个语句已经很短了:很多其他的建议节约不了几行代码
-
使用场景不多:只建议在需要将一个脚本文件运行同时也能够当作模块导入的时候,需要用到,其他情况不建议经常使用。
-
暴露了复杂性:让python使用人员,能够了解python的背后的变量和函数,这样可以更好的理解python的实现。
-
可以向后兼容。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix