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 sysna = sys.argv[0]nprint(a)n

在cmd.py所在文件夾中打開cmd(本文之後所有在cmd中輸入都指的是在這個文件夾下的cmd),輸入

python cmd.pyn

返回 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 sysna = sys.argv[1]nprint(a)n

在cmd中輸入

python cmd.py 2n

返回2

(2)支持切片一

在cmd.py文件中輸入

import sysna = sys.argv[1:]nprint(a)n

在cmd中輸入

python cmd.py 2 3 4n

返回[2, 3, 4]

(3)支持切片二

在cmd.py文件中輸入

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

在cmd中輸入

python cmd.py 2 3 4n

返回2 3

用sys模塊只支持一些簡單的傳入,如果要複雜一些,設定參數名稱,則要使用下面的庫

argparse庫

argparse是python內置庫,是最常用的命令行解析庫,官網的教程非常詳細,是從最簡單的命令開始,一步一步增加可以實現的功能。我如果寫也是這麼寫,所以不再進行過多重複,只是簡單展示一個實例。

在cmd.py文件中輸入

import argparse # 1nparser = argparse.ArgumentParser() #2nnparser.add_argument(text, help = print some text) # 3nparser.add_argument(-v,--value, nargs = 2, type = int, help = the sum of 2 int)nnargs = parser.parse_args() # 4nn# 輸出兩個部分nprint(args.text)nnif args.value:n print(args.value[0]+args.value[1])n

其中標號1 2 3 4是argparse庫的最基本四個步驟

  • 導入庫
  • 初始化解析器
  • 增加參數
  • 解析參數,讓args可以調用

下面我們在命令行中調用

(1)只調用text參數

python cmd.py whatn

返回 what

因為沒有指定參數是—vlaue,所以what賦值給了text,在cmd.py腳本中又args.text調用被列印出來

(2)兩個參數都調用

python cmd.py -v 2 3 whatn

返回 what 5 -v--value參數的簡寫形式,在cmd中調用參數直接用空格分隔,兩個參數之間也用空格分隔開

(3)用value完整參數

python cmd.py what --value 5 3n

返回 what 8

兩個參數順序無所謂

(4)調用命令的幫助文檔

python cmd.py -hn

返回如下內容

usage: cmd.py [-h] [-v VALUE VALUE] textnnpositional arguments:n text print some textnnoptional arguments:n -h, --help show this help message and exitn -v VALUE VALUE, --value VALUE VALUEn the sum of 2 intn

  • -h或者--help不需要在.py文件中定義即可使用
  • 這裡可以看到命令的用法cmd.py [-h] [-v VALUE VALUE] text表明了輸入參數的方法和順序等
  • 還把每個參數列在下面,把我們在cmd.py文件中,每個參數的help參數中的內容列印了出來

click

這個庫的語法和argparse差不太多,只是改成裝飾器形式,官網的教程個人認為不是十分清楚,沒有把完整的代碼寫出來,網上的博客也很多都是直接複製官網的代碼,所以下面的例子有比較大的借鑒意義。但是如果想深入研究還是要看官網的說明的

(1)一個簡單的實例

cmd.py文件中寫入

import clicknn@click.command() # 讓它成為一個命令行工具n@click.argument(name) # 將name參數傳入ndef newprint(name):n click.echo(my name is + name) # 用echo代替print,有一些比較細節的好處,當成print就好nnnewprint() # 這裡調用的時候就不用接參數了n

在cmd中輸入

python cmd.py bobn

(2)多個函數

import clicknn# 定義第一個函數n@click.command() n@click.argument(name)ndef newprint(name):n click.echo(my name is + name)nn# 定義第二個函數n@click.command()n@click.argument(a, type = int)n@click.argument(b, type = int)ndef newadd(a,b):n click.echo(a+b)nn# 將兩個函數結合n@click.group() # 用於整合多個函數ndef cli():n passnncli.add_command(newprint)ncli.add_command(newadd)nncli()n

在cmd中輸入

python cmd.py newadd 2 3n

返回5

輸入

python cmd.py newprint bobn

返回my name is bob

我們發現我們可以在命令行中直接調用腳本中的函數,接參數,這樣是非常方便的。

下面這個庫,個人認為結合了上面的所有優點,而且一切都更簡潔清晰,簡直是神器

fire庫

這是一個命令行解析的神器,沒有前面解析庫中那麼複雜的過程,它可以實現在cmd中直接調用py文件中的函數、變數、類、實例等等,更符合我們的思維習慣

這個庫也有非常簡明易懂的官方教程

(1)將py文件中的所有函數都導入

在cmd.py文件中輸入

import firenndef newprint(text):n print(my +text)nndef newadd(a,b):n return a + bnnfire.Fire() # 只要這一條命令n

在cmd中輸入

python cmd.py newprint notebookn

返回 my notebook

輸入

python cmd.py newadd 2 3n

返回5

輸入(可以指定函數的參數)

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

返回5

其實如果py文件中定義有變數,這樣也會把變數導入,在命令行中輸入

python cmd.py 變數名n

即可查看變數內容

(2)導入指定函數

將cmd.py文件中的fire.Fire()換成fire.Fire(newadd),這樣就只能使用newadd函數,而且不需要寫newadd函數名,直接接參數即可,調用如下

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

(其實上面的這個用法和其他庫的用法是一樣的,只是解析時代碼更簡單)

若要傳入多個函數而不是全部函數,則fire.Fire()換成

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

其實我們一般也只要導入一個函數即可,其他函數均由這個函數調用

(3)導入類或實例

其實也可以在py文件中定義類,將類傳入,或者再定義出一個實例,將實例傳入,分別把fire.Fire()換為

fire.Fire(Myclass)nfire.Fire(myinstance)n

而實例中的比如newadd方法,則和上面調用函數完全一樣來調用即可

python cmd.py newadd 2 3n

還可以傳入實例創建時的初始參數,我們來看下面一個例子

import firennclass Myclass:nn def __init__(self, name):n self.name = namenn def nameprint(self, anything):n print(anything + , my name is + self.name)nnfire.Fire(Myclass)n

在cmd中輸入

python cmd.py nameprint Yes --name bobn

輸出Yes, my name is bob

總結

  • argv和argparse庫調用的函數其實都寫在py文件里,在命令行中只是傳入函數要調用的參數
  • click用裝飾器既實現了在py函數中調用函數、命令行輸入參數的形式;而且可以在命令行中指定調用哪個函數和參數
  • fire庫也是二者都可以,這個庫的代碼設計更加簡潔

專欄信息

專欄主頁:Data Analysis

專欄目錄:目錄

版本說明:軟體及包版本說明

推薦閱讀:

Python 所謂的「閉包」是不是本著故意把人搞暈的態度發明出來的?
使用了Gunicorn或者uWSGI,為什麼還需要Nginx?
解構國內首個函數計算(從概念、入門再到實戰)
50?python爬?代碼, 帶你正確打開知乎新世界!
python anaconda 怎麼安裝?

TAG:命令行控制 | Python |