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

argparse: optional argument between positional arguments

我想模拟大多数命令行实用程序的行为,其中可选参数可以放在命令行的任何位置,包括 between 位置参数,例如在这个 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 接受位置参数之间的可选参数(具有固定的已知数量的项目)?

Python 3.7开始,好像argparse现在支持这种Unix-style解析:

Intermixed parsing

ArgumentParser.parse_intermixed_args(args=None, namespace=None)

A number of Unix commands allow the user to intermix optional arguments with positional arguments. The parse_intermixed_args() and parse_known_intermixed_args() methods support this parsing style.

有一个警告,但对于“简单”选项,它不会影响它们:

These parsers do not support all the argparse features, and will raise exceptions if unsupported features are used. In particular, subparsers, argparse.REMAINDER, and mutually exclusive groups that include both optionals and positionals are not supported.

(我在花了 1 小时试图理解为什么 Pythonargparse 文档中的示例似乎没有包含它之后发布了这个 FAQ-style 问题,只是偶然发现了一个有点不相关的问题,其中在评论中提到了这个“混合”函数,我无法再次找到它来正确引用它。)

我不熟悉 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()