使用Python轻松写出漂亮的命令行程序

诞生之初用来作为配置管理语言的Python,现在已经成为最流行的编程语言之一,尤其是随着AI应用的兴起,变得无处不在

Python中的getoptoptparse模块都可以进行命令行程序的开发,不过它们已经被废弃,在2.7和3.2版本中引入了argparse模块;这里介绍使用argparser模块,只需要数十行代码,就可以做出漂亮的命令行程序。

1.基本的命令行

先看看官方文档里的一个示例:

def main():
    parser = argparse.ArgumentParser(description='Process some integers.')
    parser.add_argument('integers', metavar='N', type=int, nargs='+',
                    help='an integer for the accumulator')
    parser.add_argument('--sum', dest='accumulate', action='store_const',
                    const=sum, default=max,
                    help='sum the integers (default: find the max)')

    args = parser.parse_args()
    print args.accumulate(args.integers)

这几行代码实现的功能为:
如果命令行输入不带--sum选项,则对输入的多个整数执行max操作;否则,执行sum操作。例如:
在命令行中执行:

  $ python prog.py 1 2 3 4 

输出为:4

在命令行中执行:

$ python prog.py 1 2 3 4 --sum 

输出为:10

上面的代码中,主要的过程分为三个步骤:

  • 调用argparse.ArgumentParser的构造器创建一个ArgumentParser对象。
  • 调用ArgumentParseradd_argument()方法添加命令行的参数,包括可选参数和必选参数。其中以---开头的表示可选参数,其它的表示必须输入的参数。
  • 调用parser.parse_args()方法对传入的sys.argv参数进行解析。

2.实现子命令

有时候,我们可以根据功能将命令行分组成一系列相关的子命令。例如,Git命令行可以分为以下几组:

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone      Clone a repository into a new directory
   init       Create an empty Git repository or reinitialize an existing one

work on the current change (see also: git help everyday)
   add        Add file contents to the index
   mv         Move or rename a file, a directory, or a symlink
   reset      Reset current HEAD to the specified state
   rm         Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect     Find by binary search the change that introduced a bug
   grep       Print lines matching a pattern
   log        Show commit logs
   show       Show various types of objects
   status     Show the working tree status

grow, mark and tweak your common history
   branch     List, create, or delete branches
   checkout   Switch branches or restore working tree files
   commit     Record changes to the repository
   diff       Show changes between commits, commit and working tree, etc
   merge      Join two or more development histories together
   rebase     Forward-port local commits to the updated upstream head
   tag        Create, list, delete or verify a tag object signed with GPG

collaborate (see also: git help workflows)
   fetch      Download objects and refs from another repository
   pull       Fetch from and integrate with another repository or a local branch
   push       Update remote refs along with associated objects

在Python中,利用argparse模块也可以很容易做出这样的子命令行程序。

例如,我们要做一个对用户信息进行管理的命令行程序,包括添加、删除、查询显示等几个功能。

我们可以根据功能将其分为三个子命令:adddeleteshow

相应的代码可以这样写:

def main():
    parser = argparse.ArgumentParser(prog='cmd')

    sub_parser = parser.add_subparsers(title='subcommands',
                                    description='valid subcommands',
                                    help='config subscommand help')

    add_parser = sub_parser.add_parser('add',help='add user config')
    add_parser.add_argument('--name', required=True, help='user name')
    add_parser.add_argument('--addr', required=False, help='user address')
    add_parser.add_argument('--phone', required=False, help='phone number')
    add_parser.set_defaults(func=add_fn)

    delete_parser = sub_parser.add_parser('delete', help='delete user config')
    delete_parser.add_argument('--name', required=True, help='user name')
    delete_parser.set_defaults(func=delete_fn)

    show_parser = sub_parser.add_parser('show', help='show user config')
    show_parser.set_defaults(func=show_fn)
    
    args = parser.parse_args()
    args.func(args)

对上面的代码进行概要的解释:
ArgumentParser对象的add_subparsers()方法创建了一个特殊的action实例,对这个实例分别调用add_parser()方法来创建子命令对应的ArgumentParser,再调用这个ArgumentParser实例的add_argument()方法来添加子命令的参数。

一个比较方便的地方在于,可以通过ArgumentParserset_defaults()方法来设置子命令对应的处理函数。上面的示例中,分别为三个子命令设置了处理函数:add_fndelete_fnshow_fn

在命令行程序中执行:

$  python cmd.py --help 

将显示出以下信息:

usage: 
    cmd [sub-command]
    
optional arguments:
  -h, --help         show this help message and exit

subcommands:
  valid subcommands

  {add,delete,show}  config subscommand help
    add              add user config
    delete           delete user config
    show             show user config

从帮助信息中可以看到,命令行被组织为三个子命令,分别为adddeleteshow

在命令行中执行:

$ python cmd.py   add  --help 

可以查看add子命令的帮助信息:

usage: cmd [sub-command] add [-h] --name NAME [--addr ADDR]
                                    [--phone PHONE]

optional arguments:
  -h, --help     show this help message and exit
  --name NAME    user name
  --addr ADDR    user address
  --phone PHONE  phone number

对于add子命令,它有3个参数,分别为用户名联系地址电话号码;其中用户名为必选参数,其它两个为可选参数。

在命令行中执行:

$ python cmd.py add --name 'Eric' --addr 'California,USA' --phone '0076938377'` 

添加一个User的处理逻辑将由add_fn()来完成。程序中将得到一个信息为{name='Eric',addr='California,USA', phone='0076938377'}的User。

def add_fn(args):
    args_dict = vars(args)
    
    name = args_dict['name']
    address = args_dict['addr']
    phone_number = args_dict['phone']

    print 'Add User : %-10s %10s %12s' % (name, address, phone_number)
    ...

其它的deleteshow子命令与此类似,不再赘述。

3.小结

使用Python的argparse模块,短短的几十行代码就可以搭建起来一个命令行程序的骨架。

argparse模块中最重要的是ArgumentParser对象,它包含了以下几个方法:

  • add_argument()
  • add_subparsers()
  • parse_args()

关于这几个方法的用法,以及参数的详细的说明请参考官方文档

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342

推荐阅读更多精彩内容