前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >Python 命令行工具:Fire (已验证)

Python 命令行工具:Fire (已验证)

作者头像
用户10002156
发布于 2022-09-05 01:59:28
发布于 2022-09-05 01:59:28
58600
代码可运行
举报
文章被收录于专栏:生活处处有BUG生活处处有BUG
运行总次数:0
代码可运行

Fire介绍

fire 可以根据任何 Python 对象自动生成命令行接口。它有如下特性:

  • 能以简单的方式生成 CLI
  • 是一个开发和调试 Python 代码的实用工具
  • 能将现存代码或别人的代码转换为 CLI
  • 使得在 Bash 和 Python 间的转换变得更容易
  • 通过预先为 REPL 设置所需的模块和变量,使得实用 REPL 更加容易

安装

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
pip install fire

调用方法

函数调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

def hello(name="World"):
  return 'Hello {name}!'.format(name=name)

if __name__ == '__main__':
  fire.Fire(hello)

在上述例子中定义一个 hello 函数,它接受 name 参数,并且有默认值 "World"。使用 fire.Fire(hello) 即可非常简单快速地实现命令功能,这个命令行就接受 --name 选项,不提供时使用默认值 "World",提供时就按提供的值来。

可在命令行中执行下列命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python hello.py
Hello World!
$ python hello.py --name=Xj
Hello Xj!
$ python hello.py --help
INFO: Showing help with the command 'hello.py -- --help'.

NAME
    hello.py

SYNOPSIS
    hello.py <flags>

FLAGS
    --name=NAME
隐式使用 fire.Fire()

实现子命令最简单的方式就是定义若干个函数,每个函数名隐式就是子命令名称,然后调用 fire.Fire() 变将当前模块所有的函数解析为对应的子命令的处理函数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

def add(x, y):
  return x + y

def multiply(x, y):
  return x * y

if __name__ == '__main__':
  fire.Fire()

然后我们就可以在命令行中这么调用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py add 10 20
30
$ python example.py multiply 10 20
200
显式使用 fire.Fire()

有时我们可能只想把部分函数当做子命令,或者是希望子命令名称和函数名称不一样。这个时候我们就可以通过字典对象显式地告诉 fire

字典对象的形式为 {'子命令名称':函数},比如前面的示例中,我们希望最终的子命令为 add2mul2,那么就可以这么写:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fire.Fire({
  'add2': add,
  'mul2': multiply,
})

然后我们就可以在命令行中这么调用。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py add2 10 20
30
$ python example.py mul2 10 20
200

类调用

使用函数是最简单的方式,如果我们想以更有组织的方式来实现,比如使用类, fire 也是支持的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

class Calculator(object):
  """A simple calculator class."""

  def double(self, number):
    return 2 * number

  def triple(self, number):
    return 3 * number

if __name__ == '__main__':
  fire.Fire(Calculator)

在上述例子中定义一个 Calculator 类,它有两个实例方法 doubletriple,并且都接受 number 参数,没有默认值。使用 fire.Fire(Calculator) 即可非常简单快速地实现命令功能,这个命令行支持两个子命令 doubletriple,位置参数 NUMBER 或选项参数 --number

可在命令行中执行下列命令:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python calculator.py double 10
20
$ python calculator.py triple --number=15
45
$ python calculator.py double --help
INFO: Showing help with the command 'calculator.py double -- --help'.

NAME
    calculator.py double

SYNOPSIS
    calculator.py double NUMBER

POSITIONAL ARGUMENTS
    NUMBER

NOTES
    You can also use flags syntax for POSITIONAL ARGUMENTS
实例化的对象使用 fire.Fire()

将类实例化,并把实例化的对象作为 fire.Fire 的入参:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

class Calculator(object):

  def add(self, x, y):
    return x + y

  def multiply(self, x, y):
    return x * y

if __name__ == '__main__':
  calculator = Calculator()
  fire.Fire(calculator)
类使用 fire.Fire()

这里把类而非实例对象作为 fire.Fire 的入参:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
fire.Fire(Calculator)

传递类和实例对象的基本作用是一样的,但传递类还有一个额外的特性:如果构造函数中定义了参数,那么这些参数都会作为整个命令行程序的选项参数。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

class BrokenCalculator(object):

  def __init__(self, offset=1):
      self._offset = offset

  def add(self, x, y):
    return x + y + self._offset

  def multiply(self, x, y):
    return x * y + self._offset

if __name__ == '__main__':
  fire.Fire(BrokenCalculator)

查看帮助命令有:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py --help
INFO: Showing help with the command 'example.py -- --help'.

