argparse:位置参数之间的可选参数

7

我希望模仿大多数命令行工具的行为,其中可选参数可以放置在命令行中的任何位置,包括位置参数之间,例如这个mkdir示例:

mkdir before --mode 077 after

在这种情况下,我们知道--mode需要恰好1个参数,因此beforeafter都被视为位置参数。可选部分--mode 077可以放置在命令行的任何位置
然而,使用argparse时,以下代码在这个例子中不起作用:
# mkdir.py
import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--mode', nargs=1)
parser.add_argument('dirs', nargs='*')
args = parser.parse_args()

运行 ./mkdir.py before --mode 077 after 会得到以下结果:

mkdir.py: error: unrecognized arguments: after

我该如何让argparse接受一个可选参数(带有固定、已知数量的项目),放在定位参数之间?


1
准确来说,不是“大多数”实用程序,而是使用库不将第一个非可选参数视为选项结束的实用程序(例如GNU getopts)。 - chepner
1
argparse 不支持这种风格。 - chepner
2个回答

6
Python 3.7开始,似乎argparse现在支持这种类Unix风格的解析方式:
混合解析 ArgumentParser.parse_intermixed_args(args=None, namespace=None) 许多Unix命令允许用户将可选参数与位置参数混合使用。 parse_intermixed_args()parse_known_intermixed_args()方法支持此解析样式。
但是需要注意的是,对于“简单”选项,它并不影响它们:
这些解析器不支持所有argparse功能,并且如果使用不受支持的功能,则会引发异常。 特别是,不支持子解析器,argparse.REMAINDER以及包括可选参数和位置参数的互斥组。
我在阅读Python的argparse文档示例时花费了1个小时,却无法理解其中的内容。后来偶然发现了一个略微不相关的问题,其中包含这个"intermixed"函数的提及,但我无法再次找到它以正确引用。以下是我发布的类似FAQ的问题。

这个解析器有点笨拙,是在常规的parse_known_args基础上运行的。它“停用”位置参数,解析可选参数,并单独处理“额外参数”。详见方法代码。正如所述,它是作为新功能添加到3.7版本中的。它不会修改常规解析。 - hpaulj

-3

我不熟悉argparse,所以我会编写自己的代码来处理参数。

import sys

#the first argument is the name of the program, so we skip that
args = sys.argv[1:]
#just for debugging purposes:
argsLen = len(args)
print(args, argsLen)

#Create a list that will contain all of the indeces that you will have parsed through
completedIndeces = []
i = 0

#add the index to the completed indeces list.
def goToNextIndex(j):
    global i
    completedIndeces.append(j)
    i += 1

def main():
    global i
    ###core logic example
    #Go through each item in args and decide what to do based on the arugments passed in
    for argu in args:
        if i in completedIndeces:
            print("breaking out")
            #increment i and break out of the current loop
            i += 1
            # If the indeces list has the index value then nothing else is done.
            pass 
        elif argu == "joe":
            print("did work with joe")
            goToNextIndex(i)
        elif argu == "sam":
            print("did work with sam")
            goToNextIndex(i)
        elif argu == "school":
            print("going to school")
            goToNextIndex(i)

            # If the argument has other arguments after it that are associated with it 
            # then add those indeces also to the completed indeces list. 
    
            #take in the argument following school
            nextArg = i
            #Do some work with the next argument
            schoolName = args[nextArg]
            print(f"You're going to the school called {schoolName}")
            #make sure to skip the next argument as it has already been handled
            completedIndeces.append(nextArg)
        else:
            print(f"Error the following argument is invalid: {argu}")
            goToNextIndex(i)


    print(f"Value of i: {i}")
    print(f"completed indeces List: {completedIndeces}")

main()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接