涉及的示例代碼和歷史文章,已同步更新到 HelloGitHub-Team 倉庫python
在上一篇文章中咱們介紹了 fire
的子命令、嵌套命令和屬性訪問等內容,今天咱們將繼續深刻了解 fire
的其餘功能。git
本系列文章默認使用 Python 3 做爲解釋器進行講解。
若你仍在使用 Python 2,請注意二者之間語法和庫的使用差別哦~
複製代碼
在上一節中,咱們介紹了只要定義一個函數就能夠實現命令行程序。好比:github
import fire
def english():
return 'Hello, fire!'
def chinese():
return '你好,fire!'
if __name__ == '__main__':
fire.Fire()
複製代碼
但這還不是最簡單的實現方式,fire
甚至容許你經過定義變量的方式來實現命令行! 上面的例子能夠寫成下面這種形式:shell
import fire
english = 'Hello, fire!'
chinese = '你好,fire!'
if __name__ == '__main__':
fire.Fire()
複製代碼
在 Fire CLI
中,你能夠經過鏈式調用不斷地對上一個結果進行處理。express
想作到這一點也很簡單,就是在實例方法中返回 self
便可。編程
在下面的示例中,咱們實現了一個簡單的四則運算命令,可鏈式調用 add
、sub
、mul
和 div
。bash
import fire
class Calculator:
def __init__(self):
self.result = 0
self.express = '0'
def __str__(self):
return f'{self.express} = {self.result}'
def add(self, x):
self.result += x
self.express = f'{self.express}+{x}'
return self
def sub(self, x):
self.result -= x
self.express = f'{self.express}-{x}'
return self
def mul(self, x):
self.result *= x
self.express = f'({self.express})*{x}'
return self
def div(self, x):
self.result /= x
self.express = f'({self.express})/{x}'
return self
if __name__ == '__main__':
fire.Fire(Calculator)
複製代碼
上述代碼中的 add
、sub
、mul
、div
分別對應加、減、乘、除的邏輯,每一個方法都接受 x
參數做爲參與運算的數字,返回值均爲 self
,這樣就能夠無限次地鏈式調用。在命令行中鏈式調用結束後,會最終調用到 __str__
方法將結果打印出來。函數
其中,__str__
在 fire
中用來完成自定義序列化。若是不提供這個方法,在鏈式調用完成後將會打印幫助內容。ui
好比,咱們能夠這麼調用:spa
$ python calculator.py add 1 sub 2 mul 3 div 4
((+1-2)*3)/4 = -0.75
$ python calculator.py add 1 sub 2 mul 3 div 4 add 4 sub 3 mul 2 div 1
((((0+1-2)*3)/4+4-3)*2)/1 = 0.5
複製代碼
經過前面的介紹咱們也都清楚了在 fire
中沒必要顯式的定義位置參數或選項參數。
經過下面的例子,咱們將細化兩類參數的使用:
import fire
class Building(object):
def __init__(self, name, stories=1):
self.name = name
self.stories = stories
def __str__(self):
return f'name: {self.name}, stories: {self.stories}'
def climb_stairs(self, stairs_per_story=10):
yield self.name
for story in range(self.stories):
for stair in range(1, stairs_per_story):
yield stair
yield 'Phew!'
yield 'Done!'
if __name__ == '__main__':
fire.Fire(Building)
複製代碼
name
和 stories
)在命令行中僅爲選項參數(如 --name
和 --stories
)。咱們能夠這麼調用:$ python example.py --name="Sherrerd Hall" --stories=3
複製代碼
$ python example.py --name="Sherrerd Hall" climb-stairs --stairs-per-story 10
$ python example.py climb-stairs --stairs-per-story 10 --name="Sherrerd Hall"
複製代碼
stories
),在命令行中是可選的。咱們能夠這麼調用:$ python example.py --name="Sherrerd Hall"
複製代碼
stairs_per_story
)在命令行中便可以是位置參數,也能夠是選項參數。咱們能夠這麼調用:# 做爲位置參數
$ python example.py --name="Sherrerd Hall" climb_stairs 10
# 做爲選項參數
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs_per_story=10
複製代碼
-
)和下劃線(_
)是等價的。所以也能夠這麼調用:# 做爲選項參數
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs-per-story=10
複製代碼
此外,fire
還支持在函數中定義 *args
和 **kwargs
。
import fire
def fargs(*args):
return str(args)
def fkwargs(**kwargs):
return str(kwargs)
if __name__ == '__main__':
fire.Fire()
複製代碼
*args
在命令行中爲位置參數。咱們能夠這麼調用:$ python example.py fargs a b c
複製代碼
**kwargs
在命令行中爲選項參數。咱們能夠這麼調用:$ python example.py fargs --a a1 --b b1 --c c1
複製代碼
-
可顯式告知分隔符後的爲子命令,而非命令的參數。且看下面的示例:# 沒有使用分隔符,upper 被做爲位置參數
$ python example.py fargs a b c upper
('a', 'b', 'c', 'upper')
# 使用了分隔符,upper 被做爲子命令
$ python example.py fargs a b c - upper
('A', 'B', 'C')
複製代碼
fire
內置的 --separator
能夠自定義分隔符,此選項參數須要跟在單獨的 --
後面:$ python example.py a b c X upper -- --separator=X
('A', 'B', 'C')
複製代碼
在 fire
中,參數的類型由其值決定,經過下面的簡單代碼,咱們能夠看到給不一樣的值時,fire
會解析爲何類型:
import fire
fire.Fire(lambda obj: type(obj).__name__)
複製代碼
$ python example.py 10
int
$ python example.py 10.0
float
$ python example.py hello
str
$ python example.py '(1,2)'
tuple
$ python example.py [1,2]
list
$ python example.py True
bool
$ python example.py {name: David}
dict
複製代碼
若是想傳遞字符串形式的數字,那就須要當心引號了,要麼把引號引發來,要麼轉義引號:
# 數字 10
$ python example.py 10
int
# 沒有對引號處理,仍然是數字10
$ python example.py "10"
int
# 把引號引發來,因此是字符串「10」
$ python example.py '"10"'
str
# 另外一種把引號引發來的形式
$ python example.py "'10'"
str
# 轉義引號
$ python example.py \"10\" str 複製代碼
考慮下更復雜的場景,若是傳遞的是字典,在字典中有字符串,那麼也是要當心引號的:
# 推薦作法
$ python example.py '{"name": "David Bieber"}'
dict
# 也是能夠的
$ python example.py {"name":'"David Bieber"'}
dict
# 錯誤,會被解析爲字符串
$ python example.py {"name":"David Bieber"}
str
# 錯誤,不會做爲單個參數(由於中間有空格),報錯
$ python example.py {"name": "David Bieber"}
<error>
複製代碼
若是值爲 True
或 False
將爲視爲布爾值,fire
還支持經過 --name
將 name
設爲 True
,或經過 --noname
將 name
設爲 False
:
$ python example.py --obj=True
bool
$ python example.py --obj=False
bool
$ python example.py --obj
bool
$ python example.py --noobj
bool
複製代碼
Fire 內置了一些選項參數,以幫助咱們更容易地使用命令行程序。若想使用內置的選項功能,須要將選項參數跟在 --
後,在上文中,咱們介紹了 --separator
參數,除了它,fire
還支持如下選項參數:
command -- --help
列出詳細的幫助信息command -- --interactive
進入交互式模式command -- --completion [shell]
生成 CLI 程序的自動補全腳本,以支持自動補全command -- --trace
獲取命令的 Fire 追蹤以瞭解調用 Fire 後究竟發生了什麼command -- --verbose
獲取包含私有成員在內的詳情fire
讓命令行程序的實現變得特別簡單,本文着重介紹了它的鏈式調用、選項參數、位置參數、參數類型以及內置選項參數。fire
的概念並很少,真正踐行了「把簡單留給他人,把複雜留給本身」的理念。
fire
的介紹就告一段落,它絕對會是你編寫命令行程序的一大利器。在下一篇文章中,咱們依然會經過實現一個簡單的 git
程序來進行 fire
的實戰。
『講解開源項目系列』——讓對開源項目感興趣的人再也不畏懼、讓開源項目的發起者再也不孤單。跟着咱們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎留言聯繫咱們、加入咱們,讓更多人愛上開源、貢獻開源~