NAME
    example.py

SYNOPSIS
    example.py <flags>

FLAGS
    --offset=OFFSET

由此可见构造函数 BrokenCalculator.__init__(self,offset=1) 中的 offset 自动转换为了命令行中的全局选项参数 --offset,且默认值为 1

我们可以在命令行中这么调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ 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
命令组/嵌套命令

想要实现嵌套命令,可将多个类组织起来,示例如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

class IngestionStage(object):

  def run(self):
    print('Ingesting! Nom nom nom...')

class DigestionStage(object):

  def run(self, volume=1):
    print(' '.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()
    print('pipeline is runing.')

if __name__ == '__main__':
  fire.Fire(Pipeline)

在上面的示例中:

  • IngestionStage 实现了子命令 run
  • DigestionStage 实现了子命令 runstatus
  • Pipeline 的构造函数中将 IngestionStage 实例化为 ingestion,将 DigestionStage 实例化为 digestion,就将这两个放到一个命令组中,因而支持了:
  • ingestion run
  • digestion run
  • digestion status
  • Pipeline 实现了子命令 run

因此整个命令行程序支持如下命令:

  • run
  • ingestion run
  • digestion run
  • digestion status

然后我们就可以在命令行中这么调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py run
Ingesting! Nom nom nom...
Burp!
pipeline is runing.
$ python example.py ingestion run
Ingesting! Nom nom nom...
$ python example.py digestion run
Burp!
$ python example.py digestion status
Satiated.
属性访问

属性访问fire 相对于其他命令行库来说一个比较独特的功能。所谓访问属性是获取预置的属性所对应的值。

举个例子,在命令行中指定 --code 来告知程序要查询的程序编码,然后希望通过 zipcode 属性返回邮编,通过 city 属性返回城市名。那么属性可实现为实例成员属性:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

cities = {
  'hz': (310000, '杭州'),
  'bj': (100000, '北京'),
}

class City(object):

  def __init__(self, code):
    info = cities.get(code)
    self.zipcode = info[0] if info else None
    self.city = info[1] if info else None

if __name__ == '__main__':
  fire.Fire(City)

使用方式如下:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py --code bj zipcode
100000
$ python example.py --code hz city
杭州

链式调用

FireCLI 中,你可以通过链式调用不断地对上一个结果进行处理。

想做到这一点也很简单,就是在实例方法中返回 self 即可。

在下面的示例中,我们实现了一个简单的四则运算命令,可链式调用 addsubmuldiv

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)

上述代码中的 addsubmuldiv 分别对应加、减、乘、除的逻辑,每个方法都接受 x 参数作为参与运算的数字,返回值均为 self,这样就可以无限次地链式调用。在命令行中链式调用结束后,会最终调用到 __str__ 方法将结果打印出来。

其中, __str__fire 中用来完成自定义序列化。如果不提供这个方法,在链式调用完成后将会打印帮助内容。

比如,我们可以这么调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ 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

参数

位置参数和选项参数

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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)

构造函数中定义的参数(如 namestories)在命令行中仅为选项参数(如 --name--stories)。我们可以这么调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py --name="Sherrerd Hall" --stories=3
name: Sherrerd Hall, stories: 3

构造函数中定义的参数可在命令中放于任意位置。比如下面两个调用都是可以的。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py --name="Sherrerd Hall" climb-stairs --stairs-per-story 10
Sherrerd Hall
1
2
3
4
5
6
7
8
9
Phew!
Done!
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py climb-stairs --stairs-per-story 10 --name="Sherrerd Hall"
Sherrerd Hall
1
2
3
4
5
6
7
8
9
Phew!
Done!

构造函数和普通方法中定义的默认参数(如 stories),在命令行中是可选的。我们可以这么调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py --name="Sherrerd Hall"

普通方法中定义的参数(如 stairs_per_story)在命令行中即可以是位置参数,也可以是选项参数。我们可以这么调用:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 作为位置参数
$ python example.py --name="Sherrerd Hall" climb_stairs 10
# 作为选项参数
$ python example.py --name="Sherrerd Hall" climb_stairs --stairs_per_story=10

此外, fire 还支持在函数中定义 *args**kwargs

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
import fire

def fargs(*args):
  return str(args)


def fkwargs(**kwargs):
  return str(kwargs)

if __name__ == '__main__':
  fire.Fire()

函数中的 *args 在命令行中为位置参数。我们可以这么调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py fargs a b c
('a', 'b', 'c')

