如何使用 python argparse 解决命令行问题?
Posted
技术标签:
【中文标题】如何使用 python argparse 解决命令行问题?【英文标题】:How to solve command line problem using python argparse? 【发布时间】:2021-03-27 10:30:48 【问题描述】:我正在处理一个命令行项目,在处理 add
子命令时遇到了一些问题,如下面的 cmets 所示:
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
我该如何解决这个问题?
【问题讨论】:
为什么要指定todo
两次?如果文件被称为todo
而不是todo.py
,则./todo
将是命令名称,并且它被放置在当前目录中并标记为可执行文件; python todo.py
是使用 python
解释器显式运行文件 todo.py
中的脚本的等效命令。
【参考方案1】:
您可能误解了如何定义参数。您可能假设您可以在示例中使用参数作为函数调用中的位置参数,但这不是参数解析器的工作方式。这是您的示例中发生的情况
python todo.py ./todo add " I am soham Das Biswas"
您定义了两个参数:“./todo”和“o”。 ./todo add
部分将add
的值分配给./todo
参数。
“I am soham Das Biswas”不会分配给“o”,因为您在通话中没有提到“o”。如果你想给“o”赋值,你需要像o value_i_want_to_assign
这样的东西。
你想让你的代码做什么?
【讨论】:
它给我 x 是强制性的,我不想给它强制性 所以当我询问 x 位置时,它会给出位置,而当我不想要它时,它不会给出强制性的【参考方案2】:有
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
。它们由位置标识,而不是任何类型的“标志”字符串。第一个字符串分配给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
用于必需的内容。有一些方法可以改变这种情况,但它会让你和你的用户更难理解输入。
【讨论】:
以上是关于如何使用 python argparse 解决命令行问题?的主要内容,如果未能解决你的问题,请参考以下文章
python argh/argparse:如何将列表作为命令行参数传递?
Python argparse 如何从命令行传递 False?