在使用python的过程中,会经常遇到一些命令要在命令行中操作,比如pip
和python
,或者是一些库如jupyter-themes库(用于修改jupyter的页面样式)中的jt命令(比如用jt -t grade3
这样的命令套用grade3样式模板)
我们有时候还会在命令行中使用类似这样的命令python --version
或python -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库也是二者都可以,这个库的代码设计更加简洁
专栏信息
专栏主页:Data Analysis