函数中的 **kwargs 在命令行中为选项参数。我们可以这么调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
python example.py fkwargs --a a1 --b b2 --c c3
{'a': 'a1', 'b': 'b2', 'c': 'c3'}

通过分隔符 - 可显式告知分隔符后的为子命令,而非命令的参数。且看下面的示例:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 没有使用分隔符,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 可以自定义分隔符,此选项参数需要跟在单独的 -- 后面

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py fargs a b c X upper -- --separator=X
('A', 'B', 'C')

参数类型

fire 中,参数的类型由其值决定,通过下面的简单代码,我们可以看到给不同的值时, fire会解析为什么类型.

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
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

如果想传递字符串形式的数字,那就需要小心引号了,要么把引号引起来,要么转义引号

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 数字 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

考虑下更复杂的场景,如果传递的是字典,在字典中有字符串,那么也是要小心引号的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
# 推荐做法
$ 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>

如果值为 TrueFalse 将为视为布尔值, fire 还支持通过 --namename 设为 True,或通过 --nonamename 设为 False

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
$ python example.py --obj=True
bool
$ python example.py --obj=False
bool
$ python example.py --obj
bool
$ python example.py --noobj
bool

Fire 内置选项参数

Fire 内置了一些选项参数,以帮助我们更容易地使用命令行程序。若想使用内置的选项功能,需要将选项参数跟在 -- 后,在上文中,我们介绍了 --separator 参数,除了它, fire 还支持以下选项参数:

  • command----help 列出详细的帮助信息
  • command----interactive 进入交互式模式
  • command----completion[shell] 生成 CLI 程序的自动补全脚本,以支持自动补全
  • command----trace 获取命令的 Fire 追踪以了解调用 Fire 后究竟发生了什么
  • command----verbose 获取包含私有成员在内的详情

注:源文为HelloGitHub公众号的《Google 开源的 Python 命令行库:深入 fire》,已整理、验证和润色。

