if __name__ == "__main__": 做啥?

Posted

技术标签:

【中文标题】if __name__ == "__main__": 做啥?【英文标题】:What does if __name__ == "__main__": do?if __name__ == "__main__": 做什么? 【发布时间】:2010-09-29 23:15:39 【问题描述】:

给定以下代码,if __name__ == "__main__": 做了什么?

# Threading example
import time, thread

def myfunction(string, sleeptime, lock, *args):
    while True:
        lock.acquire()
        time.sleep(sleeptime)
        lock.release()
        time.sleep(sleeptime)

if __name__ == "__main__":
    lock = thread.allocate_lock()
    thread.start_new_thread(myfunction, ("Thread #: 1", 2, lock))
    thread.start_new_thread(myfunction, ("Thread #: 2", 2, lock))

【问题讨论】:

仅作记录——什么是“main”:docs.python.org/3/reference/… 和什么是“name”:docs.python.org/3/reference/… 【参考方案1】:

如果您是初学者,您现在可能唯一需要的答案是对于一个简单的脚本来说,这段代码是不必要的。仅当您希望能够 import 您的脚本(或 unpickle 等;请参阅此处的其他答案以了解其他一些非初学者场景)时,它才有用。

稍微详细一点,假设您有一个简单的脚本fib.py(改编自this answer):

# 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 使用新版本,但如果你一开始不打算这样做,这个版本实际上更好,因为它更简单、更清晰。

如果你确实希望能够import fib,那么第一个版本也是没用的,因为有用的代码在你import这个文件时不会运行的部分(在这种情况下,__name__ 将不是 "__main__")。在这种情况下,正确的设计是重构代码,以便在您拥有imported 之后,您可以在想要运行的时候运行该功能。

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 并从执行此import 的代码中调用fibn() 函数。

(我调用函数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(或者,也许更好,将main 重构为return lock,并让调用者在其自己的局部变量中捕获该值)。

【讨论】:

我保持示例代码简单以避免分心;在现实生活中,您需要处理 input 返回的不是数字的东西,当然,可能应该优化现实生活中的斐波那契函数以避免每次调用时重新计算序列的开头。 n: int-&gt; int 类型注解需要 Python >= 3.6 斐波那契数列的排序规则并非一成不变。通常的约定是第一个数字是 0,但在数学上通常是 F(0)。您可能会将简单脚本的结果视为一个错误,并相应地对其进行修复。【参考方案2】:

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'

请注意,只执行my_test_module 中的***print() 语句。


第二种可能性:将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'

更全面的解释可以阅读What does if __name__ == '__main__' do in Python

【讨论】:

【参考方案3】:

我是 Python 的初学者,但我想在这里写。

假设我在 Wikipedia 上编写了用于网络抓取的函数和类 当然,这可能不是一个很好的例子 我想在另一个程序中使用这些函数而不重写它

好吧,我导入它们,但在那个文件的末尾 我把 __ name __ = '__ main __'

当我们导入一个模块时,它里面的所有代码都会从头到尾执行 但是当它达到条件时,它并没有运行 func , fucn2 和 ...,这是*** scrape

在全局范围内,Python __ name __ 被定义为当前程序的 '__ main __'

当我们导入一个模块时,它被定义为我们当前程序的名称空间中的一个变量 并且当前程序 __ 名称 __ 是 '__ main __'

#test.py
def func():
    #do somthing
    pass
def func2():
    #do somthing
    pass
print('The program name is set to',globals()['__name__'])

if __name__=='__main__':
    #in current program __name__ is equal '__main__' 
    func('https://www.wikipedia.org')
    func2('https://www.wikipedia.org')
    #or do more job
    
import test1
print('inside of current program')
print('name is current program',__name__)
print(globals()['test1'])
test1.func('another site')
test1.func2('another site')

输出

inside of test 1
name of program is set to  test1
end of madule
inside of current
__main__
<module 'test1' from 'C:\\users\\ir\\appdata\\local\\programs\\python\\python38\\lib\\test1.py'>

【讨论】:

【参考方案4】:

当从命令行调用 Python 文件时这是特殊的。这通常用于调用“main()”函数或执行其他适当的启动代码,例如命令行参数处理。

它可以用多种方式编写。另一个是:

def some_function_for_instance_main():
    dosomething()


__name__ == '__main__' and some_function_for_instance_main()

我并不是说您应该在生产代码中使用它,但它可以说明if __name__ == '__main__' 没有什么“神奇”。

这只是在 Python 文件中调用 main 函数的约定。

【讨论】:

我会考虑这种糟糕的形式,因为您 1) 依赖副作用和 2) 滥用 andand 用于检查两个布尔语句是否都为真。由于您对and 的结果不感兴趣,因此if 语句更清楚地传达了您的意图。 撇开利用布尔运算符的短路行为作为流控制机制是否是不好的风格的问题不谈,更大的问题是这 没有回答问题全部. @jpmc26 任何具有 Perl 或 javascript 背景的人都对这个习惯用法非常满意,使用 and 作为控制语句。我对此没有任何问题。另一个类似的习惯用法是使用or 设置默认值。例如,x = input("what is your name? ") or "Nameless Person" @JohnHenckel 这不是 Perl 或 JavaScript。这不是 Python 习语。在 Python 中的布尔语句中间使用具有副作用的函数被认为是不好的形式。特别是在这种情况下,在这里使用and 绝对没有任何好处;该函数甚至不返回值。它只是让代码不那么明显。 @jpmc26 我正在努力寻找与您一致的权威来源。这是在某处提到的吗?例如,在 PEP8 中是否说我们应该避免使用 and 进行控制,或者使用 or 分配默认值?我试图用谷歌搜索它,但我找不到任何东西。【参考方案5】:

