处理命令行参数

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

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

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

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

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

快速上手

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

$ python agentx.py -h
usage: agentx [-h] [-c conf_path] action

positional arguments:
  action                action to carry out: status/start/stop

optional arguments:
  -h, --help            show this help message and exit
  -c conf_path, --conf conf_path
                        configuration file path

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

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

/_src/practices/argparse/agentx.py
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
#!/usr/bin/env python
# -*- encoding=utf8 -*-

'''
FileName:   agentx.py
Author:     Fasion Chan
@contact:   fasionchan@gmail.com
@version:   $Id$

Description:

Changelog:

'''

import argparse


class ServiceController(object):

    '''
        服务控制器

        根据命令行参数,操作后台服务(守护进程)。
    '''

    def __init__(self, conf_path):
        # 命令行参数
        self.conf_path = conf_path

    def status(self):
        '''
            查询服务运行状态
        '''

        print('service is ...')

    def start(self):
        '''
            启动服务
        '''

        print('starting')

    def stop(self):
        '''
            停止服务
        '''

        print('stopping')

    def process(self, action):
        '''
            处理入口
        '''

        getattr(self, action)()


def main():
    '''
        主函数

        负责处理命令行参数并调用服务控制器。
    '''

    # 命令行解析
    parser = argparse.ArgumentParser(prog='agentx')

    # 配置文件选项
    parser.add_argument(
        '-c',
        '--conf',
        dest='conf_path',
        metavar='conf_path',
        default='',
        required=False,
        help='configuration file path',
    )

    # 操作选项
    parser.add_argument(
        'action',
        nargs=1,
        metavar='action',
        choices=('status', 'start', 'stop',),
        help='action to carry out: status/start/stop',
    )

    # 解析
    args = parser.parse_args()

    # 配置文件路径
    conf_path = args.conf_path
    # 执行动作
    action, = args.action


    # 处理
    service_controller = ServiceController(conf_path=conf_path)
    service_controller.process(action=action)

if __name__ == '__main__':
    main()

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

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

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

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

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

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

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

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

  1. 初始化解析器;

  2. 定义选项;

  3. 调用解析器解析参数;

  4. 从解析结果取值;

下一步

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

微信搜索:小菜学编程
微信搜索:小菜学编程