这样做做什么,为什么应该包括: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")

其他回答

如果此. py 文件由其它. py 文件导入, 代码在if将不执行语句。

如果此. py 运行由python this_py.py在 shell 下方的代码,或在 Windows 中双击。if将执行语句。

通常写作用于测试。

在解释之前if __name__ == '__main__'了解什么是__name__和它的作用。

什么是__name__?

__name__是 a 是达德阿里亚斯Name- 可被视为全球变量(可从模块中获取),工作方式与global.

它是一个字符串(如上所述,全球范围),如下文所示:type(__name__)(年均(年均)<class 'str'>),而两者都是一个内在的标准,Python 3Python 2版本的版本 。

何处处

它不仅可以用于脚本,还可以在口译和模块/软件包中找到。

解释器 :

>>> print(__name__)
__main__
>>>

脚本 :

测试_ 文件. py:

print(__name__)

导致__main__

模块或包件 :

一些文件. py:

def somefunction():
    print(__name__)

测试_ 文件. py :

import somefile
somefile.somefunction()

导致somefile

请注意,如果在包件或模块中使用,__name__选择文件的名称。没有给实际模块或软件包路径的路径,而是有它自己的 DunderAlias 路径。__file__,允许这样做。

你应该看到,在哪里__name__,它是主文件(或程序)的始终始终返回返回__main__,如果它是模块/软件包,或者正在从其他 Python 脚本中运行的东西,将返回其来源文件的名称。

实践实践实践

变数意味着它的价值能够被覆盖 (“ can” 并不意味着“sh') , 覆盖__name__将会导致缺乏可读性。 所以无论出于什么原因都不要这样做。 如果您需要变量定义新的变量, 请定义新的变量 。

人们总是认为,人们总是认为,__name__待 待 待 待 待 待 待 待__main__或文件的名称。 再次更改此默认值将会造成更多的混乱, 从而导致问题更加严重 。

示例:

>>> __name__ = 'Horrify' # Change default from __main__
>>> if __name__ == 'Horrify': print(__name__)
...
>>> else: print('Not Horrify')
...
Horrify
>>>

一般认为良好做法包括:if __name__ == '__main__'在脚本中。

现在回答if __name__ == '__main__':

现在我们知道__name__(b) 使情况更加明确:

A 音 Aif是一个流量控制语句,其中含有如果给定值是真实的将执行的代码块块。我们已经看到__name__中可选择其中之一__main__或从它导入的文件名 。

这意味着如果__name__等于__main__然后,文件必须是主文件,而且必须实际运行(或翻译),而不是将模块或软件包导入到脚本中。

如果确实__name__值的数值__main__然后那块代码里的任何东西 都会被执行

这告诉我们, 如果正在运行的文件是主文件( 或者您正在直接从翻译器中运行) , 那么该条件必须执行。 如果它是软件包, 那么它不应该, 而值将不会是__main__.

模块模块

__name__也可以用于模块中定义模块名称的模块

变式

此外,还可能采取其他不太常见但有用的措施,包括:__name__有些我会在这里展示:

仅在文件是一个模块或软件包时才执行

if __name__ != '__main__':
    # Do some useful things 

如果文件是主文件,则运行一个条件;如果不是主文件,则运行另一个条件

if __name__ == '__main__':
    # Execute something
else:
    # Do some useful things

您也可以使用它在软件包和模块上提供可运行的帮助功能/用途,而不必精密使用图书馆。

它还允许模块作为主脚本从命令行运行,这也非常有用。

if __name__ == "__main__":无法在导入文件时运行不需要的代码 。

例如,这是test1.pyif __name__ == "__main__"::

# "test1.py"

def hello()
    print("Hello")

hello()

还有test2.py进口test1.py:

# "test2.py"

import test1 # Here


然后,当奔跑的时候,test2.py, 1个Hello打印是因为不需要的代码hello()test1.py同时运行 :

python test2.py
Hello

当然,你可以打给test1.hello()test2.py:

# "test2.py"

import test1

test1.hello() # Here

然后,当奔跑的时候,test2, Hello已经打印 :

python test2.py
Hello
Hello

现在,添加if __name__ == "__main__":test1.py并放hello()在其之下:

# "test1.py"

def hello()
    print("Hello")

if __name__ == "__main__":
    hello()

这是test2.py:

# "test2.py"

import test1

test1.hello()

然后,当奔跑的时候,test2.py, 只有一个Hello打印是因为if __name__ == "__main__":防止要运行不需要的代码hello()何时test2.py进口进口进口test1.py:

python test2.py
Hello

此外,是否test1.py拥有if __name__ == "__main__":或非:

# "test1.py"

def hello()
    print("Hello")

if __name__ == "__main__":
    hello()
# "test1.py"

def hello()
    print("Hello")

hello()

一个Hello运行时正确打印test1.py:

python test1.py
Hello

如果你是初学者 可能你现在唯一需要的答案就是此代码没有必要简单脚本的简单脚本。它只有在您想要能够import您的脚本 (或)unpickle等; 等; 参见关于其他一些非初始情景的其他答案 。

以略微不同的措辞,if __name__警卫是隐藏代码的机制, 用于隐藏其它代码 。 如果您没有特定的理由隐藏某些信息, 不要: 如果您不需要隐藏一些代码 。import,不要把它背后的警卫, 如果你这样做, 隐藏尽可能少的隐藏。

更详细一点,假设你有一个简单的脚本fib.py(改编回答本答案):

# XXX FIXME: useless (see below)
if __name__ == "__main__":
    n = int(input('Write a number: '))
    a, b = 0, 1
    while b < n:
        a, b = b, a+b
    print('Fibonacci number %i: %i' % (n, b))

现在,如果你只是跑跑python fib.py效果不错,但是...__name__将永远"__main__"在此情况下, 条件其实是不必要的。 脚本可以简化为

n = int(input('Write a number: '))
a, b = 0, 1
while b < n:
    a, b = b, a+b
print('Fibonacci number %i: %i' % (n, b))

现在,你不能import fib新版本的版本, 但如果你一开始不打算这样做, 这个版本其实更好, 因为它简单明了。

如果你(如果)do do do 做想要能够import fib,第一个版本也是没用的,因为有用的代码是在一个区域中,当您import此文件( 在哪个情况下)__name__将不为"__main__"))。在这种情况下,适当的设计将是重新设定代码,以便有用的部分在函数中发挥作用,在您想要运行时,可以运行importEd it. Ed. Ed it. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. Ed. 编辑。 编辑 编辑。 编辑。 编辑 编辑。 编辑。

