作者:HelloGitHub-Prodesire
HelloGitHub 的《讲解开源项目》系列,项目地址:https://github.com/HelloGitHub-Team/Article
一、前言在上一篇文章中我们介绍了 fire 的子命令、嵌套命令和属性访问等内容,今天我们将继续深入了解 fire 的其他功能。
本系列文章默认使用 Python 3 作为解释器进行讲解。 若你仍在使用 Python 2,请注意两者之间语法和库的使用差异哦~ 二、功能 2.1 最简命令实现在上一节中,我们介绍了只要定义一个函数就可以实现命令行程序。比如:
import fire def english(): return 'Hello, fire!' def chinese(): return '你好,fire!' if __name__ == '__main__': fire.Fire()但这还不是最简单的实现方式,fire 甚至允许你通过定义变量的方式来实现命令行!
上面的例子可以写成下面这种形式:
在 Fire CLI 中,你可以通过链式调用不断地对上一个结果进行处理。
想做到这一点也很简单,就是在实例方法中返回 self 即可。
在下面的示例中,我们实现了一个简单的四则运算命令,可链式调用 add、sub、mul 和 div。
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 中用来完成自定义序列化。如果不提供这个方法,在链式调用完成后将会打印帮助内容。
比如,我们可以这么调用:
$ 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 2.3 位置参数和选项参数通过前面的介绍我们也都清楚了在 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') 2.4 参数类型