解析 Python 中的空选项

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1229146/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 21:44:10  来源:igfitidea点击:

Parsing empty options in Python

pythonoptparseoptionparser

提问by directedition

I have an application that allows you to send event data to a custom script. You simply lay out the command line arguments and assign what event data goes with what argument. The problem is that there is no real flexibility here. Every option you map out is going to be used, but not every option will necessarily have data. So when the application builds the string to send to the script, some of the arguments are blank and python's OptionParser errors out with "error: --someargument option requires an argument"

我有一个应用程序,允许您将事件数据发送到自定义脚本。您只需布置命令行参数并指定哪些事件数据与哪些参数对应。问题是这里没有真正的灵活性。您绘制的每个选项都将被使用,但并非每个选项都必须有数据。因此,当应用程序构建要发送到脚本的字符串时,某些参数是空白的,并且 python 的 OptionParser 错误并显示“错误:--someargument 选项需要一个参数”

Being that there are over 200 points of data, it's not like I can write separate scripts to handle each combination of possible arguments (it would take 2^200 scripts). Is there a way to handle empty arguments in python's optionparser?

由于有超过 200 个数据点,因此我无法编写单独的脚本来处理每种可能参数的组合(这将需要 2^200 个脚本)。有没有办法在 python 的 optionparser 中处理空参数?

回答by Mark Roddy

Sorry, misunderstood the question with my first answer. You can accomplish the ability to have optional arguments to command line flags use the callbackaction type when you define an option. Use the following function as a call back (you will likely wish to tailor to your needs) and configure it for each of the flags that can optionally receive an argument:

对不起,我的第一个答案误解了这个问题。您可以在定义选项时使用回调操作类型来实现为命令行标志提供可选参数的能力。使用以下函数作为回调(您可能希望根据您的需要进行定制)并为每个可以选择接收参数的标志配置它:

import optparse

def optional_arg(arg_default):
    def func(option,opt_str,value,parser):
        if parser.rargs and not parser.rargs[0].startswith('-'):
            val=parser.rargs[0]
            parser.rargs.pop(0)
        else:
            val=arg_default
        setattr(parser.values,option.dest,val)
    return func

def main(args):
    parser=optparse.OptionParser()
    parser.add_option('--foo',action='callback',callback=optional_arg('empty'),dest='foo')
    parser.add_option('--file',action='store_true',default=False)
    return parser.parse_args(args)

if __name__=='__main__':
    import sys
    print main(sys.argv)





Running from the command line you'll see this:

从命令行运行,您将看到:

# python parser.py
(<Values at 0x8e42d8: {'foo': None, 'file': False}>, [])

# python parser.py --foo
(<Values at 0x8e42d8: {'foo': 'empty', 'file': False}>, [])

# python parser.py --foo bar
(<Values at 0x8e42d8: {'foo': 'bar', 'file': False}>, [])

回答by sth

I don't think optparsecan do this. argparseis a different (non-standard) module that can handle situations like thiswhere the options have optional values.

我不认为optparse可以做到这一点。argparse是一个不同的(非标准)模块,可以处理这样的情况,其中选项具有可选值。

With optparseyou have to either have to specify the option including it's value or leave out both.

随着optparse你必须要么必须指定,包括它的价值的选项或离开了两者。

回答by Mark Roddy

Yes, there is an argument to do so when you add the option:

是的,当您添加选项时,有一个论据可以这样做:

from optparse import OptionParser
parser = OptionParser()
parser.add_option("--SomeData",action="store", dest="TheData", default='')

Give the defaultargument the value you want the option to have it is to be specified but optionally have an argument.

默认参数指定您希望该选项具有的值,但可以选择有一个参数。

回答by mhagger

Optparse already allows you to pass the empty string as an option argument. So if possible, treat the empty string as "no value". For long options, any of the following work:

Optparse 已经允许您将空字符串作为选项参数传递。因此,如果可能,请将空字符串视为“无值”。对于长选项,以下任一项工作:

my_script --opt=   --anotheroption
my_script --opt='' --anotheroption
my_script --opt="" --anotheroption
my_script --opt '' --anotheroption
my_script --opt "" --anotheroption

For short-style options, you can use either of:

对于短样式选项,您可以使用以下任一选项:

my_script -o '' --anotheroption
my_script -o "" --anotheroption

Caveat: this has been tested under Linux and should work the same under other Unixlike systems; Windows handles command line quoting differently and might not accept all of the variants listed above.

警告:这已经在 Linux 下进行了测试,并且在其他类 Unix 系统下应该可以正常工作;Windows 以不同方式处理命令行引用,并且可能不接受上面列出的所有变体。

回答by Zac B

