有没有办法将参数选择作为单个字符串接受

2024-10-02 20:31:49 发布

您现在位置:Python中文网/ 问答频道 /正文

我想处理给定参数的一系列选择,而不是多次指定参数或使用空格。你知道吗

我有一个显示视频文件元数据的脚本。大多数时候我只需要文件列表,但偶尔我需要查看文件的持续时间、大小、比特率等

最初,我对每个元数据都有一个参数。-l表示长度或持续时间,-d表示创建日期,-m表示修改日期,-b表示比特率,-r表示分辨率,-c表示音频通道,-s大小,-e表示所有内容,等等。。。我可以指定一些或全部或无,并得到确切的信息,我是在后面,但参数列表开始变得非常不规则,因为我添加了元数据显示和附加功能,我开始用完了逻辑字母分配,并开始交换参数名,我想要一个更好的方法。你知道吗

我希望简化元数据的表达,并考虑将一些参数合并为一个参数,减少最终命令的长度和所涉及的键入。你知道吗

具体来说,我正试图扭转这种局面:

script.py -d -t -l -s -b -r -f -c -v -a

对此:

script.py -m dtlsbrfcva

以下是我当前的功能:

def get_arguments():
    parser = argparse.ArgumentParser(description=DESCRIPTION)
    parser.add_argument('-m', action='append', nargs='+', choices=['d','t','l','s','b','r','f','c','v','a','e'],help='Display metadata for each file. Choices: (d)ate, (t)ime, (l)ength, (s)ize, (b)itrate, (r)esolution, (f)ramerate, (c)hannels, (v)ideo codec, (a)spect ratio, (e)verything')
    parser.add_argument('files', nargs='*')
    args = parser.parse_args()

    if len(args.files) == 0:
        args.files="."

    return args

使用choices似乎是解决这个问题的方法,但是当我对操作使用“append”,对nargs使用“+”时,我要么需要重新指定参数

script.py -md -mt -ml -ms -mb -mr -mf -mc -mv -ma

更糟的是。。。 或者使用空格

script.py -m d t l s b r f c v a

我想哪一个好一点?你知道吗

但我确实得到了有益的帮助:

 -m {d,t,l,s,b,r,f,c,v,a,e} [{d,t,l,s,b,r,f,c,v,a,e} ...]
                        Display metadata for each file. Choices: 
                        (d)ate, (t)ime, (l)ength, (s)ize, (b)itrate, 
                        (r)esolution, (f)ramerate, (c)hannels, (v)ideo codec, 
                        (a)spect ratio, (e)verything

现在说清楚,如果我用

add_argument('-m', action="store", help='Display metadata for each file. Choices: (d)ate, (t)ime, (l)ength, (s)ize, (b)itrate, (r)esolution, (f)ramerate, (c)hannels, (v)ideo codec, (a)spect ratio, (e)verything')

相反,我可以得到一个字符串,我可以分裂和处理自己,但这样的帮助不大。。。你知道吗

 -m M          Display metadata for each file. Choices: (d)ate, (t)ime,
                (l)ength, (s)ize, (b)itrate, (r)esolution, (f)ramerate,
                (c)hannels, (v)ideo codec, (a)spect ratio, (e)verything

我也研究过subparser,但从我所做的阅读来看,我只会将我的问题扩展到不同的代码层,并使我的帮助输出不那么有用。我很高兴纠正这一点。你知道吗

理想情况下,我希望坚持使用argparse选项以获得编程上的好处,包括错误选项的错误和格式良好的帮助,但我对其他方法持开放态度。非常感谢您的指导。你知道吗


Tags: 数据pyparserfor参数displayscriptargs
3条回答

这将接受-m,后面可能跟一个由与选项对应的字母组成的字符串。你知道吗

import argparse

MCHOICES = 'dtlsbrfcvae'
def msplit(marg):
    mlist = list(marg)
    for ch in mlist:
        if ch not in MCHOICES:
            raise argparse.ArgumentTypeError(f"{ch} is not a valid choice")
    return mlist


parser = argparse.ArgumentParser(description="<put description here>")
parser.add_argument('-m', type=msplit, nargs='?', const=[], default=[], help='Display metadata for each file...')