def main():
    n = int(input('Write a number: '))
    a, b = 0, 1
    while b < n:
        a, b = b, a+b
    print('Fibonacci number %i: %i' % (n, b))

if __name__ == "__main__":
    main()

如果你现在import fib,呼吁main()将不会被执行;但当您运行时python fib.py会的

实际上,更好的设计仍然是将可重复使用部分(实际计算)与用户可看到的投入/产出分开:

def fibn(n: int) -> int:
    a, b = 0, 1
    while b < n:
        a, b = b, a+b
    return b

def main() -> None:
    n = int(input('Write a number: '))
    print('Fibonacci number %i: %i' % (n, fibn(n)))

if __name__ == "__main__":
    main()

现在,你可以from fib import fibn然后喊叫,fibn()运行此功能的代码的函数import.

(我调用函数)fibn()只是为了让这个例子更清楚什么是这个例子。在现实生活中,你可以把它称为fib()并且确实from fib import fib.)

同样,你也可以import然后喊叫,main函数。

在回到问题中的代码时,我同样将代码从if功能中也包含一个功能,因此呼叫者如果愿意,可以援引该功能。

def main():
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

if __name__ == "__main__":
    main()

这改变了lock变量;如果周围代码需要访问它,您需要将其global(或,也许,更好的是,重构mainreturn lock,并让调用者在自己的本地变量中捕捉到值。)

(不同于C类语言中的名称)mainPython 对 Python 没有具体意义; 但使用它作为将要运行的事物的名称, 是一个常见的公约 。 您仍然必须实际明确称呼它, 比如 :main(),不同于C.)

有关代码的机理有很多不同之处, “如何” 但对我而言,除非我理解“为什么” , 否则这些都说不通。 这应该对新的程序员有特别的帮助。