您的关注,是我的无限动力! 公众号 @生活处处有BUG CSDN @生活处处有BUG

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-08-15,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 生活处处有BUG 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Google 开源的 Python 命令行库:深入 fire(二)
在上一篇文章中我们介绍了 fire 的子命令、嵌套命令和属性访问等内容,今天我们将继续深入了解 fire 的其他功能。
HelloGitHub
2021/05/14
3470
Google 开源的 Python 命令行库:深入 fire(一)
在第一篇“初探 fire”的文章中,我们初步掌握了使用 fire 的简单步骤,了解了它 Pythonic 的用法。
HelloGitHub
2021/05/14
7260
python-fire的使用
本文完全转载自:https://github.com/google/python-fire/blob/master/docs/guide.md#version-3-firefireobject
py3study
2020/01/08
9430
Python编写完善的命令行工具,只需要一行代码
提到编写命令行工具,你可能会想到用 sys.argv 或者标准库 argparse,没错,这两个很常用,不过情况复杂时没有那么方便和高效,因此今天分享两个工具,让你编写命令行工具不费吹灰之力。
somenzz
2021/07/01
1.4K0
Python编写完善的命令行工具,只需要一行代码
15600+星的 Python Fire为什么这么火,用完你就知道了
今天给大家介绍的项目是来自谷歌开源的Python Fire,可以从任何 Python 代码生成命令行接口(command line interfaces (CLIs)),简单地调用任意 Python 程序中的 Fire 函数以将那个程序自动地转化为 CLI。截止发稿前,该项目已经在github获得15600+⭐,接近1000次fork。为什么这个项目这么火爆呢?俩字:『好用』......
昱良
2019/11/07
2.7K0
Google 开源的 Python 命令行库:初探 fire
在本系列前面所有文章中,我们分别介绍了 argparse、docopt 和 click 的主要功能和用法。它们各具特色,都能出色地完成命令行任务。argparse 是面向过程的,需要先设置解析器,再定义参数,再解析命令行,最后实现业务逻辑。docopt 先用声明式的语法定义出参数,再过程式地解析命令行和实现业务逻辑。click 则是用装饰器的方式进一步简化显式的命令调用逻辑,但仍然不够面向对象。
HelloGitHub
2021/05/14
5280
巧用Google Fire简化Python命令行程序
上面是官方的示例代码,有了fire,编写Python的命令行程序就变得非常简单,我们无需再去处理繁琐的命令行参数解析了。接下来我们仿照HelloWorld,编写一个圆周率和阶乘计算的命令行脚本。
老钱
2018/08/14
6340
将Python程序转化为命令行界面的工具:Python Fire
大家好!今天我想和大家聊聊一个由 Google 开发的开源库——Python Fire。这个库的主要功能是将任何 Python 程序转化为命令行界面(CLI)。听起来是不是很酷?让我们一起来看看它的起源和发展吧。
TechHarmony
2024/04/17
2880
让命令行参数更简洁—google-fire库
在python中使用命令行参数一般会用argparse库,不过Google的Fire库可以让我们更加方便。现在GitHub上已经有16k多star和1k fork,链接:https://github.com/google/python-fire/blob/master/docs/guide.md
生信编程日常
2020/04/09
6160
【Python】自动生成命令行工具 - fire 简介
Python 中用于生成命令行接口(Command Line Interfaces, CLIs)的工具已经有一些了,例如已经成为 Python 标准库的 argparse 和第三方的 click ,这
Alan Lee
2018/01/02
1.8K0
【Python】自动生成命令行工具 - fire 简介
使用fire打造你自己的命令行工具
今天我的朋友小黄咨询我关于命令行的问题。他觉得他们团队的部署小组开发的命令行工具特别好用,可以用来部署环境,升级环境,检查环境等。他很好奇这到底是怎么做的。处于好奇,我们今天就一起来用 Python 写一个专属于我们自己的命令行工具。
Python研究所
2022/06/17
4220
使用fire打造你自己的命令行工具
两行代码,为 Python 脚本生成命令行!
我们定义了一个 Python 的方法,方法接收一些参数,但是调用的时候想将这些参数用命令行暴露出来。
程序员小二
2022/01/12
3090
玩转 Python 命令行:4 大主流工具库的对比
花下猫语:上篇文章提到了 invoke 也可以作为命令行工具库使用,但此用法有点像主功能的副产品,实际上,开发命令行程序最好是用主流的几个库。今天分享的文章,对 argparse、docopt、click 和 fire 这几个库做了横向对比,梳理了它们的异同与利弊,值得一读。
Python猫
2020/02/19
2.3K0
python学习: fire库的使用教程
fire是python中用于生成命令行界面(Command Line Interfaces, CLIs)的工具,不需要做任何额外的工作,只需要从主模块中调用fire.Fire(),它会自动将你的代码转化为CLI,Fire()的参数可以说任何的python对象
Python学习者
2022/12/28
6470
生成命令行接口--google开源的fire使用体验【python-fire】
在python中,命令行接口常用的argparse 和click,但是相对于python-fire 来说灵活度太缺了,fire可以直接将python中的函数,以命令行显示.
Gxjun
2018/12/19
8690
python fire使用
fire是python中用于生成命令行界面(Command Line Interfaces, CLIs)的工具,不需要做任何额外的工作,只需要从主模块中调用fire.Fire(),它会自动将你的代码转化为CLI,Fire()的参数可以说任何的python对象
李小白是一只喵
2020/04/23
8190
python fire使用
python -fire 快速创建命令行接口
def hello(name="World"): return "Hello %s!" % name
AI拉呱
2021/03/12
6110
Google 开源的 Python 命令行库:fire 实现 git 命令
在前面三篇介绍 fire 的文章中,我们全面了解了 fire 强大而不失简洁的能力。按照惯例,我们要像使用 argparse、docopt 和 click 一样使用 fire 来实现 git 命令。
HelloGitHub
2021/05/14
6050
一日一技:快速实现Python 命令行参数
那么使用 sys模块就不好用了。此时我们可以使用 argparse。但是如果你阅读它的官方文档:https://docs.python.org/zh-cn/3/howto/argparse.html,你就会发现 argparse写起来还是有点麻烦。
青南
2019/09/03
4250
一日一技:快速实现Python 命令行参数
fire让命令行接口更简单
Python中用于生成命令行接口CLIs(Command Line Interfaces)的库已经有一些了,例如标准库argparse和第三方的click,但是这些库为Python程序生成CLIs的时候稍显麻烦,需要增加的地方比较多,过程稍显繁琐. 这里介绍的这个利器,几乎可以不改变原始代码就能够生成CLIs,它就是fire ---- fire让命令行如此简单 下面通过一个简单的计算器来展示下fire的魔力 原始计算器 1def add(x, y): 2 """ 3 加法运算 4
用户2196567
2018/07/02
5920
推荐阅读
相关推荐
Google 开源的 Python 命令行库:深入 fire(二)
更多 >
领券
社区富文本编辑器全新改版!诚邀体验~
全新交互,全新视觉,新增快捷键、悬浮工具栏、高亮块等功能并同时优化现有功能,全面提升创作效率和体验
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文