Mark Roddy's solution would work, but it requires attribute modification of a parser object during runtime, and has no support for alternative option formattings other than - or --. A slightly less involved solution is to modify the sys.argv array before running optparse and insert an empty string ("") after a switch which doesn't need to have arguments. The only constraint of this method is that you have your options default to a predictable value other than the one you are inserting into sys.argv (I chose None for the example below, but it really doesn't matter).

Mark Roddy 的解决方案可行,但它需要在运行时修改解析器对象的属性,并且不支持除 - 或 -- 之外的其他选项格式。稍微少一些的解决方案是在运行 optparse 之前修改 sys.argv 数组,并在不需要参数的开关之后插入一个空字符串 ("")。此方法的唯一限制是您的选项默认为可预测的值,而不是您插入到 sys.argv 中的值(我在下面的示例中选择了 None ,但这真的无关紧要)。

The following code creates an example parser and set of options, extracts an array of allowed switches from the parser (using a little bit of instance variable magic), and then iterates through sys.argv, and every time it finds an allowed switch, it checks to see if it was given without any arguments following it . If there is no argument after a switch, the empty string will be inserted on the command line. After altering sys.argv, the parser is invoked, and you can check for options whose values are "", and act accordingly.

下面的代码创建一个示例解析器和一组选项,从解析器中提取一组允许的开关(使用一点实例变量魔术),然后遍历 sys.argv,每次找到允许的开关时,它检查它是否在没有任何参数的情况下给出。如果 switch 后没有参数,则在命令行中插入空字符串。更改 sys.argv 后,将调用解析器,您可以检查值为 "" 的选项,并进行相应操作。

#Instantiate the parser, and add some options; set the options' default values to None, or something predictable that
#can be checked later.
PARSER_DEFAULTVAL = None
parser = OptionParser(usage="%prog -[MODE] INPUT [options]")
#This method doesn't work if interspersed switches and arguments are allowed.
parser.allow_interspersed_args = False
parser.add_option("-d", "--delete", action="store", type="string", dest="to_delete", default=PARSER_DEFAULTVAL)
parser.add_option("-a", "--add", action="store", type="string", dest="to_add", default=PARSER_DEFAULTVAL)

#Build a list of allowed switches, in this case ['-d', '--delete', '-a', '--add'] so that you can check if something
#found on sys.argv is indeed a valid switch. This is trivial to make by hand in a short example, but if a program has
#a lot of options, or if you want an idiot-proof way of getting all added options without modifying a list yourself,
#this way is durable. If you are using OptionGroups, simply run the loop below with each group's option_list field.
allowed_switches = []
for opt in parser.option_list:
    #Add the short (-a) and long (--add) form of each switch to the list.
    allowed_switches.extend(opt._short_opts + opt._long_opts)

#Insert empty-string values into sys.argv whenever a switch without arguments is found.
for a in range(len(sys.argv)):
    arg = sys.argv[a]
    #Check if the sys.argv value is a switch
    if arg in allowed_switches:
        #Check if it doesn't have an accompanying argument (i.e. if it is followed by another switch, or if it is last
        #on the command line)
        if a == len(sys.argv) - 1 or argv[a + 1] in allowed_switches:
            sys.argv.insert(a + 1, "")

options, args = parser.parse_args()

#If the option is present (i.e. wasn't set to the default value)
if not (options.to_delete == PARSER_DEFAULTVAL):
    if options.droptables_ids_csv == "":
        #The switch was not used with any arguments.
        ...
    else:
        #The switch had arguments.
        ...

回答by Tobias

After checking that the cpcommand understands e.g. --backup=simplebut not--backup simple, I answered the problem like this:

在检查cp命令理解 eg--backup=simple理解之后--backup simple,我回答了这样的问题:

import sys
from optparse import OptionParser

def add_optval_option(pog, *args, **kwargs):
    if 'empty' in kwargs:
        empty_val = kwargs.pop('empty')
        for i in range(1, len(sys.argv)):
            a = sys.argv[i]
            if a in args:
                sys.argv.insert(i+1, empty_val)
                break
    pog.add_option(*args, **kwargs)

def main(args):
    parser = OptionParser()
    add_optval_option(parser,
                      '--foo', '-f',
                      default='MISSING',
                      empty='EMPTY',
                      help='"EMPTY" if given without a value. Note: '
                      '--foo=VALUE will work; --foo VALUE will *not*!')
    o, a = parser.parse_args(args)
    print 'Options:'
    print '  --foo/-f:', o.foo
    if a[1:]:
        print 'Positional arguments:'
        for arg in a[1:]:
            print ' ', arg
    else:
        print 'No positional arguments'

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

Self-advertisement: This is part of the opomodule of my thebopspackage ... ;-)

自我广告:这是opo我的thebops包裹模块的一部分...... ;-)