处理命令行参数

在程序开发中,经常需要调整程序的执行行为。

大部分情况下,最佳实践是—— 实现规范的命令行参数 ,而不是动不动就改代码。试想一下,程序配置文件是通过命令行指定好呢?还是写死在代码里好呢?

每个程序都应该实现 -h 或者 —help 参数选项,输出帮助信息。这样一来,谁都可以通过该途径获悉程序用法,应用自如。这便是惯例的力量!

实现命令行参数的成本也不高,大部分语言都提供了足够方便的程序库,无需也不推荐重复造轮子:

Python 程序可以通过标准库 argparse 解析命令行参数。

快速上手

接下来,以一个名为 AgentX 的程序为例,讲解如何使用 argparse 模块。AgentX 的用法如下:

  1. $ python agentx.py -h
  2. usage: agentx [-h] [-c conf_path] action
  3.  
  4. positional arguments:
  5. action action to carry out: status/start/stop
  6.  
  7. optional arguments:
  8. -h, --help show this help message and exit
  9. -c conf_path, --conf conf_path
  10. configuration file path

-h 选项显示帮助文档; -c 选项指定配置文件目录;位置参数 action 指定要执行的操作。

借助 argparse ,解析命令行参数只需代码若干:

/_src/practices/argparse/agentx.py

  1. #!/usr/bin/env python
  2. # -*- encoding=utf8 -*-
  3.  
  4. '''
  5. FileName: agentx.py
  6. Author: Fasion Chan
  7. @contact: fasionchan@gmail.com
  8. @version: $Id$
  9.  
  10. Description:
  11.  
  12. Changelog:
  13.  
  14. '''
  15.  
  16. import argparse
  17.  
  18.  
  19. class ServiceController(object):
  20.  
  21. '''
  22. 服务控制器
  23.  
  24. 根据命令行参数,操作后台服务(守护进程)。
  25. '''
  26.  
  27. def __init__(self, conf_path):
  28. # 命令行参数
  29. self.conf_path = conf_path
  30.  
  31. def status(self):
  32. '''
  33. 查询服务运行状态
  34. '''
  35.  
  36. print('service is ...')
  37.  
  38. def start(self):
  39. '''
  40. 启动服务
  41. '''
  42.  
  43. print('starting')
  44.  
  45. def stop(self):
  46. '''
  47. 停止服务
  48. '''
  49.  
  50. print('stopping')
  51.  
  52. def process(self, action):
  53. '''
  54. 处理入口
  55. '''
  56.  
  57. getattr(self, action)()
  58.  
  59.  
  60. def main():
  61. '''
  62. 主函数
  63.  
  64. 负责处理命令行参数并调用服务控制器。
  65. '''
  66.  
  67. # 命令行解析
  68. parser = argparse.ArgumentParser(prog='agentx')
  69.  
  70. # 配置文件选项
  71. parser.add_argument(
  72. '-c',
  73. '--conf',
  74. dest='conf_path',
  75. metavar='conf_path',
  76. default='',
  77. required=False,
  78. help='configuration file path',
  79. )
  80.  
  81. # 操作选项
  82. parser.add_argument(
  83. 'action',
  84. nargs=1,
  85. metavar='action',
  86. choices=('status', 'start', 'stop',),
  87. help='action to carry out: status/start/stop',
  88. )
  89.  
  90. # 解析
  91. args = parser.parse_args()
  92.  
  93. # 配置文件路径
  94. conf_path = args.conf_path
  95. # 执行动作
  96. action, = args.action
  97.  
  98.  
  99. # 处理
  100. service_controller = ServiceController(conf_path=conf_path)
  101. service_controller.process(action=action)
  102.  
  103. if __name__ == '__main__':
  104. main()

代码看似很长,但参数解析部分却只有一小段。

19 - 57 行是服务控制类 ServiceController 定义,我们需要根据命令行参数驱动该类执行选定逻辑。

紧接着是 main 函数定义,命令行解析逻辑代码所在。

68 行处先初始化一个参数解析器, prog 参数是程序名字。

82 行处是 -c 参数的定义: dest 执行参数值存放位置;metavar 是选项名称占位符,与 help 结合在帮助文档中显示;default 是默认值; required 指定选项是否必填。

82 行处是位置参数 action 的定义:nargs 指定参数个数,这里为 1choices 指定参数可选值。

91 行处调用解析器进行解析;94 行处从解析结果中取值。注意到,属性名和参数定义中 dest 参数一致。

总结起来,参数解析只需要这几个步骤:

  • 初始化解析器;
  • 定义选项;
  • 调用解析器解析参数;
  • 从解析结果取值;

下一步

订阅更新,获取更多学习资料,请关注我们的 微信公众号

../_images/wechat-mp-qrcode.png小菜学编程

微信打赏