【问题标题】:Is it bad practice to have arguments called in main() in Python在 Python 的 main() 中调用参数是不好的做法吗
【发布时间】:2019-04-11 18:55:59
【问题描述】:

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

我知道它有效,但我想知道这是否是糟糕的编程习惯。抱歉,如果这是重复的,但我看不到专门针对 Python 回答的问题。

【问题讨论】:

  • 这是一个主要基于意见的问题。但不,这不是坏习惯。无论如何,在 Python 中,名为 main 的函数没有特殊状态。
  • 我们能否停止以基于意见的方式关闭设计问题,拜托-.- 只需回答“没有一个选项天生就比另一个更好”,然后繁荣,这是一个有用的问题,有一个有用的答案。
  • main() 只是一个命名约定,你在那里做什么并不重要,另一方面,if __name__ == '__main__': 块应该是最小的,以便在导入模块时不会丢失功能
  • @Aran-Fey 完全同意,在 Python 中,即使答案不清楚,最佳实践问题也可以,但显然不是每个人都这么认为,请参阅 meta.stackoverflow.com/questions/376232/…
  • @Chris_Rands,是的,这是一种可悲的状况。 Python 风格/设计 IMO 是学习该语言的巨大部分,即使它在技术上是固执己见的。 Python 代码旨在阅读,而不是编译和永远被遗忘。

标签: python main


【解决方案1】:

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

int main(char *argv[], int argc)

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

import sys

def main():
    print(sys.argv, len(sys.argv))

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

import sys

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

if __name__ == '__main__':
    main(sys.argv, len(sys.argv))

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

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

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

第 2 点可能看起来很有意义,但你可以在实践中这样做:

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

if __name__ == '__main__':
    x = 4
    y = 5
    main(x, y)

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

【讨论】:

  • 您的第二个 sn-p 是我放置 sys.argv[1]sys.argv[2] 而不是 xy 的位置
  • 我不喜欢你的第一个 sn-p 因为sys.argv 在你导入模块时是空的,我认为main() 的想法是它可以在模块执行时调用或导入时
  • @Chris_Rands 啊。我明白你在说什么。让我编辑
【解决方案2】:

按照模式:

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

if __name__ == '__main__':
    main()

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

见:https://setuptools.readthedocs.io/en/latest/setuptools.html#automatic-script-creation

您可以在setup.py 中添加类似:

entry_points={
    'console_scripts': [
        'my_script = my_module:main'
    ]
}

然后当你构建一个包时,人们可以在他们的虚拟环境中安装它,并立即在他们的路径上获得一个名为 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()

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

cmets 中提到了这篇博文:https://www.artima.com/weblogs/viewpost.jsp?thread=4829,它在 main 上使用默认参数来允许依赖注入进行测试,但是,这是一篇非常古老的博文(getopt 库从那时起已经被取代了两次) 我认为这种模式更胜一筹。

【讨论】:

  • 像这样的自动脚本创建需要一个不带参数的函数 ...不完全是。你可能会做def main(argv=None):
  • 这样做有什么意义?从自动生成的脚本调用时不会传递 argv。但是,是的,这应该说一个*需要*没有参数的函数
  • 我已经看到使用这种模式,以便测试可以显式地传递 argv 列表,而不需要对 sys.argv 的内容进行猴子补丁。对我来说似乎是一个足够合理的方法。
  • Guido 自己在他的博客上推荐它:artima.com/weblogs/viewpost.jsp?thread=4829
  • 好的,依赖注入似乎是一件合理的事情,尽管我个人可能只是制作 main 构造 args 并将其传递给其他东西,然后测试该函数,所以你没有条件这会改变被测行为。
【解决方案3】:

我肯定更愿意看到main 接受参数,而不是直接访问sys.argv

这使得其他 Python 模块对 main 函数的重用变得更加容易。

import sys

def main(arg):
    ...

if __name__ == "__main__":
    main(sys.argv[1])

现在,如果我想将此模块作为脚本从另一个模块执行,我可以编写(在我的另一个模块中)。

from main_script import main

main("use this argument")

如果main 使用sys.argv,这就更难了。

【讨论】:

  • 其他模块不应该直接使用main。在解析完任何参数之后,他们应该使用 main 委托给的相同库代码。开发人员应努力将 API 与 CLI 分离。
猜你喜欢
  • 2021-09-24
  • 1970-01-01
  • 2020-07-26
  • 2016-08-17
  • 1970-01-01
  • 2021-06-16
  • 2012-12-15
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多