Python中的“样板”代码是什么?

39

谷歌有一个Python教程,他们将样板代码描述为“不幸的”,并提供了以下示例:

#!/usr/bin/python

# import modules used here -- sys is a very standard one
import sys

# Gather our code in a main() function
def main():
  print 'Hello there', sys.argv[1]
  # Command line args are in sys.argv[1], sys.argv[2] ..
  # sys.argv[0] is the script name itself and can be ignored

# Standard boilerplate to call the main() function to begin
# the program.
if __name__ == '__main__':
  main()

我听说过模板代码被描述为“看起来重复的代码,一次又一次地出现,以获得某些似乎应该更简单的结果”(例子)。

无论如何,在Python中,上述示例中被认为是“模板”的代码部分是:

if __name__ == '__main__':
  main()
现在,我的问题如下:
1)Python中的样板代码(如提供的示例)是否与我提供的定义具有相同的定义?如果是这样,为什么?
2)这段代码甚至是否必要?在我看来,无论是否有一个主方法,代码似乎都可以运行。使用这段代码有什么优点?它真的更好吗?
3)为什么我们使用那段代码,它提供了什么服务?
4)在Python中是否经常出现这种情况?还有其他“样板代码”的例子吗?
哦,还有一个题外话:在Python中需要import sys 来使用命令行参数吗?如果没有,它是如何处理这些参数的?

4
无论是否导入,sys都存在。如果您不导入它,您就无法在代码中使用它。 - Ignacio Vazquez-Abrams
关于这个特定的样板代码,我想说一下,你应该始终使用 #!/usr/bin/env python 而不是 !#/usr/bin/python,因为前者可以获取用户/环境特定的 Python 版本。这种方式更可取,因为用户可能会将 Python 命名为其他名称或安装在除了 /bin 之外的其他位置,虽然通常情况下都不会如此。但是,作为一个曾经因此遇到过错误的人,我可以告诉你,这些错误非常令人沮丧。这就像硬编码路径和使用相对路径之间的区别。 - guribe94
例如Python 2和3的样板文件,请查看python-boilerplate.com - Chris Hager
一个重要的用途是,所有从 main() 运行的函数和类都会被提升。这在像 nodejs 这样的语言中自然发生,并且如果用户希望 main() 坐在脚本顶部调用下面的其他函数时非常有用。 - D.L
8个回答

26
  1. 在这个意义上,它是重复的,因为它会针对您可能从命令行执行的每个脚本重复出现。
  2. 如果您将主代码放入此类函数中,则可以导入模块而无需执行它。这有时很有用。它也使事情更加有条理。
  3. 据我所知,与#2相同
  4. Python通常非常擅长避免样板文件。它足够灵活,以至于在大多数情况下,您可以编写代码来生成样板文件,而不是编写样板文件代码。

离题问题:

如果您不编写代码来检查参数,则会忽略它们。


9
在这种情况下,if __name__ == "__main__":块被称为样板文件的原因是,在许多其他语言中,它复制了一种自动功能。在Java或C++等语言中,当您运行代码时,它会寻找main()方法并运行它,甚至会抱怨它不存在。Python运行文件中的任何代码,因此您需要告诉它运行main()方法;一个简单的替代方案是将运行main()方法作为默认功能。
因此,if __name__ == "__main__":是一种常见模式,可能会更短。您也可以使用不同的方法,比如:
if __name__ == "__main__":
  print "Hello, Stack Overflow!"

  for i in range(3):
    print i

  exit(0)

这会很好用;尽管我的例子有点傻,但你可以看到你可以放任何你喜欢的东西。Python设计者选择了这种行为而不是自动运行main()方法(该方法可能不存在),可能是因为Python是一种“脚本”语言;所以你可以直接将一些命令写入文件,运行它,然后你的命令就会执行。我个人更喜欢Python的方式,因为对于初学者来说,这使得在Python中启动变得更容易,并且拥有一个只需要一行代码就能输出"Hello World"的语言总是很好的。

1
我见过一些模块,如果直接运行它们,会运行测试,并且我自己有时也使用相同的方法。这非常方便,可以确保在开发过程中不会出现问题。当作为模块导入时,当然不会运行测试。 - kindall

