Python中的if name == “__main__” 的全面解释

这是一个条件判断语句,如果条件满足,就进入下面的语句。简单来说,该语句用来当文件当作脚本运行时候,就执行代码;但是当文件被

当做Module被import的时候,就不执行相关代码

也就是说如果你需要把代码放在一个文件中,在if name == "__main__”里面放的代码,就只有在该文件被当作脚本文件执行的时候才会起作用。

比如下面的例子:

print_hello.py

def printHello():

print(“hello”)

if name == “__main__"

print(“in if name == “main” block”)

在上面的代码中,可以运行

python print_hello.py

in if name == “main” block

如果用python来执行该文件,那么in if name == “__main__” 条件就会满足,就会打印出

in if name == “__main__” block语句。

但是如果将print_hello.py文件当作module导入,情况如下:

from print_hello import printHello

printHello()

Hello

可以看到,在这种情况下,if name == “__main__” 下面的代码是没有被激活执行的。

因此可以看到,我们可以将代码放到if name == “__main__”,来适应不同的使用场景。

这段代码的工作原理

从上面的例子,可以看到if name == “__main__”主要就是一个条件语句

当该条件语句为True的时候,该语句下的缩进语句代码,就会执行

当该条件语句为False的时候,该语句下的缩进语句代码,就会被Python解析器跳过

那么需要考虑的是,什么时候if name == “__main__”会为True,也就是__name__ 变量会等于“__main__”?__name__变量是一个Python的Module的全局变量,Python解析器会在执行过程中设置该变量。当Python解析器将代码当作顶层模块运行的时候,__name__变量就会被赋值为“__main__”。

所谓的顶层模块,就是指第一个运行的用户定义的Python的模块。这个模块由于是第一个执行的,因此在该模块运行中,将会由此模块导入imports所有其他的别的相关依赖模块。因此该模块就被当作顶层模块。

为了很好的理解这个,可以简单

用一个例子来说明。

showname.py

print(__name__, type(__name__))

该语句打印__name__

$ python show name.py

main <class ’str’>

可以看到如果当作脚本来执行就被设置成了__main__。

import showname

showname <class ’str’>

在这个例子中,python在import过程中,执行了showname。py文件全局命名空间中的代码,并且将结果打印在控制台中,也就是打印了print(__name__, type(__name__))

如果是当作module导入的时候,

该名字

就被设置成了showname,该模块的名字。

从上面的内容已经说明了,python总是把最顶层的模块的__name__设置成main,因此可以

做如

下试验:

import showname

showname <class ’str’>

name

'__main__'

showname.__name__

'showname'

可以看到和上面介绍的知识点是一致的。总结如下:

最顶层的__name__,将会被设置成了__main__

导入的模块中的__name__就被设置成了模块的名称

因此也可以用if name == “__main__”来判断你的模块代码是不是被当作最顶层模块在使用。

知道了运行原理,再次回到在什么情况下需要使用if name == "__main__”语句,该语句可以用来干什么?

根据这个特性,可以用来对脚本中的函数进行一些输入参数获取。比如在模块中,有一些函数需要输入一些参数,那么当该模块被当作顶层模块执行时候,那么可以通过if name == "__main__”语句来获取输入,并且调用相关的函数,如果该函数被当作模块来调用的时候,函数的输入可以由其他导入的模块来进行输入给定。

什么时候需要避免使用if name == "__main__”语句。

有些时候可以用来屏蔽掉执行测试的部分代码。比如下面的例子:

如果该模块被执行,可以用来执行测试用例,否则就当作一个模块导入,测试不会被执行。

adder.py

import unittest
def add(a: int, b: int) -> int:
return a + b
class 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.py

if name == "__main__":
import sys
def 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.py

import sys
def 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的实现。

可以向后兼容。

标签: none

相关阅读

  • 测试信息
  • 拼多多2023年度财报分析
  • 2023年最后一个工作日
  • 2023山东社会责任企业(企业家)” 推选活动结果
  • 测试信息
  • 测试信息
  • 测试信息