当您执行模块(源文件)时,if-condition 会检查模块是直接调用还是从另一个源文件调用。这里直接表示不导入。

如果直接调用执行,则模块名设置为“main”,然后执行if块内的代码。

【讨论】:

【参考方案6】:

当一个python文件被执行时,它会创建许多特殊的变量,例如__name__变量__name__保存文件的名称。并回答你的问题是

if __name__ == "__main__":
       #do something

这意味着如果正在执行的文件的名称作为源文件运行并且不是模块,那么它将运行其中的代码,这可以通过一个简单的示例来证明。创建两个python文件foo.pysecond.py然后在foo.py中输入这个

if __name__ == "__main__":
       print("file is not imported")
else:
       print("file is imported")

然后在second.py 中输入这个

import foo

if foo.__name__ == "__main__":
       print("file is not imported")
else:
       print("file is imported")

除此之外,如果你会这样做print(__name__),那么它会打印__main__,为什么?因为文件作为 ma​​in 源运行,如果你会这样做 print(foo.__name__) 它将打印 foo 因为 __name__ 变量的默认值是文件的名称,默认情况下我的意思是你也可以更改它来执行此操作只需转到 foo.py 并执行此操作 __name__ = "name" 然后当您运行该文件时,例如

__name__ = "hello world"
print(__name__)

然后输出将是

hello world

【讨论】:

【参考方案7】:

简答

它是样板代码,可防止用户在无意中意外调用脚本。以下是脚本中省略守卫时的一些常见问题:

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

如果您在无保护脚本中有一个自定义类并将其保存到一个 pickle 文件中,那么在另一个脚本中将其取消腌制将触发无保护脚本的导入,与上一个项目符号中概述的问题相同。

长答案

为了更好地理解为什么以及如何重要,我们需要退后一步来了解 Python 如何初始化脚本以及它如何与其模块导入机制交互。

每当 Python 解释器读取源文件时,它都会做两件事:

它设置了一些特殊的变量,比如__name__,然后

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

让我们看看它是如何工作的,以及它与您对我们在 Python 脚本中经常看到的__name__ 检查的问题有何关联。

代码示例

让我们使用一个稍微不同的代码示例来探索导入和脚本的工作原理。假设以下内容位于名为 foo.py 的文件中。

# Suppose this is foo.py.

print("before import")
import math

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

print("before functionB")
def functionB():
    print("Function B ".format(math.sqrt(100)))

print("before __name__ guard")
if __name__ == '__main__':
    functionA()
    functionB()
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"

执行模块的代码

设置特殊变量后,解释器执行模块中的所有代码,一次一条语句。您可能想在代码示例旁边打开另一个窗口,以便您可以按照此说明进行操作。