3
您不需要为那些不打算作为较大项目的一部分使用的单次脚本添加if __name__ == '__main__'。请参阅这里获取详细解释。只有当您想要运行该文件本身并将其与其他Python文件一起作为模块包含时,才需要此语句。
如果您只想运行一个文件,则可以没有任何样板文件:
print 1

运行代码,使用$ python your_file.py

添加shebang行 #!/usr/bin/python 并运行chmod +x print_one.py,就可以使用以下方式运行:

./print_one.py

最后,# coding: utf-8 允许您在文件中添加Unicode字符,如果您想在文件中添加❤等特殊字符。


3
您使用“if main”检查的原因是可以让模块在顶层运行部分代码(创建它导出的常量、函数或类),并且只有在作为脚本执行时才运行某些部分(例如单元测试功能)。
后面应该将后面的代码包装在一个函数中,因为main()代码块的局部变量会泄漏到模块作用域中。
现在,替代设计可能是文件作为脚本执行时必须声明一个名为__main__()的函数,但这意味着向语言添加一个新的魔术函数名称,而__name__机制已经存在。(并且不能被移除,因为每个模块都必须有一个__name__,以及由于分配模块名称的方式,作为脚本执行的模块必须具有“特殊”名称。)引入两种执行相同任务的机制,仅仅是为了去掉两行样板代码 - 通常是每个应用程序两行样板代码 - 看起来不值得。

2

我来到这个页面的主要原因是一个类似于你的问题#3的问题:

我们为什么要使用那段代码,它提供了什么服务?

我阅读了这些解释,尽管答案非常详细,但我仍然无法理解这个概念。在阅读完这些解释后,我不得不通过一个小例子来实际操作,才真正理解发生了什么。

这就是最后让我明白的东西:

# code that runs regardless if it's ran 
# by itself or if it's imported 

if __name__ == "__main__":
    # code that runs only if this file is ran by itself

希望这对某人有所帮助

1

1) 主要的样板代码是通用的,但不能再简单了

2) 没有样板代码就无法调用 main()

3) 样板代码允许模块既可以作为独立脚本使用,也可以作为其他程序中的库使用

4) 这非常普遍。另一个例子是 doctest

努力成为 Python 大师……祝你论文好运! ;-)


0

对于“样板代码(boilerplate code)”这个词我感到非常困惑:它是否意味着可以在简单的脚本中避免此类代码?或者是对Python特性的批评,这些特性强制使用这种语法?甚至是鼓励使用这种“样板”代码的邀请?

然而,经过多年的Python编程,我至少清楚了不同语法的作用,尽管可能仍不确定什么是最佳实践。

通常你需要在脚本末尾加上测试代码或者想要执行的代码,但这会带来一些影响/副作用:

  1. 当脚本被导入时,该代码将会被执行,这很少是我们想要的。
  2. 代码中的变量和值被定义并导出到调用命名空间。
  3. 脚本末尾的代码可以通过调用脚本 (python script.py) 或从ipython shell运行 (%run script.py) 来执行,但没有办法从其他脚本中运行它。

避免在所有情况下执行后续代码的最基本机制是以下语法:

if __name__ == '__main__':

这使得代码仅在调用或运行脚本时运行,避免问题1。另外两个点仍然成立。

使用单独的main()函数的“样板”代码添加了进一步的步骤,还排除了上述第2和第3点,因此您可以从不同的脚本中调用多个测试,有时可以再增加一级(例如:多个函数,每个测试一个函数,因此它们可以从外部逐个调用,并且主要调用所有测试函数,无需从外部了解它们是哪个函数)。

我补充说,我发现这种结构通常令人不满意的主要原因是,除了其复杂性之外,有时我想保持第2点,如果将代码移到单独的函数,则会失去这种可能性。


0

让我们花点时间看看当您调用import sys时发生了什么:

  • Python查看列表并引入sys模块
  • 它找到argv函数并运行它

那么,这里发生了什么?

在当前程序的范围内使用编写在其他地方的函数来执行某些操作。以这种方式进行编程有很多好处。它将逻辑与实际工作分开。

现在,就样板而言,有两个部分:

  • 程序本身(逻辑),在main下定义,和
  • 检查main是否存在的调用部分

您基本上在main下编写程序,使用在定义main之前(或其他地方)定义的所有函数,并让Python查找main


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接