命令行程序?qū)Ρ菺UI程序有很多優(yōu)點:編寫簡單叁执,參數(shù)形式統(tǒng)一茄厘,便于自動化,使用python編寫命令行實現(xiàn)單一功能谈宛,然后用shell調(diào)用比較方便次哈。
此外命令行解析,用來調(diào)試程序也比較方便吆录,不用到源碼里改程序的參數(shù)了窑滞,用命令行指定就比較靈活。
很多功能簡單的程序恢筝,不涉及復(fù)雜的交互哀卫,用命令行比較方便,更好用撬槽。
01.注釋運行環(huán)境
如果在linux系統(tǒng)上運行此改,通過注釋運行環(huán)境,然后我們使用chmod a+x賦予執(zhí)行權(quán)限,就可以直接運行文件不用指明解釋器了侄柔,比較方便共啃。
#!/usr/bin/env python
如果在windows系統(tǒng)中這個注釋是沒有效果的。windows系統(tǒng)通常是根據(jù)文件后綴選擇打開的工具勋拟。
02.命令行解析工具argparse的使用
argparse是python標準庫自帶的命令行解析工具勋磕,功能比較強大。因為標準庫自帶敢靡,所以一般我們用這個寫命令行就行了挂滓,比較方便。
我們先來編寫一個最簡單的程序:
%%writefile 'arghelp.py'
import argparse
parser = argparse.ArgumentParser()
parser.parse_args()
%%cmd
python arghelp.py -h
Microsoft Windows [版本 10.0.17763.557]
(c) 2018 Microsoft Corporation啸胧。保留所有權(quán)利赶站。
D:\code\Projects\jupyterNotes\python3\python3筆記>python arghelp.py -h
usage: arghelp.py [-h]
optional arguments:
-h, --help show this help message and exit
D:\code\Projects\jupyterNotes\python3\python3筆記>
我們在cmd中執(zhí)行這個程序,發(fā)現(xiàn)可以打印出唯一一條幫助文檔纺念。
--help -h是默認會添加的選項贝椿,不需要定制
001. 位置參數(shù)
下面我們寫一個簡單的計算乘冪的程序來演示,位置參數(shù)的添加陷谱。
%%writefile 'calpower.py'
import argparse
parser = argparse.ArgumentParser()
# 加進去的字符串會被當成選項,注意類型直接寫烙博,不用字符串,這樣子不帶連接符的就是位置參數(shù),是必須的。
# 如果帶連接符就是可選參數(shù)
parser.add_argument('base',help='指數(shù)運算的底',type=int)
parser.add_argument('power',help='指數(shù)運算的冪',type=int)
args = parser.parse_args()
print ('{}th power of {} is {}'.format(args.power,args.base,args.base**args.power))
%%cmd
python calpower.py 2 3
Microsoft Windows [版本 10.0.17763.557]
(c) 2018 Microsoft Corporation烟逊。保留所有權(quán)利渣窜。
D:\code\Projects\jupyterNotes\python3\python3筆記>python calpower.py 2 3
3th power of 2 is 8
D:\code\Projects\jupyterNotes\python3\python3筆記>
002.可選參數(shù)
帶連接符的參數(shù)就會被當做可選參數(shù)
下面我們添加一個常見的功能,就是輸出通常有簡單模式宪躯,復(fù)雜模式兩種
%%writefile 'test/calpower.py'
import argparse
parser = argparse.ArgumentParser()
# 加進去的字符串會被當成選項,注意類型直接寫乔宿,不用字符串,這樣子不帶連接符的就是位置參數(shù),是必須的。
# 如果帶連接符就是可選參數(shù)
parser.add_argument('base',help='指數(shù)運算的底',type=int)
parser.add_argument('power',help='指數(shù)運算的冪',type=int)
# 可以直接添加簡短復(fù)雜兩種访雪,總之加進去的字符串會被當成選項
# 這里是個開關(guān)選項只有true和flase兩個值详瑞,所以我們默認設(shè)為true
parser.add_argument('-v','--verbose', help="increase output verbosity", action="store_true")
args = parser.parse_args()
if args.verbose:
print('verbose on')
print ('{}th power of {} is {}'.format(args.power,args.base,args.base**args.power))
else:
print(args.base**args.power)
%%cmd
python test/calpower.py 2 3
Microsoft Windows [版本 10.0.17763.557]
(c) 2018 Microsoft Corporation掂林。保留所有權(quán)利。
D:\code\Projects\jupyterNotes\python3\python3筆記>python test/calpower.py 2 3
8
D:\code\Projects\jupyterNotes\python3\python3筆記>
%%cmd
python test/calpower.py -v 2 3
Microsoft Windows [版本 10.0.17763.557]
(c) 2018 Microsoft Corporation坝橡。保留所有權(quán)利泻帮。
D:\code\Projects\jupyterNotes\python3\python3筆記>python test/calpower.py -v 2 3
verbose on
3th power of 2 is 8
D:\code\Projects\jupyterNotes\python3\python3筆記>
也就是說action='store_true'意思是,當有這個選項時就把值設(shè)置為true
add_argument還有一些參數(shù)驳庭,比如說 choices=[0, 1, 2]
,這樣就可以在指定范圍里選
count參數(shù)刑顺,這樣就可以用來指定輸出的級別
default可以指定默認值
import argparse
parser = argparse.ArgumentParser()
parser.add_argument("square", type=int,
help="display the square of a given number")
parser.add_argument("-v", "--verbosity", action="count",
help="increase output verbosity",default=0)
args = parser.parse_args()
answer = args.square**2
if args.verbosity == 2:
print("the square of {} equals {}".format(args.square, answer))
elif args.verbosity == 1:
print("{}^2 == {}".format(args.square, answer))
else:
print(answer)
?
003.互斥參數(shù)
使用add_mutually_exclusive_group()這個方法可以添加互斥參數(shù)
import argparse
parser = argparse.ArgumentParser()
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y
if args.quiet:
print(answer)
elif args.verbose:
print("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
print("{}^{} == {}".format(args.x, args.y, answer))
004.添加工具的描述
只需要在創(chuàng)建parser對象時給出description參數(shù)即可
import argparse
parser = argparse.ArgumentParser(description="calculate X to the power of Y")
group = parser.add_mutually_exclusive_group()
group.add_argument("-v", "--verbose", action="store_true")
group.add_argument("-q", "--quiet", action="store_true")
parser.add_argument("x", type=int, help="the base")
parser.add_argument("y", type=int, help="the exponent")
args = parser.parse_args()
answer = args.x**args.y
if args.quiet:
print(answer)
elif args.verbose:
print("{} to the power {} equals {}".format(args.x, args.y, answer))
else:
print("{}^{} == {}".format(args.x, args.y, answer))
005.詳細參數(shù)說明
parser = argparse.ArgumentParser(prog=None, usage=None, description=None, epilog=None, parents=[], formatter_class=argparse.HelpFormatter, prefix_chars='-', fromfile_prefix_chars=None, argument_default=None, conflict_handler='error', add_help=True)
創(chuàng)建命令行解析對象
其中的參數(shù):
prog - 程序的名字(默認:sys.argv[0])
usage - 描述程序用法的字符串(默認:從解析器的參數(shù)生成)
description - 參數(shù)幫助信息之前的文本(默認:空)
epilog - 參數(shù)幫助信息之后的文本(默認:空)
parents - ArgumentParser 對象的一個列表,這些對象的參數(shù)應(yīng)該包括進去饲常,像有時候需要解析非常復(fù)雜的關(guān)鍵字參數(shù),比如像git那樣的,
formatter_class - 定制化幫助信息的類
prefix_chars - 可選參數(shù)的前綴字符集(默認:‘-‘)
fromfile_prefix_chars - 額外的參數(shù)應(yīng)該讀取的文件的前綴字符集(默認:None)
argument_default - 參數(shù)的全局默認值(默認:None)
conflict_handler - 解決沖突的可選參數(shù)的策略(通常沒有必要)
add_help - 給解析器添加-h/–help 選項(默認:True)
parser.add_argument(name or flags...[, action][, nargs][, const][, default][, type][, choices][, required][, help][, metavar][, dest])
增加命令行參數(shù),方法的參數(shù)說明如下:
name or flags 命令行參數(shù)名或者選項,如上面的address或者-p,--port.其中命令行參數(shù)如果沒給定狼讨,且沒有設(shè)置defualt贝淤,則出錯。但是如果是選項的話政供,則設(shè)置為None,add_argument() 方法必須知道期望的是可選參數(shù)播聪,比如-f 或者--foo,還是位置參數(shù)布隔,比如一個文件列表离陶。傳遞給add_argument() 的第一個參數(shù)因此必須是一個標記序列或者一個簡單的參數(shù)名字。例如衅檀,一個可選的參數(shù)可以像這樣創(chuàng)建:
-
action action 關(guān)鍵字參數(shù)指出應(yīng)該如何處理命令行參數(shù)招刨。支持的動作有:
'store' - 只是保存參數(shù)的值。這是默認的動作
'store_const' - 保存由const關(guān)鍵字參數(shù)指出的值哀军。(注意const關(guān)鍵字參數(shù)默認是幾乎沒有幫助的None沉眶。)'store_const'動作最常用于指定某種標記的可選參數(shù)
'store_true'和'store_false' - 它們是'store_const' 的特殊情形,分別用于保存值True和False杉适。另外谎倔,它們分別會創(chuàng)建默認值False 和True。
'append' - 保存一個列表猿推,并將每個參數(shù)值附加在列表的后面片习。這對于允許指定多次的選項很有幫助。示例用法:
'append_const' - 保存一個列表蹬叭,并將const關(guān)鍵字參數(shù)指出的值附加在列表的后面藕咏。(注意const關(guān)鍵字參數(shù)默認是None。)'append_const' 動作在多個參數(shù)需要保存常量到相同的列表時特別有用具垫。例如:
'count' - 計算關(guān)鍵字參數(shù)出現(xiàn)的次數(shù)侈离。例如,這可用于增加詳細的級別:
'help' - 打印當前解析器中所有選項的完整的幫助信息然后退出筝蚕。默認情況下卦碾,help動作會自動添加到解析器中铺坞。參見ArgumentParser以得到如何生成輸出信息。
'version' - 它期待version=參數(shù)出現(xiàn)在add_argument()調(diào)用中洲胖,在調(diào)用時打印出版本信息并退出:
nargs 命令行參數(shù)的個數(shù)济榨,一般使用通配符表示,其中绿映,'?'表示只用一個擒滑,'*'表示0到多個,'+'表示至少一個
default 默認值
type 參數(shù)的類型叉弦,默認是字符串string類型丐一,還有float、int,file等類型choices 可以看做是default的擴展,參數(shù)的值必須在choices的范圍內(nèi)
required 一般情況下淹冰,argparse模塊假定-f和--bar標記表示可選參數(shù)库车,它們在命令行中可以省略。如果要使得選項是必需的樱拴,可以指定True作為required=關(guān)鍵字參數(shù)的值給add_argument()
help 和ArgumentParser方法中的參數(shù)作用相似柠衍,出現(xiàn)的場合也一致
006.子解析
像git這樣復(fù)雜的命令行工具,會有add push pull等分支晶乔,需要用到一個新的方法:
add_subparsers([title][, description][, prog][, parser_class][, action][, option_string][, dest][, help][, metavar])
- title - 在輸出的幫助中子解析器組的標題珍坊;默認情況下,如果提供description參數(shù)則為“subcommands”正罢,否則使用位置參數(shù)的標題
- description - 在輸出的幫助中子解析器組的描述阵漏,默認為None
- prog - 與子命令的幫助一起顯示的使用幫助信息,默認為程序的名字和子解析器參數(shù)之前的所有位置參數(shù)
- parser_class - 用于創(chuàng)建子解析器實例的類腺怯,默認為當前的解析器(例如ArgumentParser)
- dest - 子命令的名字應(yīng)該存儲的屬性名稱袱饭;默認為None且不存儲任何值
- help - 在輸出的幫助中子解析器中的幫助信息,默認為None
- metavar - 在幫助中表示可用的子命令的字符串呛占;默認為None并以{cmd1, cmd2, ..}的形式表示子命令
parser = argparse.ArgumentParser()
parser.add_argument('--foo', action='store_true', help='foo help')
subparsers = parser.add_subparsers(help='sub-command help')
parser_a = subparsers.add_parser('a', help='a help')
parser_a.add_argument('bar', type=int, help='bar help')
parser_b = subparsers.add_parser('b', help='b help')
parser_b.add_argument('--baz', choices='XYZ', help='baz help')
parser.parse_args(['a', '12'])
Namespace(bar=12, foo=False)
parser.parse_args(['--foo', 'b', '--baz', 'Z'])
Namespace(baz='Z', foo=True)
處理子命令的一個特別有效的方法是將add_subparsers()方法和set_defaults() 調(diào)用綁在一起使用虑乖,這樣每個子命令就可以知道它應(yīng)該執(zhí)行哪個Python 函數(shù)。例如:
def foo(args):
print(args.x * args.y)
def bar(args):
print('((%s))' % args.z)
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
parser_foo = subparsers.add_parser('foo')
parser_foo.add_argument('-x', type=int, default=1)
parser_foo.add_argument('y', type=float)
parser_foo.set_defaults(func=foo)
parser_bar = subparsers.add_parser('bar')
parser_bar.add_argument('z')
parser_bar.set_defaults(func=bar)
007.參數(shù)分組
很多時候參數(shù)是相互配合使用的,這就可以用add_argument_group(title=None, description=None)分組
parser = argparse.ArgumentParser(prog='PROG', add_help=False)
group1 = parser.add_argument_group('group1', 'group1 description')
group1.add_argument('foo', help='foo help')
group2 = parser.add_argument_group('group2', 'group2 description')
group2.add_argument('--bar', help='bar help')
008.多級子命令
如果我們的命令行工具有更加復(fù)雜的子命令解析需求,那么我們可以使用如下的方式做擴展:
class Command:
def __init__(self, argv):
parser = argparse.ArgumentParser(
description='xxxxxx',
usage='''xxxx <command> [<args>]
The most commonly used xxx commands are:
clean clean a project
install install a package
''')
parser.add_argument('command', help='Subcommand to run')
# parse_args defaults to [1:] for args, but you need to
# exclude the rest of the args too, or validation will fail
self.argv = argv
args = parser.parse_args(argv[0:1])
if not hasattr(self, args.command):
print('Unrecognized command')
parser.print_help()
exit(1)
# use dispatch pattern to invoke method with same name
getattr(self, args.command)()
def clean(self):
parser = argparse.ArgumentParser(
description='clean a project')
parser.add_argument(
'-A', '--all', action='store_true')
parser.set_defaults(func=clean)
args = parser.parse_args(self.argv[1:])
args.func(args)
def install(self):
parser = argparse.ArgumentParser(
description='install a package for this project')
parser.add_argument('packages', nargs='?', type=str, default="DEFAULT")
parser.add_argument(
'-D', '--dev', action='store_true')
parser.add_argument(
'-T', '--test', action='store_true')
parser.add_argument(
'-A', '--all', action='store_true')
parser.set_defaults(func=install)
args = parser.parse_args(self.argv[1:])
args.func(args)
print("install done!")
def main(argv: Sequence[str]=sys.argv[1:]):
Command(argv)
03.其他命令行解析工具
click是一個很符合Python編程風格的命令行解析晾虑,支持構(gòu)建比較復(fù)雜的命令行工具疹味。
fire是谷歌開源的命令行解析工具,可以直接根據(jù)函數(shù)參數(shù)解析成命令行帜篇,自動生成
docopt所見即所得的命令行解析工具糙捺,利用文件的__doc__
,寫完文檔注釋你的命令行解析也就實現(xiàn)了笙隙。
用<>包裹表示參數(shù),如果參數(shù)后面有...則表示參數(shù)是列表
用[]包裹選項
用()包裹必選內(nèi)容
用|區(qū)分選項
下面是一個實例:
%%writefile test/sqrt_doc.py
#!/usr/bin/env python
# coding:utf-8
u"""
Usage:
test1.py [option] <num>...
test1.py (-v|--version)
test1.py (-a|--all)
test1.py (-h|--help)
Options:
-h --help 幫助
-v --version 顯示版本號.
-a --all 顯示全部參數(shù)
"""
from docopt import docopt
from math import sqrt
__version__="0.1.0"
def version():
return "version:"+__version__
def main():
args = docopt(__doc__)
if args.get("-h") or args.get("-help"):
print(__doc__)
elif args.get("-v") or args.get("--version"):
print(__version__)
elif args.get("-a") or args.get("--all"):
print(args)
elif args.get("<num>"):
print(" ".join(map(lambda x :str(sqrt(float(x))),args.get("<num>"))))
else:
print("wrong args!")
print(__doc__)
if __name__ == '__main__':
main()
Writing test/sqrt_doc.py
04.命令行進度條
tqdm是一個進度條工具,除了可以給命令行工具增加進度條看出進度外,還可以用于jupyter-notebook
tqdm模塊的tqdm類是這個包的核心,所有功能都是在它上面衍生而來
tqdm類 可以包裝可迭代對象,它的實例化參數(shù)有:
desc : str, optional 放在bar前面的描述字符串
total : int, optional 顯示多長
leave : bool, optional 結(jié)束時時保留進度條的所有痕跡洪灯。
file : io.TextIOWrapper or io.StringIO, optional 輸出到文件
ncols : int, optional 自定義寬度
mininterval : float, optional 更新最短時間
maxinterval : float, optional 更新最大時間
miniters : int, optional 每次更新最小值
ascii : bool, optional 使用ascii碼顯示
disable : bool, optional 是否禁用整個progressbar
unit : str, optional 顯示的更新單位
unit_scale : bool, optional 根據(jù)單位換算進度
dynamic_ncols : bool, optional 可以不斷梗概ncols的環(huán)境
smoothing : float, optional 用于速度估計的指數(shù)移動平均平滑因子(在GUI模式中忽略)。范圍從0(平均速度)到1(當前/瞬時速度)[默認值:0.3]竟痰。
bar_format : str, optional 指定自定義欄字符串格式签钩√秃簦可能會影響性能
initial : int, optional 初始計數(shù)器值。重新啟動進度條時有用[默認值:0]铅檩。
position : int, optional 指定打印此條的線偏移(從0開始)如果未指定憎夷,則為自動。用于一次管理多個條
下面寫幾個程序?qū)嵗?/p>
# 900萬次循環(huán)
from tqdm import tqdm
for i in tqdm(range(int(9e6)),desc="test:"):
pass
test:: 100%|████████████████████████████████████████████████████████████| 9000000/9000000 [00:01<00:00, 4813939.90it/s]
for i in tqdm(range(int(9e6)),desc="test",dynamic_ncols=True):
pass
test: 100%|█████████████████████████████████████████████████████████████| 9000000/9000000 [00:01<00:00, 4998333.08it/s]
import time
# 使用with語句手動更新
with tqdm(total=100) as bar:
for i in range(10):
time.sleep(0.5)
bar.update(10)
100%|████████████████████████████████████████████████████████████████████████████████| 100/100 [00:05<00:00, 19.94it/s]
05.為命令行工具自動創(chuàng)建gui
Gooey是一個可以將python命令行自動轉(zhuǎn)成gui的工具,它依賴wxpython昧旨,下面給出的的例子是吧一個求開平方的命令行工具轉(zhuǎn)化為gui工具
這個工具貌似挺方便拾给,以后簡單的gui都不用寫了,直接自動生成兔沃。
%%writefile src/python/std/sqrt_std_gui.py
#!/usr/bin/env python3
import argparse
from math import sqrt
from gooey import Gooey, GooeyParser
__version__="0.1.0"
def sqrtarg(number):
return sqrt(number)
def version():
return "version:"+__version__
@Gooey(language='chinese')
def main():
parser = argparse.ArgumentParser()
parser.add_argument("number", type=int, help=u"求開根的參數(shù)")
parser.add_argument("-v","--version", help=u"查看版本號",action="store_true")
args = parser.parse_args()
if args.version:
print(version())
if args.number:
print(sqrtarg(args.number))
if __name__ == '__main__':
main()
06.命令行工具發(fā)布
下面介紹一個用setup.py把腳本安裝到python的腳本位置的例子
from distutils.core import setup
import os
pathroot = os.path.split(os.path.realpath(__file__))[0]
setup(
name='sqrt_doc',
version='0.1.0',
scripts=[pathroot+'/sqrt_doc.py']
)