使用一些可选参数运行 python 脚本

Posted

技术标签:

【中文标题】使用一些可选参数运行 python 脚本【英文标题】:Run python script with some of the argument that are optional 【发布时间】:2015-04-13 07:27:57 【问题描述】:

我已经浏览了sys 文档,但是我仍然不清楚。我在 *** 上寻找了一些类似的问题,但我没有找到任何有用的东西(显然任何参考都值得赞赏!)。

我想创建一个脚本——比如foo.py——我想在其中传递 3 到 6 个参数:

$ python foo.py arg1 arg2 arg3

在任何情况下都必须给出前 3 个参数;如果没有传递任何参数,则最后 3 个参数用于具有默认参数值的函数。

问题是我该怎么做?到目前为止,我正在考虑编写类似以下内容的内容foo.py(这是一个简单的示例,仅用于提供具体的内容来支持我的问题):

import sys

def example(credit_mom, credit_dad, debt_mom, debt_dad = 1000,
            salary = 2000, bonus = 0):
    total_gain = salary + credit_dad + credit_mom + bonus
    total_loss = debt_dad + debt_mom

    return total_gain - total_loss

if __name__ == '__main__':
    if len(sys.argv) < 4:
        sys.exit('Need at least 3 arguments. The order is as follows:\n\
            1.credit_mom;\n\
            2.credit_dad;\n\
            3.debt_mom;\n\
            4.others')
    else:
        sys.exit(example(sys.argv[1],
                         sys.argv[2],
                         sys.argv[3],
                         sys.argv[4],
                         sys.argv[5],
                         sys.argv[6]))

如果我运行这个脚本,我显然会得到一个IndexError 异常:

$ python foo.py 110 110 220
Traceback (most recent call last):
  File "foo.py", line 19, in <module>
    sys.argv[4],
IndexError: list index out of range

【问题讨论】:

我建议你使用argparse(和here is the tutorial)。省去您手动检查参数是否存在的麻烦。 谢谢!我立即开始学习教程 【参考方案1】:

除了使用argparse(我推荐)之外,这可以通过切片和扩展来解决:

    sys.exit(example(*sys.argv[1:7]))

切片将仅包含实际存在的元素,即使不足以满足请求的切片大小。

【讨论】:

所以,例如,sys.argv[4] 将是 None? 没有。它不会存在,所以sys.argv[1:7] 将是[110, 110, 220]【参考方案2】:

使用 Argparse

我建议你使用argparse(和here is the tutorial)。省去您手动检查参数是否存在的麻烦。此外,argparse 为您提供--help 参数作为免费赠品,如果提供,它将读取为每个参数定义的help="" 字符串。

示例程序

在您的情况下,您有三个强制(位置)参数和三个可选参数。示例 argparse 代码如下所示:

#!/usr/bin/python
# coding: utf-8

import argparse

def parseArguments():
    # Create argument parser
    parser = argparse.ArgumentParser()

    # Positional mandatory arguments
    parser.add_argument("creditMom", help="Credit mom.", type=float)
    parser.add_argument("creditDad", help="Credit dad.", type=float)
    parser.add_argument("debtMom", help="Debt mom.", type=float)

    # Optional arguments
    parser.add_argument("-dD", "--debtDad", help="Debt dad.", type=float, default=1000.)
    parser.add_argument("-s", "--salary", help="Debt dad.", type=float, default=2000.)
    parser.add_argument("-b", "--bonus", help="Debt dad.", type=float, default=0.)

    # Print version
    parser.add_argument("--version", action="version", version='%(prog)s - Version 1.0')

    # Parse arguments
    args = parser.parse_args()

    return args

def example(credit_mom, credit_dad, debt_mom, debt_dad = 1000, salary = 2000, bonus = 0):
    total_gain = salary + credit_dad + credit_mom + bonus
    total_loss = debt_dad + debt_mom

    return total_gain - total_loss

if __name__ == '__main__':
    # Parse the arguments
    args = parseArguments()

    # Raw print arguments
    print("You are running the script with arguments: ")
    for a in args.__dict__:
        print(str(a) + ": " + str(args.__dict__[a]))

    # Run function
    print(example(args.creditMom, args.creditDad, args.debtMom, args.debtDad, args.salary, args.bonus))

【讨论】:

正确使用 argparse 可以很好地模拟终端行为,所以我也推荐使用内置的 argparse。 澄清一下,1.这段代码必须在__name__==之后... 2.parser.add_argument的顺序必须与我在命令行中传递参数的顺序相匹配. 3. 如果参数之一是字符串,我会这样做:parser.add_argument("creditMom" help="Credit mom.", type=string),相应的命令行参数将是 'something'(不是 something)。这些考虑对吗? 另外,这种情况下的函数必须定义为def example(*args)。在if __name__== 中,在你的代码行之后,我将简单地执行example(args)。对吗? @rafforaffo args = parser.parse_args() 返回一个名为argsNamespace() 对象,它不应与*args 一起“解包”。但是,您可以通过执行 args.creditMomargs.bonus 来引用各个已解析的参数,例如。最后是的位置参数,作为名称建议,必须使用parser.add_argument() 定义,以便将它们传递给python脚本。然而,可选参数不需要。请参阅我的更新答案。 ;) @rafforaffo 我很高兴。 :) 请注意,可能有一种 Pythonic 方式来解开 *** Namespace() 对象。我从来没有调查过这个,但你可以。 :)【参考方案3】:

您的函数“示例”很好。问题是您正在尝试读取不存在的 sysargs。尝试检查它们是否为空(在 else 子句中)。

【讨论】:

不是他们“不存在”,而是sys.argv中的职位不存在 是的,例如sys.argv[4] 不存在/不存在。 确实,这个问题旨在了解在大多数情况下最后 3 个参数不存在时如何执行此操作。【参考方案4】:

虽然我支持 argparse 方法,但这是一种快速而肮脏的方法:

arg1, arg2, arg3 = [None, False, []]
if sys.argv[1:]:   # test if there are atleast 1 argument (beyond [0])
    arg1 = sys.argv[1]
    if sys.argv[2:]:
        arg2 = sys.argv[2]  # careful 'True' is a string, not a boolean
        arg3 = sys.argv[3:]  # rest

当我开始向脚本添加参数解析时,我通常会使用它,而我的参数选择还没有成熟。它更适合“位置”而不是“可选”(使用 argparse 术语)。

【讨论】:

以上是关于使用一些可选参数运行 python 脚本的主要内容,如果未能解决你的问题,请参考以下文章

python argparse - 我可以只使用互斥的可选参数还是有更好的方法

在 Python 脚本中采用命令行参数的最佳方式

Python 选项解析器:带有可选参数的布尔标志

接受可选参数的Shell脚本[重复]

将可选路径参数传递给 ant

存储可选管道多行字符串和可选参数的批处理脚本