总是

    它打印字符串"before import"(不带引号)。

    它加载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")

    它打印字符串"before functionA"

    它执行def 块,创建一个函数对象,然后将该函数对象分配给一个名为functionA 的变量。

    它打印字符串"before functionB"

    它执行第二个def 块,创建另一个函数对象,然后将其分配给一个名为functionB 的变量。

    它打印字符串"before __name__ guard"

仅当您的模块是主程序时

    如果您的模块是主程序,那么它会看到__name__ 确实设置为"__main__",并调用这两个函数,打印字符串"Function A""Function B 10.0"

仅当您的模块被其他人导入时

    (instead) 如果你的模块不是主程序而是被另一个程序导入,那么__name__ 将是"foo",而不是"__main__",它会跳过正文if 声明。

总是

    在这两种情况下都会打印字符串"after __name__ guard"

总结

总之,以下是两种情况下会打印的内容:

# What gets printed if foo is the main program
before import
before functionA
before functionB
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 functionA
before functionB
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 functionA():
    print("a1")
    from foo2 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
if __name__ == "__main__":
    print("m1")
    functionA()
    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 functionA():
    print("a1")
    from foo3 import functionB
    print("a2")
    functionB()
    print("a3")

def functionB():
    print("b")

print("t1")
print("m1")
functionA()
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")

【讨论】:

出于好奇:如果我在 python 脚本中运行 subprocess.run('foo_bar.py') 会发生什么?我想foo_bar 将以__name__ = '__main__' 开头,就像我在cmd 中手动提示foo_bar.py 一样。是这样吗?考虑到@MrFooz 的回答,这样做应该没有任何问题,并且一次拥有尽可能多的“主要”模块。即使更改 __name__ 值或让多个独立创建的实例(或由 subprocess 相互创建的实例)相互交互,对于 Python 来说也应该照常进行。我错过了什么吗? @hajef 你对subprocess.run 的工作方式是正确的。也就是说,在脚本之间共享代码通常更好的方法是创建模块并让脚本调用共享模块,而不是作为脚本相互调用。很难调试subprocess.run 调用,因为大多数调试器不会跨越进程边界,它会增加重要的系统开销来创建和销毁额外的进程等。 我对思考部分中的 foo2.py 示例有疑问。 from foo2.py import functionB 有什么作用?在我看来,它只是从 functionB 导入 foo2.py multiprocessing 是可能导入您的代码的模块之一,尤其是在 Windows 上需要进行此测试。 非常小的一点,但我相信python实际上是从import语句中确定导入模块的__name__,而不是从文件名中剥离“.py”。因为 python 标识符区分大小写但文件名可能不区分大小写(例如在 windows 上),所以文件名中不一定有足够的信息来确定正确的 python 模块名称。【参考方案8】:

if __name__ = "__main__" 表示如果你像python foo.py 一样正常运行python 文件,它会将特殊变量__name__ 分配给"__main__",但如果你正在导入像“import foo”这样的文件,它将分配@987654325 @ 到"foo" 并且不会运行该函数。

【讨论】:

【参考方案9】:

简单来说:

您在if __name__ == "__main__": 下看到的代码只会在您的 python 文件作为“python example1.py”执行时才会被调用。

但是,如果您希望将您的 python 文件“example1.py”作为模块导入以使用另一个 python 文件,例如“example2.py”,if __name__ == "__main__": 下的代码将不会运行或生效。

【讨论】:

【参考方案10】:

我一直在阅读此页面上的所有答案。我想说,如果你知道这件事,你肯定会明白那些答案,否则你还是一头雾水。

简而言之,你需要知道几点:

    import a 动作实际上运行所有可以在a.py 中运行的内容,即a.py 中的每一行

    由于第 1 点,您可能不希望在导入时所有内容都在 a.py 中运行

    为了解决第 2 点的问题,python 允许您进行条件检查

    __name__ 是所有.py 模块中的隐式变量:

a.pyimported 时,a.py 模块的__name__ 的值设置为其文件名“a” 当a.py直接使用“python a.py”运行时,__name__的值设置为字符串__main__
    基于python如何为每个模块设置变量__name__的机制,你知道如何实现第3点吗?答案很简单,对吧?放一个 if 条件:if __name__ == "__main__": // do A
然后python a.py 将运行部件// do Aimport a 将跳过部分// do A
    您甚至可以根据您的功能需要输入 if __name__ == "a",但很少这样做