# some examples:
args = parser.parse_args("-m dtlsv".split())
print(args)
args = parser.parse_args("-m".split()) # const=... is used in this case (bare -m)
print(args)
args = parser.parse_args("".split()) # default=... is used in this case (no -m at all)
print(args)

更新:

当设置默认值时,字符串被当作参数处理。非字符串是直接赋值的,它们不被mlist处理。例如,要使“-me”成为默认的元数据选择,请使用default='e'default=['e'](以及const=...)。(感谢@hpaulj的评论)


此选项使带选项的字符串成为必需的:

parser.add_argument('-m', type=msplit, default=[], help='Display metadata for each file...')

如果有人好奇的话,下面是我(可能)不必要的复杂实现。你知道吗

就行为而言,我的选项列表位于dict中,因此我可以添加或删除项,而无需修改任何argparse代码或帮助字符串。它为帮助信息构建必要的字符串,并从dict生成一个要比较的列表

然后,它将输入字符串与可用选项列表进行比较,并构建一个新的列表,以根据特定规则迭代并执行相应的函数。你知道吗

-m假定-me变成-mdtlsbrfcvae并转换为列表。
不管给出了什么,如果字符串中根本没有“e”,请将list设置为等于所有元数据选项。你知道吗

对-m进行适当的语法分析,必要时给出错误。你知道吗

metadata_options={'d':'date',
                  't':'time',
                  'l':'length',
                  's':'size',
                  'b':'bitrate',
                  'r':'resolution',
                  'f':'framerate',
                  'c':'channels',
                  'v':'video codec',
                  'a':'aspect ratio',
                  'e':'everything'}

def metadata_option_extractor():
    metadata_choices=[]
    metadata_options_string=''
    punct=''
    last=len(metadata_options)
    count=0
    for choice,description in metadata_options.items():
        metadata_choices.append(choice)
        word=list(description)
        word.insert(0, '(')
        word.insert(2, ')')
        description = "".join(word)
        count += 1
        if count < last:
            punct=','
        else:
            punct='.'
        metadata_options_string += description + punct + ' '
    return metadata_choices,metadata_options_string

metadata_choices,metadata_options_string=metadata_option_extractor()

def msplit(mlist):
    new_mlist=[]
    for ch in mlist:
        if ch not in metadata_choices:
            raise argparse.ArgumentTypeError(f"invalid choice: '{ch}' in '{mlist}' (choose from "+str(metadata_choices)+")")

        else:
            new_mlist.append(ch)

    if 'e' in new_mlist:
        new_mlist = metadata_choices

    return new_mlist

def get_arguments():
    parser = argparse.ArgumentParser(description=DESCRIPTION)
    parser.add_argument('-g', action='store', default='d', nargs=1, choices=['d', 'l', 't', 'b'], help='Group by various criteria. (d)ate, (t)ime, (l)ength, (b)itrate. Default: Date')
    parser.add_argument('-m', type=msplit, nargs='?', const='e', help='Display metadata for each file. When given without any options it is taken to mean all options. Choices: '+metadata_options_string)
    parser.add_argument('-n', nargs='*', action='store', help='Go back only n many groups (typically days). A second argument may be added to limit the number of grouped results.', type=int)
    parser.add_argument('-r', action='store_true', help='Recurse subdirectories.')
    parser.add_argument('-s', action='store', help='Search for "Word(s)", separated by commas, in filenames.', type=str)
    parser.add_argument('-a', action='store_true', help='Switch search method from OR to AND. Requires -s')
    parser.add_argument('-x', action='store_true', help='Export filenames in quotes as a single line for use with another program.')
    parser.add_argument('-c', action='store_true', help='Count number of videos by group rather than list the videos.')

    parser.add_argument('files', nargs='*')
    args = parser.parse_args()

    # Default behaviour
    if len(args.files) == 0:
        args.files="."

    return args

将单个选项叠加在一起是完全可以接受的。因此:

script.py -d -t -l -s -b -r -f -c -v -a

可以等效地调用为:

script.py -dtlsbrfcva

这可能会解决您的问题,而无需任何更改。你知道吗

相关问题 更多 >