在Python中使用main()调用参数是不好的做法

Cap*_*oom 6 python program-entry-point

函数名是否应该main()为空并且在函数本身内调用参数,或者将它们作为函数的输入是否可接受main(arg1, arg2, arg3)

我知道它有效,但我想知道它是不是很糟糕的编程习惯.如果这是重复的道歉,但我看不出专门针对Python的问题.

Ter*_*ryA 9

在大多数其他编程语言中,您要么有零个参数,要么有两个参数:

int main(char *argv[], int argc)
Run Code Online (Sandbox Code Playgroud)

表示传递给参数的参数。但是,在 Python 中,这些是通过sys模块访问的:

import sys

def main():
    print(sys.argv, len(sys.argv))
Run Code Online (Sandbox Code Playgroud)

但是你可以扩展它,这样你就可以将 argv 和 argc 传递到你的 python 函数中,类似于其他语言是的:

import sys

def main(argv, arc):
    print(argv, arc)

if __name__ == '__main__':
    main(sys.argv, len(sys.argv))
Run Code Online (Sandbox Code Playgroud)

但是让我们暂时忘记 argv/argc -为什么要将某些内容传递给 main。您在 main 之外创建了一些东西,并希望将它传递给 main。这可能发生在两种情况下:

  1. 您从其他函数多次调用 main 。
  2. 您已经在main要传递的外部创建了变量。

第 1 点绝对是不好的做法。main应该是唯一的并且只在程序开始时调用一次。如果需要多次调用,那么里面的代码main就不属于 inside main。把它分开。

第 2 点可能看起来有道理,但是您在实践中这样做:

def main(a, b):
    print(a, b)

if __name__ == '__main__':
    x = 4
    y = 5
    main(x, y)
Run Code Online (Sandbox Code Playgroud)

但是不是xy全局变量吗?好的做法是假设这些位于文件的顶部(以及多个其他属性 - 它们是常量等),并且您不需要将它们作为参数传递。


Spo*_*ser 8

通过遵循以下模式:

def main():
    ...stuff...

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

它允许您的脚本直接运行,并且如果使用安装工具打包,则可以在通过指定 main 作为入口点安装包时自动生成可执行脚本。

请参阅:https ://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation

您可以添加setup.py以下内容:

entry_points={
    'console_scripts': [
        'my_script = my_module:main'
    ]
}
Run Code Online (Sandbox Code Playgroud)

2023 编辑:诗歌等较新的打包工具也遵循相同的模式:https ://python-poetry.org/docs/pyproject#scripts

然后,当您构建一个包时,人们可以将其安装在他们的虚拟环境中,并立即在他们的路径上调用一个脚本my_script

像这样的自动脚本创建需要一个不带必需参数的函数。

允许导入脚本并公开其功能以供代码重用和测试是一个好主意。我会推荐一些符合这种模式的东西:

import argparse

def parse_args():
    parser = argparse.ArgumentParser()
    #
    # ... configure command line arguments ...
    #
    return parser.parse_args()

def do_stuff(args):
    #
    # ... main functionality goes in here ...
    #

def main():
    args = parse_args()
    do_stuff(args)

if __name__ == '__main__':
    main()
Run Code Online (Sandbox Code Playgroud)

这允许您直接运行脚本,自动生成一个行为相同的脚本,还可以导入脚本并调用do_stuff以重用或测试实际功能。

评论中提到了这篇博文:https://www.artima.com/weblogs/viewpost.jsp ?thread=4829,它使用 main 上的默认参数来允许依赖注入进行测试,但是,这是一个非常古老的博客邮政; 从那时起,该getopt图书馆已被取代两次。这种模式更优越,并且仍然允许依赖注入。