python 的特别之处在于第 4 点!其余的只是基本逻辑。

【讨论】:

是的,理解第 1 点至关重要。由此,对这种机制的需求变得清晰。 钉了它,仍然对上面的答案感到完全困惑,但现在它非常清晰! 这是迄今为止最好的“可以理解”的答案。【参考方案11】:

让我们以更抽象的方式来看答案:

假设我们在x.py中有这段代码:

...
<Block A>
if __name__ == '__main__':
    <Block B>
...

当我们运行 x.py 时运行块 A 和 B。

但是当我们运行另一个模块时,只运行块 A(而不是 B),例如 y.py,其中导入了 x.py 并从那里运行代码(就像 x.py 中的函数时一样)从y.py 调用)。

【讨论】:

我无法编辑帖子(如果需要更改,最少 6 个字符)。第 14 行有 'x.y' 而不是 'x.py'。【参考方案12】:

Python 中的每个模块都有一个名为name 的特殊属性。当模块作为主程序执行(例如运行python foo.py)时,name属性的值设置为'ma​​in'。否则,name 的值将设置为调用它的模块的名称。

【讨论】:

【参考方案13】:

PYTHON MAIN FUNCTION 是任何程序的起点。当程序运行时,python 解释器按顺序运行代码。 Main 函数只有在作为 Python 程序运行时才会执行...

def main():
     print ("i am in the function")
print ("i am out of function")

当你运行脚本时:

i am out of function

而不是代码“我在函数中” 这是因为我们没有声明调用函数“if__name__==”ma​​in”。 如果你使用它:

def main():
     print ("i am in the function")


if __name__ == "__main__":
    main()

print ("i am out of function")

输出等于

i am in the function
i am out of function

在 Python 中,“if__name__==”ma​​in”允许您将 Python 文件作为可重用模块或独立程序运行。

当 Python 解释器读取一个源文件时,它将执行在其中找到的所有代码。 当 Python 将“源文件”作为主程序运行时,它会将特殊变量(name)设置为具有值(“ma​​in”)。

当你执行 main 函数时,它会读取 "if" 语句并检查 name 是否等于 ma​​in

在 Python 中,“if__name__==”ma​​in”允许您将 Python 文件作为可重用模块或独立程序运行。

【讨论】:

【参考方案14】:

简单来说,就是运行文件的入口点,就像C编程语言中的main函数。

【讨论】:

这个答案假设 OP(或任何有类似问题的用户)都熟悉 C 并且知道什么是入口点是。 这个答案还假设在 if __name__ == "__main__" 块之前没有代码(除了没有副作用的定义)。从技术上讲,执行的脚本的顶部是程序的入口点。 这是不正确的,并且可能导致许多初学者脚本无用地将所有代码放入此块中。【参考方案15】:

您可以通过以下简单示例检查特殊变量 __name__

创建文件1.py

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

创建文件2.py

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")

执行file2.py

输出

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

【讨论】:

【参考方案16】:

