python编程
首发于python编程
python命令行解析工具

python命令行解析工具

在使用python的过程中,会经常遇到一些命令要在命令行中操作,比如pippython,或者是一些库如jupyter-themes库(用于修改jupyter的页面样式)中的jt命令(比如用jt -t grade3这样的命令套用grade3样式模板)
我们有时候还会在命令行中使用类似这样的命令python --versionpython -h。(后面---是命令行中接参数的两种方法,和python中的函数接参数一样)
因为python和pip在前面的文章中已经讲过,这里拿jt来举例子
jt -t grade3 这条命令其实是调用了jt.exe文件,并把t参数赋值为grade3传入运行。而这个.exe文件其实是.py文件打包而成的。
所以说它的过程是这样的:

  • 写好一个jt.py文件,但是运行这个文件需要外部输入参数
  • jt.py文件里面要定义一些方法来接受cmd中输入的参数
  • 最后实现可以运行 python jt.py -t grade3
  • 再将jt.py文件打包成exe文件
  • 最后就可以运行jt -t grade3

其中第二步————接受cmd中输入的参数,需要用到的就是命令行解析工具。
python中有很多命令行解析库,主要有如下几种

  • sys.argv
  • argparse库
  • click库
  • fire库(这是一个神器)
  • 总结

下面我们分别进行讲解

sys.argv

可以把sys.argv理解成一个list

  • 其中第一个元素是代码所在的module,比如代码是在cmd.py文件夹下编辑,在命令行中运行python cmd.py,此时sys.argv[0]就是cmd.py
  • 后面的元素是我们在命令行中给它加入的参数

我们看一下下面例子
1.sys.argv[0]
在cmd.py文件中输入下面内容

import sys
a = sys.argv[0]
print(a)

在cmd.py所在文件夹中打开cmd(本文之后所有在cmd中输入都指的是在这个文件夹下的cmd),输入

python cmd.py

返回 cmd.py
如果在jupyter的一个cell中输入cmd.py中的内容,运行则返回 filepath/__main__.py(filepath是ipykernel所在路径),因为不在一个.py文件中,所以它的module自动就是__main__.py。
如果我们只关注我们输入的参数,则可以不关注sys.argv[0]

2.sys.argv[i] i = 1,2,3…

下面我们来看一下如何将命令行中的参数传入python脚本中运行
(1)最简单是使用
在cmd.py文件中输入

import sys
a = sys.argv[1]
print(a)

在cmd中输入

python cmd.py 2

返回2

(2)支持切片一
在cmd.py文件中输入

import sys
a = sys.argv[1:]
print(a)

在cmd中输入

python cmd.py 2 3 4

返回['2', '3', '4']

(3)支持切片二
在cmd.py文件中输入

import sys
a = sys.argv[1:3]
for i in a:
    print(i)

在cmd中输入

python cmd.py 2 3 4

返回2 3

用sys模块只支持一些简单的传入,如果要复杂一些,设定参数名称,则要使用下面的库

argparse库

argparse是python内置库,是最常用的命令行解析库,官网的教程非常详细,是从最简单的命令开始,一步一步增加可以实现的功能。我如果写也是这么写,所以不再进行过多重复,只是简单展示一个实例。

在cmd.py文件中输入

import argparse # 1
parser = argparse.ArgumentParser() #2

parser.add_argument('text', help = 'print some text') # 3
parser.add_argument('-v','--value', nargs = 2, type = int, help = 'the sum of 2 int')

args = parser.parse_args() # 4

# 输出两个部分
print(args.text)

if args.value:
    print(args.value[0]+args.value[1])

其中标号1 2 3 4是argparse库的最基本四个步骤

  • 导入库
  • 初始化解析器
  • 增加参数
  • 解析参数,让args可以调用

下面我们在命令行中调用
(1)只调用text参数

python cmd.py what

返回 what
因为没有指定参数是—vlaue,所以what赋值给了text,在cmd.py脚本中又args.text调用被打印出来

(2)两个参数都调用

python cmd.py -v 2 3 what

返回 what 5 -v--value参数的简写形式,在cmd中调用参数直接用空格分隔,两个参数之间也用空格分隔开

(3)用value完整参数

python cmd.py what --value 5 3

返回 what 8
两个参数顺序无所谓

(4)调用命令的帮助文档

python cmd.py -h

返回如下内容

usage: cmd.py [-h] [-v VALUE VALUE] text