获取文件“ ab. py ” :

def a():
    print('A function in ab file');
a()

第二个文件“xy.py”:

import ab
def main():
    print('main function: this is where the action is')
def x():
    print ('peripheral task: might be useful in other projects')
x()
if __name__ == "__main__":
    main()

这个代码到底在干嘛?

执行时执行xy.py, 您 , 您import ab。导入语句在导入时立即运行模块,因此ab业务在剩余时间之前完成xy完成后ab,它继续xy.

口译员跟踪脚本运行的脚本__name__。当您运行一个脚本时,不管你叫什么,口译员都叫它"__main__",使它成为在运行外部脚本后返回的主人或“家”脚本。

任何其它的脚本 从这里调用"__main__"将其文件名指定为脚本__name__(例如,__name__ == "ab.py"因此,线线if __name__ == "__main__":是口译员的测试, 以确定它是否在解释/ 区分最初执行的“ 家” 脚本, 或者它是否临时偷看另一个( 外部) 脚本。 这让程序员具有灵活性, 如果直接执行的话, 脚本行为会有所不同 。

让我们跨过上面的代码 来理解发生了什么, 首先关注未缩入的行和它们出现在脚本中的顺序。 记住这个函数 - 或者def翻译会说,如果自己自欺欺人的话:

  • 打开 xy.py 作为“ home” 文件; 调用它"__main__"和在__name__变量。
  • 导入并打开文件__name__ == "ab.py".
  • 哦,一个功能,我会记住的
  • Ok, 函数函数a(); 我刚学到了这一点。打印ab 文件中的函数'.
  • 文件结束; 返回到"__main__"!
  • 哦,一个功能,我会记住的
  • 再来一个
  • 函数职能职能职能职能职能职能职能职能x(); OK, 打印 '外围任务:在其他项目中可能有用'.
  • 这是什么?if条件已经满足(变量__name__设定为"__main__"),所以我将进入main()函数和打印main 函数:这是动作所在位置'.

底下两行的意思是: "如果这是"__main__"或“ home” 脚本, 执行调用的函数main()这就是为什么你会看到def main():上方块块, 包含脚本功能的主流 。

为什么要执行这一规定?

还记得我之前说过的进口对帐单吗 ? 当您导入一个模块时, 它不只是“ 承认” 它, 等待进一步的指示 - 它实际上运行脚本中包含的所有可执行操作 。 所以, 将您的脚本中的肉输入到脚本中 。main()功能有效隔离它, 将其隔离, 这样它不会在被其它脚本导入时立即运行 。

同样,也有例外,但通常的做法是:main()通常不会在外部被调用。所以你可能想知道一件事: 如果我们不打电话,main(), 为什么我们要调用剧本? 这是因为许多人用独立的功能构建剧本结构, 这些功能是用来独立运行的, 独立于文件的其余代码。 他们后来在剧本的正文中被调用到别的地方。 这让我想到:

但是没有它 代码是有效的

是的,没错,这些独立的功能能够被调自一个内线脚本, 它不包含在main()函数。如果您习惯(像我一样,在编程的早期学习阶段) 建立内部脚本, 来做你需要的, 你会试着再弄清楚, 如果你需要操作的话... 好吧, 你对代码的这种内部结构并不习惯, 因为它更复杂, 并且没有直观的阅读能力。

但是,这个剧本可能无法将其功能外部命名, 因为如果它真的存在的话, 它会立即开始计算和分配变量。如果你试图重新使用一个函数, 你的新剧本就会与旧剧本紧密相连, 而旧剧本会互相冲突。

分离独立函数时, 您可以通过将您先前的作品调用为另一个脚本来重新使用您之前的工作 。 例如, “ example. py” 可能会导入“ Xy. py” 并调用x(),使用“xy.py”中的“x”函数(也许它正在将给定文本字符串的第三个字数化为资本化;从数字列表中创建 NumPy 阵列并进行排列;或解开3D表面。可能性是无限的。)

(以物配主者,问题 本问题@ kindall 的回答, 终于帮助我理解为什么, 而不是如何。 不幸的是, 它被标记为重复这个我认为这是一个错误。 )