如何使用 python argparse 解决命令行问题?

How to solve command line problem using python argparse?

我正在处理一个命令行项目,在处理 add 子命令时遇到一些问题,如下面的注释所示:

import argparse
import sys
def todo(args):
    if args.o =='add':
        print("Added Todo: "+args.x)
        f=open("todo.txt", "a+")
        c= str(count+1)
        p= '\n'+'. '+args.x
        f.write(p)
        f.close()
    elif args.o =='report':
        return 
    elif args.o =='del NUMBER':
        return 
    elif args.o =='done NUMBER':
        return 
    elif args.o =='help':
        print ("Usage :-"+
               "\n"+'$ ./todo add "todo item"           # add a new todo'+
               "\n"+'$ ./todo ls                        # Show remaining todos'+
               "\n"+'$ ./todo del NUMBER                # delete a todo'+
               "\n"+'$ ./todo done NUMBER               # complete a todo'+
               "\n"+'$ ./todo help                      # Show Usage'+
               "\n"+'$ ./todo report                    # Statistics')
    elif args.o =='ls':
        f=open("todo.txt", "r")
        print(f.read())
        f.close()
if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument('./todo', type=str, default="./todo")
    parser.add_argument('o', type=str, default="add")
    args = parser.parse_args()
    if args.o =='add':                     # <- starting here
        parser.add_argument('x', type=str, default=None)
        args = parser.parse_args()
        sys.stdout.write(str(todo(args)))  # <- ending here
    else:
        a = parser.parse_args()
        sys.stdout.write(str(todo(args)))

当我在 Powershell 中 运行 这个脚本时,我得到了一些错误,比如

PS E:\python projects\fellowship challenge\python> python todo.py ./todo add " I am soham Das Biswas"
usage: todo.py [-h] ./todo o
todo.py: error: unrecognized arguments:  I am soham Das Biswas

我该如何解决这个问题?

您可能误解了如何定义参数。您可能假设您可以在示例中使用参数作为函数调用中的位置参数,但这不是参数解析器的工作方式。这是您的示例中发生的情况

python todo.py ./todo add " I am soham Das Biswas"

您定义了两个参数:“./todo”和“o”。 ./todo add 部分将 add 的值分配给 ./todo 参数。

“我是 soham Das Biswas”不会分配给“o”,因为您在通话中没有提到“o”。如果你想为“o”分配一些东西,你需要像 o value_i_want_to_assign.

这样的东西

您希望您的代码做什么?

import argparse

parser = argparse.ArgumentParser()
parser.add_argument('./todo', type=str, default="./todo")
parser.add_argument('o', type=str, default="add")
args = parser.parse_args()
print(args)

一些样本运行:

1301:~/mypy$ python3 stack65328753.py -h
usage: stack65328753.py [-h] ./todo o

positional arguments:
  ./todo
  o

optional arguments:
  -h, --help  show this help message and exit

有 2 个字符串:

1303:~/mypy$ python3 stack65328753.py todo add
Namespace(o='add', **{'./todo': 'todo'})

还有额外的:

1304:~/mypy$ python3 stack65328753.py todo add "extra string"
usage: stack65328753.py [-h] ./todo o
stack65328753.py: error: unrecognized arguments: extra string

这定义了 2 个参数,都是 positionals。它们由位置标识,而不是任何类型的 'flag' 字符串。第一个字符串分配给 args 的“./todo”属性,第二个字符串分配给“o”。没啥拿三弦的。

您可以使用 args.o 访问第二个值,但 args../todo 不起作用。相反,您必须 getattr(args, "./todo")。所以使用这样一个“花哨”的名字通常不是一个好主意。

由于这些是必需的位置,因此没有必要指定 default

将参数更改为 optionals:

parser = argparse.ArgumentParser()
parser.add_argument("--dir", default="./todo")
parser.add_argument('-o', type=str, default="add")
args = parser.parse_args()
print(args)
print(args.dir, args.o)

并运行:

1315:~/mypy$ python3 stack65328753.py -h
usage: stack65328753.py [-h] [--dir DIR] [-o O]

optional arguments:
  -h, --help  show this help message and exit
  --dir DIR
  -o O

1316:~/mypy$ python3 stack65328753.py
Namespace(dir='./todo', o='add')
./todo add

1316:~/mypy$ python3 stack65328753.py --dir ./mydir 
Namespace(dir='./mydir', o='add')
./mydir add

1316:~/mypy$ python3 stack65328753.py --dir ./mydir -o subtract
Namespace(dir='./mydir', o='subtract')
./mydir subtract

1316:~/mypy$ python3 stack65328753.py --dir ./mydir -o "an extra string"
Namespace(dir='./mydir', o='an extra string')
./mydir an extra string

您尝试根据 args.o

添加“x”参数
args = parser.parse_args()
if args.o =='add':                     # <- starting here
    parser.add_argument('x', type=str, default=None)
    args = parser.parse_args()

但第一个 parse_args() 引发无法识别的错误并退出。所以你永远不会继续这个添加。

parser = argparse.ArgumentParser()
parser.add_argument("--dir", default="./todo")
parser.add_argument('-o', type=str, default="add")
args, extras = parser.parse_known_args()
print(args, extras)
print(args.dir, args.o)

if args.o == "add":
    parser.add_argument('x')
    args = parser.parse_args()
    print(args)

帮助未更改,因为它是第一个 parse 作用于该帮助:

1318:~/mypy$ python3 stack65328753.py -h
usage: stack65328753.py [-h] [--dir DIR] [-o O]

optional arguments:
  -h, --help  show this help message and exit
  --dir DIR
  -o O


1323:~/mypy$ python3 stack65328753.py --dir ./mydir -o "an extra string"
Namespace(dir='./mydir', o='an extra string') []
./mydir an extra string

parse_known_args 将多余的字符串放在 extras 中。现在继续添加 x 参数:

1323:~/mypy$ python3 stack65328753.py --dir ./mydir -o add "an extra string"
Namespace(dir='./mydir', o='add') ['an extra string']
./mydir add
Namespace(dir='./mydir', o='add', x='an extra string')

另一种选择是

args.x = extras

这将是(可能是空的)列表。

对于这样的问题,我强烈建议使用 print(args) 来查看解析器的功能。并在将其嵌入更大的脚本之前调试解析器。首先,不要试图太花哨。使用 optionals 表示可选、非必需的内容,使用 positionals 表示必需的内容。有多种方法可以改变它,但这会使您和您的用户更难理解输入内容。