positional arguments:
  text                  print some text

optional arguments:
  -h, --help            show this help message and exit
  -v VALUE VALUE, --value VALUE VALUE
                        the sum of 2 int
  • -h或者--help不需要在.py文件中定义即可使用
  • 这里可以看到命令的用法cmd.py [-h] [-v VALUE VALUE] text表明了输入参数的方法和顺序等
  • 还把每个参数列在下面,把我们在cmd.py文件中,每个参数的help参数中的内容打印了出来

click

这个库的语法和argparse差不太多,只是改成装饰器形式,官网的教程个人认为不是十分清楚,没有把完整的代码写出来,网上的博客也很多都是直接复制官网的代码,所以下面的例子有比较大的借鉴意义。但是如果想深入研究还是要看官网的说明的

(1)一个简单的实例
cmd.py文件中写入

import click

@click.command() # 让它成为一个命令行工具
@click.argument('name') # 将name参数传入
def newprint(name):
    click.echo('my name is ' + name) # 用echo代替print,有一些比较细节的好处,当成print就好

newprint() # 这里调用的时候就不用接参数了

在cmd中输入

python cmd.py bob

(2)多个函数

import click

# 定义第一个函数
@click.command() 
@click.argument('name')
def newprint(name):
    click.echo('my name is ' + name)

# 定义第二个函数
@click.command()
@click.argument('a', type = int)
@click.argument('b', type = int)
def newadd(a,b):
    click.echo(a+b)

# 将两个函数结合
@click.group() # 用于整合多个函数
def cli():
    pass

cli.add_command(newprint)
cli.add_command(newadd)

cli()

在cmd中输入

python cmd.py newadd 2 3

返回5

输入

python cmd.py newprint bob

返回my name is bob
我们发现我们可以在命令行中直接调用脚本中的函数,接参数,这样是非常方便的。
下面这个库,个人认为结合了上面的所有优点,而且一切都更简洁清晰,简直是神器

fire库

这是一个命令行解析的神器,没有前面解析库中那么复杂的过程,它可以实现在cmd中直接调用py文件中的函数、变量、类、实例等等,更符合我们的思维习惯
这个库也有非常简明易懂的官方教程

(1)将py文件中的所有函数都导入
在cmd.py文件中输入

import fire

def newprint(text):
    print('my '+text)

def newadd(a,b):
    return a + b

fire.Fire() # 只要这一条命令

在cmd中输入

python cmd.py newprint notebook

返回 my notebook

输入

python cmd.py newadd 2 3

返回5

输入(可以指定函数的参数)

python cmd.py newadd --a 2 --b 3

返回5

其实如果py文件中定义有变量,这样也会把变量导入,在命令行中输入

python cmd.py 变量名

即可查看变量内容


(2)导入指定函数
将cmd.py文件中的fire.Fire()换成fire.Fire(newadd),这样就只能使用newadd函数,而且不需要写newadd函数名,直接接参数即可,调用如下

python cmd.py --a 2 --b 3

(其实上面的这个用法和其他库的用法是一样的,只是解析时代码更简单)

若要传入多个函数而不是全部函数,则fire.Fire()换成

fire.Fire({
  'newadd': newadd,
  'newprint': newprint,
})

其实我们一般也只要导入一个函数即可,其他函数均由这个函数调用


(3)导入类或实例
其实也可以在py文件中定义类,将类传入,或者再定义出一个实例,将实例传入,分别把fire.Fire()换为

fire.Fire(Myclass)
fire.Fire(myinstance)

而实例中的比如newadd方法,则和上面调用函数完全一样来调用即可

python cmd.py newadd 2 3

还可以传入实例创建时的初始参数,我们来看下面一个例子

import fire

class Myclass:

    def __init__(self, name):
        self.name = name

    def nameprint(self, anything):
        print(anything + ', my name is ' + self.name)

fire.Fire(Myclass)

在cmd中输入

python cmd.py nameprint Yes --name bob

输出Yes, my name is bob


总结

  • argv和argparse库调用的函数其实都写在py文件里,在命令行中只是传入函数要调用的参数
  • click用装饰器既实现了在py函数中调用函数、命令行输入参数的形式;而且可以在命令行中指定调用哪个函数和参数
  • fire库也是二者都可以,这个库的代码设计更加简洁

专栏信息

专栏主页:python编程

专栏目录:目录

版本说明:软件及包版本说明

编辑于 2018-05-12

文章被以下专栏收录