python 中的每个模块都有一个名为__name__ 的属性。直接运行模块时__name__属性的值为__main__,如python my_module.py。否则(就像你说import my_module__name__ 的值是模块的名称。

小例子简单说明。

#Script test.py

apple = 42

def hello_world():
    print("I am inside hello_world")

if __name__ == "__main__":
    print("Value of __name__ is: ", __name__)
    print("Going to call hello_world")
    hello_world()

我们可以直接这样执行

python test.py  

输出

Value of __name__ is: __main__
Going to call hello_world
I am inside hello_world

现在假设我们从其他脚本调用上面的脚本

#script external_calling.py

import test
print(test.apple)
test.hello_world()

print(test.__name__)

当你执行这个

python external_calling.py

输出

42
I am inside hello_world
test

因此,上面的内容很明显,当您从其他脚本调用 test 时,test.py 中的 if 循环 __name__ 将不会执行。

【讨论】:

【参考方案17】:

如果 Python 解释器正在运行特定模块,则 __name__ 全局变量将具有值 "__main__"

  def a():
      print("a")
  def b():
      print("b")

  if __name__ == "__main__": 

          print ("you can see me" )
          a()
  else: 

          print ("You can't see me")
          b()

当你运行这个脚本时,你可以看到我

一个

如果你导入这个文件说A到文件B并执行文件B,那么文件A中的if __name__ == "__main__"会变成假,所以它会打印出You can't see me

b

【讨论】:

【参考方案18】:

考虑:

print __name__

上面的输出是__main__

if __name__ == "__main__":
  print "direct method"

以上陈述为真,打印出“直接方法”。假设如果他们在另一个类中导入这个类,它不会打印 "direct method",因为在导入时,它会设置 __name__ equal to "first model name"

【讨论】:

【参考方案19】:

__name__ 变量(恕我直言)的最简单解释如下:

创建以下文件。

# a.py
import b

# b.py
print "Hello World from %s!" % __name__

if __name__ == '__main__':
    print "Hello World again from %s!" % __name__

运行它们会得到这个输出:

$ python a.py
Hello World from b!

如你所见,当一个模块被导入时,Python 将这个模块中的globals()['__name__'] 设置为模块的名称。此外,导入后,模块中的所有代码都在运行。由于if 语句的计算结果为False,这部分不会被执行。

$ python b.py
Hello World from __main__!
Hello World again from __main__!

如你所见,当一个文件被执行时,Python 将这个文件中的globals()['__name__'] 设置为"__main__"。这一次,if 语句的计算结果为 True 并且正在运行。

【讨论】:

【参考方案20】:

此答案适用于学习 Python 的 Java 程序员。 每个 Java 文件通常都包含一个公共类。您可以通过两种方式使用该类:

    从其他文件调用类。您只需在调用程序中导入即可。

    单独运行该类,用于测试目的。

对于后一种情况,该类应包含一个公共静态 void main() 方法。在 Python 中,此目的由全局定义的标签 '__main__' 提供。

【讨论】:

【参考方案21】:

如果这个.py文件被其他.py文件导入,“if语句”下的代码将不会被执行。

如果这个 .py 由 python this_py.py 在 shell 下运行,或者在 Windows 中双击。 “if语句”下的代码将被执行。

它通常是为测试而编写的。

【讨论】:

【参考方案22】:

在解释任何关于if __name__ == '__main__' 的内容之前,了解__name__ 是什么以及它的作用很重要。

什么是__name__

__name__ 是一个DunderAlias - 可以被认为是一个全局变量(可从模块访问),其工作方式类似于global

它是由type(__name__)(产生&lt;class 'str'&gt;)指示的字符串(如上所述的全局),并且是Python 3 和Python 2 版本的内置标准。

地点:

它不仅可以在脚本中使用,还可以在解释器和模块/包中找到。

口译员:

>>> print(__name__)
__main__
>>>

脚本:

test_file.py

print(__name__)

导致__main__

模块或包:

somefile.py:

def somefunction():
    print(__name__)

test_file.py:

import somefile
somefile.somefunction()

导致somefile

请注意,当在包或模块中使用时,__name__ 采用文件名。没有给出实际模块或包路径的路径,但有自己的 DunderAlias __file__,允许这样做。

你应该看到,__name__,它是主文件(或程序)将总是返回__main__,如果它是一个模块/包,或者任何东西运行其他一些 Python 脚本,将返回它所来自的文件的名称。

练习:

作为变量意味着它的值可以被覆盖(“可以”并不意味着“应该”),覆盖__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__ 的行为变得更加清晰了:

if 是一个流控制语句,如果给定值为真,则包含将执行的代码块。我们已经看到__name__ 可以采取 __main__ 或从中导入它的文件名。

这意味着如果 __name__ 等于 __main__ 则该文件必须是主文件并且必须实际运行(或者它是解释器),而不是导入到脚本中的模块或包。

如果确实 __name__ 确实采用了 __main__ 的值,那么该代码块中的任何内容都将执行。

这告诉我们,如果运行的文件是主文件(或者您直接从解释器运行),那么必须执行该条件。如果它是一个包那么它不应该,并且值不会是__main__

模块:

__name__也可以用在modules中来定义一个module的名字

变体:

还可以使用__name__ 做其他不太常见但有用的事情,我将在这里展示一些:

仅当文件是模块或包时执行:

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

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

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

您还可以使用它为包和模块提供可运行的帮助功能/实用程序,而无需精心使用库。

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

【讨论】:

【参考方案23】:

所有答案几乎都解释了该功能。但我将提供一个它的用法示例,这可能有助于进一步理清这一概念。

假设您有两个 Python 文件,a.py 和 b.py。现在,a.py 导入 b.py。我们运行 a.py 文件,其中首先执行“import b.py”代码。在其余的 a.py 代码运行之前,文件 b.py 中的代码必须完全运行。

在 b.py 代码中,有一些代码是该文件 b.py 独有的,我们不希望导入 b.py 文件的任何其他文件(除了 b.py 文件)运行它。

这就是这行代码检查的内容。如果它是运行代码的主文件(即 b.py),在这种情况下它不是(a.py 是运行的主文件),那么只有代码被执行。

【讨论】:

【参考方案24】:

如果 name == 'ma​​in':

我们是否经常查看__name__ == '__main__':

它检查一个模块是否正在被导入。

换句话说,if 块中的代码只有在代码直接运行时才会被执行。这里directly 表示not imported

让我们看看它使用打印模块名称的简单代码做了什么:

# test.py
def test():
   print('test module name=%s' %(__name__))

if __name__ == '__main__':
   print('call test()')
   test()

如果我们直接通过python test.py运行代码,模块名称为__main__

call test()
test module name=__main__

【讨论】:

【参考方案25】:

创建一个文件,a.py

print(__name__) # It will print out __main__

__name__ 始终等于__main__,只要该文件直接运行表明这是主文件。

在同一目录中创建另一个文件 b.py

import a  # Prints a

运行它。它将打印a,即导入的文件的名称

所以,为了显示同一文件的两种不同行为,这是一个常用的技巧:

# Code to be run when imported into another python file

if __name__ == '__main__':
    # Code to be run only when run directly

【讨论】:

【参考方案26】:

考虑:

if __name__ == "__main__":
    main()

它检查 Python 脚本的 __name__ 属性是否为 "__main__"。换句话说,如果程序本身被执行,属性将是__main__,所以程序会被执行(这里是main()函数)。

但是,如果您的 Python 脚本被模块使用,则if 语句之外的任何代码都将被执行,因此if \__name__ == "\__main__" 仅用于检查程序是否用作模块,因此决定是否运行代码。

【讨论】:

【参考方案27】:

我认为最好深入浅出地打破答案:

__name__:Python 中的每个模块都有一个名为__name__ 的特殊属性。 它是一个返回模块名称的内置变量。

__main__:与其他编程语言一样,Python 也有一个执行入口点,即 main。 '__main__' 是***代码执行的范围的名称。基本上你有两种使用 Python 模块的方法:直接作为脚本运行它,或者导入它。当模块作为脚本运行时,其__name__ 设置为__main__

因此,当模块作为主程序运行时,__name__ 属性的值设置为__main__。否则,__name__ 的值将设置为包含模块的名称。

【讨论】:

【参考方案28】:

这里对所讨论代码的机制有很多不同的看法,即“如何”,但对我来说,在我理解“为什么”之前,这没有任何意义。这对新程序员应该特别有帮助。

获取文件“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。 import 语句在导入时立即运行模块,因此ab 的操作在xy 的其余部分之前执行。完成ab 后,继续使用xy

解释器跟踪使用__name__ 运行的脚本。当您运行脚本时(无论您将其命名为什么),解释器都会将其称为 "__main__",使其成为运行外部脚本后返回的主脚本或“主”脚本。

从此"__main__" 脚本调用的任何其他脚本都将其文件名指定为其__name__(例如__name__ == "ab.py")。因此,if __name__ == "__main__": 行是解释器的测试,以确定它是否正在解释/解析最初执行的“主”脚本,或者它是否暂时窥视另一个(外部)脚本。这让程序员可以灵活地让脚本在直接执行和外部调用时表现不同。

让我们逐步浏览上面的代码以了解发生了什么,首先关注未缩进的行以及它们在脚本中出现的顺序。记住这个函数——或者def——块在被调用之前不会自己做任何事情。如果口译员自言自语,可能会说什么:

将 xy.py 作为“主”文件打开;在__name__ 变量中调用它"__main__"。 使用__name__ == "ab.py" 导入和打开文件。 哦,一个函数。我会记住的。 好的,函数a();我刚刚学到了。打印“ab 文件中的函数”。 文件结束;回"__main__"! 哦,一个函数。我会记住的。 另一个。 函数x();好的,打印“周边任务:可能对其他项目有用”。 这是什么? if 声明。嗯,条件已经满足了(变量__name__已经设置为"__main__"),所以我进入main()函数并打印'main function: this is where the action is'。

下面两行的意思是:“如果这是"__main__" 或'home' 脚本,请执行名为main() 的函数”。这就是为什么您会在顶部看到一个 def main(): 块,其中包含脚本功能的主要流程。

为什么要实现这个?

还记得我之前说过的关于 import 语句的内容吗?当您导入一个模块时,它不仅会“识别”它并等待进一步的指令 - 它实际上会运行脚本中包含的所有可执行操作。因此,将脚本的内容放入 main() 函数可以有效地隔离它,将其隔离,以便在被另一个脚本导入时不会立即运行。

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

但是没有它代码也可以工作

是的,没错。这些单独的函数可以从不包含在main() 函数中的内嵌脚本中调用。如果您习惯于(就像我一样,在我编程的早期学习阶段)构建完全符合您需要的内联脚本,并且如果您再次需要该操作,您将尝试再次弄清楚...... . 好吧,您不习惯代码的这种内部结构,因为它构建起来更复杂,而且阅读起来也不那么直观。

但这是一个可能无法在外部调用其函数的脚本,因为如果调用它,它将立即开始计算和分配变量。如果您尝试重用一个函数,那么您的新脚本与旧脚本的相关性很可能会导致变量冲突。

在拆分独立函数时,您可以通过将它们调用到另一个脚本中来重用以前的工作。例如,“example.py”可能会导入“xy.py”并调用x(),利用“xy.py”中的“x”函数。 (也许它是将给定文本字符串的第三个单词大写;从数字列表创建一个 NumPy 数组并将它们平方;或者去除 3D 表面的趋势。可能性是无限的。)

(顺便说一句,this question 包含@kindall 的答案,最终帮助我理解了 - 为什么,而不是如何。不幸的是,它被标记为 this one 的副本,我认为这是一个错误。 )

【讨论】:

【参考方案29】:

简单地说,__name__ 是为每个脚本定义的变量,用于定义脚本是作为主模块运行还是作为导入模块运行。

如果我们有两个脚本;

#script1.py
print "Script 1's name: ".format(__name__)

#script2.py
import script1
print "Script 2's name: ".format(__name__)

执行script1的输出是

Script 1's name: __main__

执行script2的输出是:

Script1's name is script1
Script 2's name: __main__

如您所见,__name__ 告诉我们哪个代码是“主”模块。 这很棒,因为您可以只编写代码而不必担心像 C/C++ 中的结构问题,如果文件没有实现“main”函数,那么它就无法编译为可执行文件,如果确实如此,然后它不能用作库。

假设您编写了一个出色的 Python 脚本,并且您实现了大量可用于其他目的的函数。如果我想使用它们,我可以只导入您的脚本并使用它们而不执行您的程序(假设您的代码仅在 if __name__ == "__main__": 上下文中执行)。而在 C/C++ 中,您必须将这些部分分成一个单独的模块,然后包含该文件。想象一下下面的情况;

箭头是导入链接。对于三个模块,每个模块都试图包含以前的模块代码,有六个文件(九个,计算实现文件)和五个链接。这使得很难将其他代码包含到 C 项目中,除非将其专门编译为库。现在为 Python 想象一下:

您编写一个模块,如果有人想使用您的代码,他们只需导入它,__name__ 变量可以帮助将程序的可执行部分与库部分分开。

【讨论】:

C/C++ 图解错误:3 次相同的单元名(file1)。【参考方案30】:

if __name__ == "__main__":基本上是***脚本环境,它指定了解释器('我有最高优先级先执行')。

'__main__' 是***代码执行的范围的名称。当从标准输入、脚本或交互式提示中读取时,模块的 __name__ 设置为等于 '__main__'

if __name__ == "__main__":
    # Execute only if run as a script
    main()

【讨论】:

以上是关于if __name__ == "__main__": 做啥?的主要内容,如果未能解决你的问题,请参考以下文章

if __name__ == "__main__": 做啥?

unittest: if __name__ == "__main__" 理解

python if __name__ == "__main__"

if __name__ == "__main__" 语法错误

if __name__ == "__main__": 和 Python 中的递归 [重复]

if __name__=="__main__"作用