Python fire官方文档教学(自动生成命令行,个人觉得意义不大,不如argparse)
0x00 簡(jiǎn)介
歡迎來(lái)到Python Fire指南! Python Fire是一個(gè)Python庫(kù),只需對(duì)Fire進(jìn)行一次調(diào)用即可將任何Python組件轉(zhuǎn)變?yōu)槊钚薪缑妗?/p>
讓我們開(kāi)始吧!
0x01 安裝
從pypi安裝Python Fire,請(qǐng)運(yùn)行:
pip install fire
或者,從源代碼安裝Python Fire,請(qǐng)下載源代碼并運(yùn)行:
python setup.py install
0x02 Hello World
Version 1:?fire.Fire()
使用Fire最簡(jiǎn)單的方法是在任何Python程序結(jié)束時(shí)調(diào)用fire.Fire()。 這會(huì)將程序的全部?jī)?nèi)容暴露給命令行。
import firedef hello(name):return 'Hello {name}!'.format(name=name)if __name__ == '__main__':fire.Fire()從命令行運(yùn)行程序:
$ python example.py hello World Hello World!Version 2:?fire.Fire(<fn>)
讓我們稍微修改我們的程序,只將hello函數(shù)暴露給命令行。
import firedef hello(name):return 'Hello {name}!'.format(name=name)if __name__ == '__main__':fire.Fire(hello)以下是我們?nèi)绾螐拿钚羞\(yùn)行該命令的方法:
$ python example.py World Hello World!注意我們不再需要指定hello函數(shù),因?yàn)槲覀冋{(diào)用了fire.Fire(hello)。
Version 3: Using a main
我們也可以這樣寫(xiě)這個(gè)程序:
import firedef hello(name):return 'Hello {name}!'.format(name=name)def main():fire.Fire(hello)if __name__ == '__main__':main()或者如果我們使用entry points,那么代碼更加簡(jiǎn)潔:
import firedef hello(name):return 'Hello {name}!'.format(name=name)def main():fire.Fire(hello)0x03 Exposing Multiple Commands
在前面的例子中,我們向命令行暴露了一個(gè)函數(shù)。 現(xiàn)在我們來(lái)看看如何將多個(gè)函數(shù)暴露給命令行。
Version 1:?fire.Fire()
暴露多個(gè)命令最簡(jiǎn)單的方法是編寫(xiě)多個(gè)函數(shù),然后調(diào)用Fire。
import firedef add(x, y):return x + ydef multiply(x, y):return x * yif __name__ == '__main__':fire.Fire()我們可以這樣使用它:
$ python example.py add 10 20 30 $ python example.py multiply 10 20 200你會(huì)注意到Fire正確地將10和20解析為數(shù)字,而不是字符串。 可以看0X09 參數(shù)解析。
Version 2:?fire.Fire(<dict>)
在Version 1中,我們將所有程序的功能暴露給命令行。 通過(guò)使用字典,我們可以有選擇性地將一些函數(shù)暴露給命令行。
import firedef add(x, y):return x + ydef multiply(x, y):return x * yif __name__ == '__main__':fire.Fire({'add': add,'multiply': multiply,})我們可以像以前一樣使用它:
$ python example.py add 10 20 30 $ python example.py multiply 10 20 200Version 3:?fire.Fire(<object>)
正如在這個(gè)變體中一樣,Fire 也適用于object。 這是暴露多個(gè)命令的一個(gè)好的做法。
import fireclass Calculator(object):def add(self, x, y):return x + ydef multiply(self, x, y):return x * yif __name__ == '__main__':calculator = Calculator()fire.Fire(calculator)我們可以像之前那樣使用它:
$ python example.py add 10 20 30 $ python example.py multiply 10 20 200Version 4:?fire.Fire(<class>)
Fire也適用于class。 這是暴露多個(gè)命令的另一個(gè)好的做法。
import fireclass Calculator(object):def add(self, x, y):return x + ydef multiply(self, x, y):return x * yif __name__ == '__main__':fire.Fire(Calculator)我們可以像之前那樣使用它:
$ python example.py add 10 20 30 $ python example.py multiply 10 20 200為什么我們更喜歡使用class而不是object? 一個(gè)原因是你可以給構(gòu)造類傳遞參數(shù),就像這個(gè)BrokenCalculator例子一樣。
import fireclass BrokenCalculator(object):def __init__(self, offset=1):self._offset = offsetdef add(self, x, y):return x + y + self._offsetdef multiply(self, x, y):return x * y + self._offsetif __name__ == '__main__':fire.Fire(BrokenCalculator)當(dāng)你使用BrokenCalculator時(shí),你會(huì)得到錯(cuò)誤的答案:
$ python example.py add 10 20 31 $ python example.py multiply 10 20 201但你可以這樣解決它:
$ python example.py add 10 20 --offset=0 30 $ python example.py multiply 10 20 --offset=0 200與調(diào)用普通函數(shù)不同,它可以通過(guò)位置參數(shù)和命名參數(shù)(--flag語(yǔ)法)完成,而__init__函數(shù)的參數(shù)必須以--flag語(yǔ)法傳遞。 請(qǐng)參閱0x08 函數(shù)調(diào)用。
0x04 分組命令
下面是一個(gè)如何使用分組命令創(chuàng)建命令行界面的示例。
class IngestionStage(object):def run(self):return 'Ingesting! Nom nom nom...'class DigestionStage(object):def run(self, volume=1):return ' '.join(['Burp!'] * volume)def status(self):return 'Satiated.'class Pipeline(object):def __init__(self):self.ingestion = IngestionStage()self.digestion = DigestionStage()def run(self):self.ingestion.run()self.digestion.run()if __name__ == '__main__':fire.Fire(Pipeline)以下是使用方式:
$ python example.py run Ingesting! Nom nom nom... Burp! $ python example.py ingestion run Ingesting! Nom nom nom... $ python example.py digestion run Burp! $ python example.py digestion status Satiated.你可以用任意復(fù)雜的方式嵌套你的命令。
0x05 屬性訪問(wèn)
到目前為止,在所有例子中,我們通過(guò)python example.py運(yùn)行了示例程序的一些功能。 在下面這個(gè)例子中,我們只訪問(wèn)一個(gè)屬性。
from airports import airportsimport fireclass Airport(object):def __init__(self, code):self.code = codeself.name = dict(airports).get(self.code)self.city = self.name.split(',')[0] if self.name else Noneif __name__ == '__main__':fire.Fire(Airport)現(xiàn)在我們可以使用下面的方式使用Airport代碼!
$ python example.py --code=JFK code JFK $ python example.py --code=SJC name San Jose-Sunnyvale-Santa Clara, CA - Norman Y. Mineta San Jose International (SJC) $ python example.py --code=ALB city Albany-Schenectady-Troy(譯者注:注意這里--code就是0x03 Exposing Multiple Commands最后說(shuō)的,給__init__傳遞參數(shù),必須使用–flag語(yǔ)法)
0x06 鏈?zhǔn)胶瘮?shù)調(diào)用
當(dāng)您運(yùn)行Fire CLI時(shí),您可以對(duì)調(diào)用Fire的結(jié)果采取所有相同的操作。
例如,我們可以這樣使用之前的Airport例子:
$ python example.py --code=ALB city upper ALBANY-SCHENECTADY-TROY這是可行的,因?yàn)閡pper是所有字符串的一種方法。
所以,如果你想設(shè)置你的函數(shù)鏈?zhǔn)秸{(diào)用,你只需要設(shè)置方法返回self。下面通過(guò)一個(gè)例子說(shuō)明:
import fireclass BinaryCanvas(object):"""A canvas with which to make binary art, one bit at a time."""def __init__(self, size=10):self.pixels = [[0] * size for _ in range(size)]self._size = sizeself._row = 0 # The row of the cursor.self._col = 0 # The column of the cursor.def __str__(self):return '\n'.join(' '.join(str(pixel) for pixel in row) for row in self.pixels)def show(self):print(self)return selfdef move(self, row, col):self._row = row % self._sizeself._col = col % self._sizereturn selfdef on(self):return self.set(1)def off(self):return self.set(0)def set(self, value):self.pixels[self._row][self._col] = valuereturn selfif __name__ == '__main__':fire.Fire(BinaryCanvas)現(xiàn)在我們可以繪制東西:)。
$ python example.py move 3 3 on move 3 6 on move 6 3 on move 6 6 on move 7 4 on move 7 5 on __str__ 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0它應(yīng)該是一個(gè)笑臉。
0x07 有沒(méi)有比Hello World更簡(jiǎn)單的例子?
有,下面這個(gè)程序比我們之前的Hello World例子更簡(jiǎn)單。
import fire english = 'Hello World' spanish = 'Hola Mundo' fire.Fire()你可以像這樣使用它:
$ python example.py english Hello World $ python example.py spanish Hola Mundo0x08 函數(shù)調(diào)用
構(gòu)造函數(shù)的參數(shù)可以使用--flag語(yǔ)法--name = value傳遞。
例如,考慮這個(gè)簡(jiǎn)單的類:
import fireclass Building(object):def __init__(self, name, stories=1):self.name = nameself.stories = 1def climb_stairs(self, stairs_per_story=10):for story in range(self.stories):for stair in range(1, stairs_per_story):yield stairyield 'Phew!'yield 'Done!'if __name__ == '__main__':fire.Fire(Building)我們可以通過(guò)這種方式實(shí)例化它:python example.py --name ="Sherrerd Hall"
其他函數(shù)的參數(shù)同樣可以使用--flag語(yǔ)法來(lái)傳遞。
要實(shí)例化一個(gè)Building,然后運(yùn)行climb_stairs函數(shù),以下命令都是有效的:
$ python example.py --name="Sherrerd Hall" --stories=3 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 $ python example.py climb-stairs --stairs-per-story 10 --name="Sherrerd Hall"你會(huì)注意到連字符和下劃線(?-和_)在成員名稱和標(biāo)志名稱中是可以互換的。
你還會(huì)注意到構(gòu)造函數(shù)的參數(shù)可以在其他函數(shù)的參數(shù)之后或函數(shù)之前。
你還會(huì)注意到,標(biāo)志名稱和其值之間的等號(hào)是可選的。
帶有*varargs和** kwargs的函數(shù)
Fire支持帶*varargs或** kwargs的函數(shù)。 這是一個(gè)例子:
import firedef order_by_length(*items):"""Orders items by length, breaking ties alphabetically."""sorted_items = sorted(items, key=lambda item: (len(str(item)), str(item)))return ' '.join(sorted_items)if __name__ == '__main__':fire.Fire(order_by_length)要使用它,我們這樣運(yùn)行:
$ python example.py dog cat elephant cat dog elephant你可以使用分隔符給函數(shù)提供參數(shù)。分隔符后的所有參數(shù)將用于處理函數(shù)的結(jié)果,而不是傳遞給函數(shù)本身。 默認(rèn)分隔符是連字符?-。
以下是我們使用分隔符的示例。
$ python example.py dog cat elephant - upper CAT DOG ELEPHANT如果沒(méi)有分隔符,upper就會(huì)被當(dāng)作另一個(gè)參數(shù)。
$ python example.py dog cat elephant upper cat dog upper elephant你可以使用--separator標(biāo)志更改分隔符。通過(guò)--將標(biāo)志與你的Fire指令隔開(kāi) 。 以下是我們更改分隔符的示例。
$ python example.py dog cat elephant X upper -- --separator=X CAT DOG ELEPHANT當(dāng)函數(shù)接受*varargs,**kwargs或你不想指定的默認(rèn)值時(shí),分隔符會(huì)很有用。作為參數(shù),更改分隔符也很重要。
0x09 參數(shù)解析
參數(shù)的類型取決于它們的值,而不是使用它們的函數(shù)簽名。 您可以從命令行傳遞任何Python文本:數(shù)字,字符串,元組,列表,字典(僅在某些版本的Python中支持集合)。只要它們只包含文字,您也可以任意嵌套這些集合。
為了演示這個(gè),我們將制作一個(gè)小程序,通過(guò)這個(gè)小程序告訴我們傳給它的參數(shù)類型:
import fire fire.Fire(lambda obj: type(obj).__name__)我們會(huì)像這樣使用它:
$ 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在最后一個(gè)例子中,你會(huì)注意到裸詞會(huì)自動(dòng)替換為字符串。
要注意! 如果你想傳遞字符串"10"而不是int 10,你需要轉(zhuǎn)義或者引用你的引號(hào)。 否則,Bash將會(huì)把你的引用取消并將一個(gè)沒(méi)有引號(hào)的10傳遞給你的Python程序,在那里Fire將把它解釋為一個(gè)數(shù)字。
$ python example.py 10 int $ python example.py "10" int $ python example.py '"10"' str $ python example.py "'10'" str $ python example.py \"10\" str要注意! 記住Bash首先處理你的參數(shù),然后Fire解析結(jié)果。 如果你想將dict {"name":"David Bieber"}傳遞給你的程序,你可以試試這個(gè):
$ python example.py '{"name": "David Bieber"}' # Good! Do this. dict $ python example.py {"name":'"David Bieber"'} # Okay. dict $ python example.py {"name":"David Bieber"} # Wrong. This is parsed as a string. str $ python example.py {"name": "David Bieber"} # Wrong. This isn't even treated as a single argument. <error> $ python example.py '{"name": "Justin Bieber"}' # Wrong. This is not the Bieber you're looking for. (The syntax is fine though :)) dictbool類型參數(shù)
True和False被解析為布爾值。
你也可以通過(guò)--flag語(yǔ)法--name和--noname來(lái)指定布爾值,它們分別將名稱設(shè)置為T(mén)rue和False。
繼續(xù)前面的例子,我們可以運(yùn)行以下任何一個(gè):
$ python example.py --obj=True bool $ python example.py --obj=False bool $ python example.py --obj bool $ python example.py --noobj bool要注意! 如果除另一個(gè)標(biāo)志之外的標(biāo)志緊跟在應(yīng)該是布爾值的標(biāo)志之后,該標(biāo)志將取代該標(biāo)志的值而不是布爾值。 您可以解決這個(gè)問(wèn)題:通過(guò)在最后一個(gè)標(biāo)志之后放置一個(gè)分隔符,明確指出布爾標(biāo)志的值(如--obj = True),或者確保在布爾標(biāo)志參數(shù)后面有另一個(gè)標(biāo)志。
0x10 Using Fire Flags
Fire CLI自己也帶有一些標(biāo)志。這些標(biāo)志應(yīng)該通過(guò)--與Fire命令分開(kāi)。如果至少有一個(gè)--,那么在最后一個(gè)--之后的參數(shù)將被視為標(biāo)志,而在最后一個(gè)--之前的所有參數(shù)都被視為Fire命令的一部分。
一個(gè)有用的標(biāo)志是--interactive。在任何CLI上使用--interactive標(biāo)志輸入一個(gè)Python REPL,其中包含已調(diào)用Fire的上下文中使用的所有模塊和變量。其他有用的變量,例如Fire命令的結(jié)果也將可用。像這樣使用這個(gè)特性:python example.py -- --interactive。
你可以將幫助標(biāo)志添加到任何命令中,用來(lái)查看幫助和使用信息。 Fire將文檔結(jié)合到它生成的幫助和使用信息中。即使你省略了--,Fire也會(huì)試圖提供幫助,它會(huì)將標(biāo)志從Fire命令中分離出來(lái)。但并不總是如此,因?yàn)閔elp是一個(gè)有效的參數(shù)名稱。像這樣使用這個(gè)特性:python example.py -- --help。
下面Reference部分中顯示了完整的可用標(biāo)志集。
Reference
| install | pip install fire | ? |
Creating a CLI
| import | import fire | ? |
| Call | fire.Fire() | Turns the current module into a Fire CLI. |
| Call | fire.Fire(component) | Turns?component?into a Fire CLI. |
Flags
| Help | command -- --help | Show help and usage information for the command. |
| REPL | command -- --interactive | Enter interactive mode. |
| Separator | command -- --separator=X | This sets the separator to?X. The default separator is?-. |
| Completion | command -- --completion | Generate a completion script for the CLI. |
| Trace | command -- --trace | Gets a Fire trace for the command. |
| Verbose | command -- --verbose | Include private members in the output. |
Note that flags are separated from the Fire command by an isolated – arg.
source code
-
https://github.com/google/python-fire
總結(jié)
以上是生活随笔為你收集整理的Python fire官方文档教学(自动生成命令行,个人觉得意义不大,不如argparse)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: bzoj 5216 [Lydsy2017
- 下一篇: XFF漏洞利用说明