这样做做什么,为什么应该包括:if语句?

if __name__ == "__main__":
    print("Hello, World!")

如果你试图结束一个问题 如果你想要结束一个问题 在那里有人应该应该 使用这个学说,而不是,是不是, 考虑关闭作为 重复的为什么Python在我进口时 运行我的模块? 我该如何阻止它?。而对于某些问题,如果有人只是没有调用任何函数,或者错误地期望指定函数main自动用作切入点,使用当我启动 Python 脚本时, 主函数为何不运行? 脚本从哪里开始运行 ?.


当前回答

短答

保护用户在无意时不意外地引用剧本的锅炉牌代码。 当剧本遗漏了警卫时, 这里有一些常见的问题:

  • 如果您在另一个脚本中导入了无保护脚本(例如 ) 。import my_script_without_a_name_eq_main_guard))),后一脚本将触发前一脚本运行导入时使用第二脚本命令行参数。这几乎总是一个错误。

  • 如果您在无警卫的脚本中有自定义类, 并将其保存为泡菜文件, 那么在另一部脚本中拆开它就会触发无警卫的脚本的输入, 与前一颗子弹中描述的相同问题 。

长答答

为了更好地了解为什么和如何看待这一问题,我们需要退一步,了解Python初始化脚本的方式,以及这如何与其模块输入机制相互作用。

Python 译员读到源文件时,

  • 它设置了几个特殊的变量,比如__name__,然后

  • 它执行文件中发现的所有代码。

让我们看看这是怎么回事 和它与你的问题有什么关系__name__我们总是在 Python 脚本中看到检查。

代码样本

让我们使用略微不同的代码样本来探索导入和脚本是如何工作的。 假设以下是在一个名为foo.py.

# Suppose this is foo.py.

print("before import")
import math

print("before function_a")
def function_a():
    print("Function A")

print("before function_b")
def function_b():
    print("Function B {}".format(math.sqrt(100)))

print("before __name__ guard")
if __name__ == '__main__':
    function_a()
    function_b()
print("after __name__ guard")

特殊变量

当 Python 口译员读取源文件时, 它首先定义了几个特殊变量。 在这种情况下, 我们关心的是__name__变量。

当您的模块是主程序时

如果您正在将模块(源文件)作为主程序运行,例如 。

python foo.py

口译员将指定硬编码字符串"__main__"会 议 日 和 排__name__变量,即:

# It's as if the interpreter inserts this at the top
# of your module when run as the main program.
__name__ = "__main__" 

当您的模块被另一个模块导入时

另一方面,假设某个其他模块是主程序, 它会导入您的模块。 这意味着在主程序或其它模块中, 有类似这样的语句, 或者是主要程序导入 :

# Suppose this is in some other main program.
import foo

译员会搜索您foo.py文件( 加上搜索其它几个变量) 执行该模块之前, 它会指定名称"foo"从导入对帐单到__name__变量,即:

# It's as if the interpreter inserts this at the top
# of your module when it's imported from another module.
__name__ = "foo"

执行模块代码

设置特殊变量后, 口译员将执行模块中的所有代码, 一次执行一个语句。 您可能想要用代码样本在侧面打开另一个窗口, 以便您可以随此解释一起执行 。

