Python 中关于 __main__ 的概念探究
Posted
技术标签:
【中文标题】Python 中关于 __main__ 的概念探究【英文标题】:Conceptual inquiry about __main__ in Python 【发布时间】:2012-07-01 08:05:38 【问题描述】:我目前正在使用 Python,并且对函数在 __main__
中列出的事实感到困惑。我一直在查看多个 python 脚本,试图找到一个共同的主题,即哪些函数需要在__main__
中占有一席之地,但无济于事。在这里,我有一个我自己的代码示例。 firstfunction
和
anotherfunction
是我的代码中仅有的两个函数。
def main(argv):
firstinput=""
secondinput=""
if len(argv) < 3 or len(argv) > 3:
print """"Please set to:
metisfinal.main(metisfinal.py, firstinput, secondinput)""""
return
else:
firstinput = argv[1]
secondinput = argv[2]
firstfunction(firstinput, dictionary)
anotherfunction(list, secondinput)
if __name__ == "__main__":
main(sys.argv)
(我认为)我知道参数和__main__
调用是正确的,但firstfunction
和anotherfunction
总是返回错误(因为它们的参数不是全局定义的)。我很肯定这是由于对__main__
的错误理解造成的,因为我看过的所有其他示例基本上都是以相同的方式设置__main__
。
什么构成在__main__
中列出特定功能?我偶然发现了一些 Python 代码,其中包含超过 30 个函数,但程序员在 __main__
中只列出了其中的 2 个函数。同样,有时代码会在主参数中包含类,例如这个(Project
之前定义为对象类):
def main(argv):
filename = ""
outputfilename = ""
p = Project(filename, outputfilename, subdomainNames)
p.generateICs()
if __name__ == "__main__":
main(sys.argv)
从概念上讲,我无法理解为什么没有列出所有函数...不是所有函数都需要运行还是 __main__
只是在初始化某些东西?
我在看非典型代码吗?我错过了__main__
的哪些关键概念?一旦我找到了要放入 __main__
的函数,是否有特定的方法来格式化它们?
【问题讨论】:
“将函数放入__main__
”是什么意思?
@FogleBird 我认为就像在 C 或 C++ void main 等中一样)
+1 用于验证和加深您的理解。有时你会犯错,但这就是你学习的方式。
@AllysonKim 不,不一定,你可以编写你想要调用的函数,没有缩进和任何“main”
非常感谢你们,非常感谢您的帮助。我理解这是一个基本问题。现在肯定更有意义。伙计,Python 有时可能与 MATLAB 不同 :)
【参考方案1】:
不清楚您所说的“在__main__
中列出”是什么意思。 __main__
不是源文件中的实体。相反,它是模块的name,如果你直接执行它的话。当您执行if __name__=="__main__"
时,您是在告诉 Python 当且仅当代码作为主模块执行时才执行该块中的代码 --- 也就是说,如果它是正在运行的程序。如果模块是从另一个模块导入的,if __name__=="__main__"
块中的代码将不会运行。
请注意,您不会在 if 块中“列出”函数。相反,您将 常规程序代码 放在要运行的那个块中。通常这段代码只调用一个函数。人们经常将该函数称为main()
。但是__main__
和main
之间并没有什么特殊关系。您可以随意调用该函数:
def snicklefritz():
# This function will be run when you run the program
print "You ran the program!"
if __name__ == "__main__":
snicklefritz()
尝试运行该程序(例如,将其保存为“snicklefritz.py”,然后从命令行执行python snicklefritz.py
)。你会看到“你运行了程序!”打印。相反,如果您创建一个单独的文件来执行import snicklefritz
,则不会打印该消息。
请注意,没有关于“列出函数”的内容。比如看这个程序:
print "This will always be printed!"
if __name__ == "__main__":
print "This will only be printed if you run the file as a program!"
这里的if __name__=="__main__"
块没有“列出”任何函数。它只包含文件作为脚本运行时运行的实际代码。但是,人们通常不会这样做,因为将代码放在单独的函数中而不是仅仅“暴露”在函数之外会更整洁。
至于其他功能,您可以在模块中定义您喜欢的任何其他功能,在该模块中使用,或由导入您的模块的其他模块使用。通常,模块中的大多数函数不会在 if __name__=="__main__"
块内使用,因为它们不会是“主”函数的一部分。相反,它们将是供其他代码使用的其他函数。例如:
def otherFunc(x):
# Return x squared
return x**2
def snicklefritz():
# This function will be run when you run the program
print "You ran the program!"
if __name__ == "__main__":
snicklefritz()
otherFunc
在模块中根本没有使用。没关系。可能有人想要导入您的模块并自己使用otherFunc
。并非每个函数都必须在同一个模块中使用,更不用说从 if __name__=="__main__"
块中调用了。
【讨论】:
__main__
实际上是一个模块;你甚至可以导入它。
@Ignacio Woha 确实,虽然从快速的dir(__main__)
看来,它似乎很空 - 它有什么好处?
确实如此,但它不是源文件中的实体,如函数或类。 OP 似乎认为 __main__
是源代码中的“位置”。无论如何,将__main__
作为模块导入是一种相当晦涩的技术,在基本的 Python 使用中并不常见。 (例如,它被线程库等使用。)
@Voo:用于脚本需要自我引用的时候。
我编辑了我的回复以澄清:它没有列出要运行的函数。它包含运行的实际代码。您可以在该块中放置您喜欢的任何内容,而不仅仅是对函数的调用。【参考方案2】:
您误解了__main__
成语。
考虑下面的程序,它保存在一个名为sum.py
的文件中:
def read_numbers():
n1 = int(raw_input())
n2 = int(raw_input())
return n1, n2
def sum_numbers(i1, i2):
return i1+i2
def print_sum(i1, i2, i3):
print "%d + %d = %d" % (i1, i2, i3)
v1, v2 = read_numbers()
sum = sum_numbers(v1, v2)
print_sum(v1, v2, sum)
它具有三个功能 - 一个从标准输入读取两个数字,另一个将它们相加,第三个打印操作。定义函数后,我以读取两个数字并打印其总和的方式调用它们。相当容易。如果我执行它,我会得到这样的结果:
$ python sum.py
12
34
12 + 34 = 46
现在,假设我需要编写另一个程序,它只读取一个数字 - 实际上给出了另一个数字。因为我已经有了一个sum_numbers()
函数和一个print_sum()
函数,所以我很想重用sum
模块,这是一件好事:
import sum
MY_FIXED_NUMBER=3
n = int(raw_input())
value = sum.sum_numbers(n, MY_FIXED_NUMBER)
print_sum(n, MY_FIXED_NUMBER, value)
太棒了!但是,如果我执行它,我得到了什么?这个:
$ python three_sum.py
12
34
12 + 34 = 46
12
12 + 3 = 15
哇?!程序要求我输入两个数字,打印它们的总和,然后要求输入第三个数字,它的总和正确为 3。我只是想被要求输入第三个数字,然后打印总和与 3!发生了什么?
碰巧,当我导入一个模块(例如import sum
)时,它里面的所有代码都会被执行。所以,我的模块有两个部分,一个定义可以在其他地方使用的有用函数(我将其称为定义部分),另一个部分是它以某种方式执行此函数以获得特定的结果,所以我可以将模块用作程序(我将其称为执行部分)。执行部分总是被执行。
幸运的是,Python 有一个技巧可以让我仅在 未 导入模块时才执行执行部分。如果我使用import
导入一个Python 文件,该模块将有一个名为__name__
的变量,其名称将是模块的原始名称:
>>> import sum
12
34
12 + 34 = 46
>>> sum.__name__
'sum'
但是,如果我将 Python 文件作为脚本 ($ python sum.py
) 运行,__name__
变量将在那里,但名称不同。假设我添加了一行,例如
print __name__
在我的sum.py
末尾。当我再次运行它时,我得到了它:
$ python sum.py
12
34
12 + 34 = 46
__main__
另一方面,如果我运行three_sum.py
,print __name__
的结果会大不相同:
$ python three_sum.py
12
34
12 + 34 = 46
sum
12
12 + 3 = 15
是的,将文件作为脚本运行时__name__
变量的值是__main__
。
那么,这对我有什么帮助?这样:我会将模块的执行部分放在if
条件中。如果模块的名称是__main__
,那是因为该文件作为带有$ python sum.py
的脚本运行——在这种情况下,我应该执行我的模块的执行部分。所以我的sum.py
模块现在是这样的:
def read_numbers():
n1 = int(raw_input())
n2 = int(raw_input())
return n1, n2
def sum_numbers(i1, i2):
return i1+i2
def print_sum(i1, i2, i3):
print "%d + %d = %d" % (i1, i2, i3)
if __name__ == "__main__":
v1, v2 = read_numbers()
sum = sum_numbers(v1, v2)
print_sum(v1, v2, sum)
如果我运行$ python sum.py
,我会得到和以前一样的结果:
$ python sum.py
12
34
12 + 34 = 46
但是,如果我运行three_sum.py
,一切都会不同:
$ python three_sum.py
12
12 + 3 = 15
现在这可以按预期工作。之所以这样,是因为第一次执行的模块名是__main__
,所以会执行if __name__ == "__main__"
下的命令。但是在第二次执行中,模块名称为sum
,所以if
下的命令并没有被执行。
即使您的文件不是设计为导入的,将文件的执行部分放在if __name__ == "__main__"
下仍然是一个好习惯,因此您的文件很容易适应成为模块.
【讨论】:
哦,@BrenBarn 给了我一个很好的答案 :) 我会离开我的,因为它的方法略有不同。 +1 以获得如此详细的解释!谢谢你。逐步完成所有内容(以及代码示例)非常有帮助。我会多次重温。以上是关于Python 中关于 __main__ 的概念探究的主要内容,如果未能解决你的问题,请参考以下文章
python中关于不执行if __name__ == '__main__':测试模块的解决
[Python]解决python3中关于import的疑难杂症