总是

  1. 它印着弦"before import"(没有引文)。

  2. 里面装满了math模块,然后将它指派给一个变量,该变量被称为math。这等于替换import math(注:__import__是在 Python 中的低级别函数, 需要字符串并触发实际导入 :

# Find and load a module given its string name, "math",
# then assign it to a local variable called math.
math = __import__("math")
  1. 它印着弦"before function_a".

  2. 它执行def键,创建函数对象,然后将该函数对象指定给一个被称作变量的变量function_a.

  3. 它印着弦"before function_b".

  4. 它执行第二个def键,创建另一个函数对象,然后将其指派到一个被调用的变量function_b.

  5. 它印着弦"before __name__ guard".

只有当您的模块是主程序时

  1. 如果您的模块是主程序, 它就会看到__name__确实设定"__main__"它调用两个功能, 打印字符串"Function A""Function B 10.0".

只有当您的模块被另一个模块导入时

  1. (取代如果您的模块不是主程序,而是被另一个程序导入,那么__name__"foo",而不是"__main__"它会跳过if语句。

总是

  1. 它会打印字符串"after __name__ guard"这两种情况都存在。

摘要摘要摘要

简而言之,这里是两个案例的印刷品:

# What gets printed if foo is the main program
before import
before function_a
before function_b
before __name__ guard
Function A
Function B 10.0
after __name__ guard
# What gets printed if foo is imported as a regular module
before import
before function_a
before function_b
before __name__ guard
after __name__ guard

为什么它这样工作?

你可能会自然而自然而自然地想知道为什么有人想要这个。.py可用于其他程序和/或模块作为模块的文件,也可以作为主要程序本身运行。例如:

  • 您的模块是一个库, 但是您想要有一个脚本模式, 它运行一些单元测试或演示 。

  • 您的模块仅作为主程序使用, 但它有一些单位测试, 以及导入的测试框架 。.py比如您的脚本文件, 并运行特殊测试功能。 您不希望它仅仅因为正在导入模块而尝试运行脚本 。

  • 您的模块大多用作主要程序, 但也为高级用户提供程序员友好的 API 。

除了这些例子之外, 在 Python 中运行脚本只是设置一些神奇变量, 并导入脚本, 这是优雅的。 “ 运行” 脚本是导入脚本模块的副作用 。

" 思想食品 " 组织

  • 问题:我能有多个__name__检查路障?回答:这样做很奇怪, 但语言不会阻止你。

  • 假设以下是foo2.py。如果你说,会发生什么呢?python foo2.py指挥线上?

# Suppose this is foo2.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters

def function_a():
    print("a1")
    from foo2 import function_b
    print("a2")
    function_b()
    print("a3")

def function_b():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    function_a()
    print("m2")
print("t2")
      
  • 现在,找出如果你删除__name__检查中foo3.py:
# Suppose this is foo3.py.
import os, sys; sys.path.insert(0, os.path.dirname(__file__)) # needed for some interpreters

def function_a():
    print("a1")
    from foo3 import function_b
    print("a2")
    function_b()
    print("a3")

def function_b():
    print("b")

print("t1")
print("m1")
function_a()
print("m2")
print("t2")
  • 当作为脚本使用时, 这将做什么 ? 当作为模块导入时 ?
# Suppose this is in foo4.py
__name__ = "__main__"

def bar():
    print("bar")
    
print("before __name__ guard")
if __name__ == "__main__":
    bar()
print("after __name__ guard")

其他回答

您可以查看特殊变量__name__使用此简单示例 :

创建创建文件1. py

if __name__ == "__main__":
    print("file1 is being run directly")
else:
    print("file1 is being imported")

创建 *file2。平平

import file1 as f1

print("__name__ from file1: {}".format(f1.__name__))
print("__name__ from file2: {}".format(__name__))

if __name__ == "__main__":
    print("file2 is being run directly")
else:
    print("file2 is being imported")

执行文件2. py

Output:

file1 is being imported
__name__ from file1: file1
__name__ from file2: __main__
file2 is being run directly

用于从命令行调用 Python 文件。 它通常用于调用“ main ()) ” 函数或执行其他合适的启动代码, 比如, 处理命令行参数 。

也可以以几种方式写成。

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

我不是说你应该用这个来做生产代码, 但是它可以说明,没有什么"神奇"if __name__ == '__main__'.

这只是援引 Python 文件中主要功能的常规 。

除了已经提供的资料外,if __name__ == "__main__":技术也是确保pytestunittest如果您不小心调用脚本, 脚本仍然在运行python代替pytest(或)python -m unittest举例来说:

def test_assert():
    assert 1 + 2 == 3

if __name__ == "__main__":
    import pytest
    pytest.main([__file__])

现在不管怎么称呼你的测试 都会在测试中进行pytestpython。在这里,这是unittest版本 :

import unittest

class Tests(unittest.TestCase):
    def test_assert(self):
        self.assertTrue(1 + 2 == 3)

if __name__ == "__main__":
    unittest.main()

然后您的脚本用python以一计号,以python -m unittest拨打。

现在,如果你也想确保 你所有的价码都通过pytest如果被召唤时python或者,如果你也想加入额外的参考物呢?

def test_assert():
    assert 1 + 2 == 3

if __name__ == "__main__":
    from pytest import main
    from sys import argv
    main([*argv, "-s"])

现在,你的python -v --html=report.html具有与pytest -v --html=report.html,等等。这是一个很好的方法,可以确保脚本仍然照原意运行, 即使没有按照预期运行pytestpython -m unittest电话

当您的脚本作为命令传递给 Python 口译员时,

python myscript.py

缩进级别 0 的所有代码都得到执行。 定义的函数和类别是, 定义的, 定义明确, 但他们的代码没有运行 。 与其他语言不同, 没有main()函数自动运行 -main()函数是最高层所有代码的隐含值。

在这种情况下,最高层代码是if区块。__name__是一个内嵌变量。该变量对当前模块的名称进行评估。但是,如果模块直接运行,则该模块直接运行(如myscript.py above), then __name__而不是设置为字符串"__main__"因此,您可以测试您的脚本是直接运行的,还是通过测试输入其它东西的脚本。

if __name__ == "__main__":
    ...

如果您的脚本正在导入到另一个模块中, 它的各种函数和类定义将会导入, 并且它的顶层代码将会被执行, 但是在当时if以上条款将无法运行,因为不符合条件。作为一个基本例子,考虑以下两个脚本:

# file one.py
def func():
    print("func() in one.py")

print("top-level in one.py")

if __name__ == "__main__":
    print("one.py is being run directly")
else:
    print("one.py is being imported into another module")
# file two.py
import one

print("top-level in two.py")
one.func()

if __name__ == "__main__":
    print("two.py is being run directly")
else:
    print("two.py is being imported into another module")

如果您现在援引译员为

python one.py

产出将是

top-level in one.py
one.py is being run directly

如果你逃跑two.py代之以:

python two.py

你得到

top-level in one.py
one.py is being imported into another module
top-level in two.py
func() in one.py
two.py is being run directly

因此,当模块one装上子弹,装上子弹__name__等于相等"one"代替"__main__".

下代码的代码if __name__ == '__main__':仅仅如果将模块作为脚本引用,则执行该模块。

例如,考虑以下模块my_test_module.py:

# my_test_module.py

print('This is going to be printed out, no matter what')

if __name__ == '__main__':
    print('This is going to be printed out, only if user invokes the module as a script')

第一种可能性:进口my_test_module.py在另一个模块中

# main.py

import my_test_module

if __name__ == '__main__':
    print('Hello from main.py')

如果你现在祈祷main.py:

python main.py

>> 'This is going to be printed out, no matter what'
>> 'Hello from main.py'

请注意,只有最高层print()语中的语中my_test_module执行。


第二种可能性:my_test_module.py作为脚本

现在,如果你现在跑my_test_module.py作为 Python 脚本, 两者print()将执行语句:

python my_test_module.py

>>> 'This is going to be printed out, no matter what'
>>> 'This is going to be printed out, only if user invokes the module as a script'

更全面的解释,可读作:什么是什么东西if __name__ == '__main__'在 Python 中做.