Google 开源的 Python 命令行库:深刻 fire(一)

做者:HelloGitHub- Prodesire

涉及的示例代码和历史文章,已同步更新到 HelloGitHub-Team 仓库python

1、前言

在第一篇“初探 fire”的文章中,咱们初步掌握了使用 fire 的简单步骤,了解了它 Pythonic 的用法。git

今天咱们将深刻了解 fire 的子命令、嵌套命令和属性访问功能。github

本系列文章默认使用 Python 3 做为解释器进行讲解。
若你仍在使用 Python 2,请注意二者之间语法和库的使用差别哦~
复制代码

2、功能

2.1 子命令

使用 fire 实现子命令有多种方式:编程

2.1.1 定义若干函数,使用 fire.Fire()

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

import fire

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

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

if __name__ == '__main__':
  fire.Fire()
复制代码

而后咱们就能够在命令行中这么调用:函数

$ python example.py add 10 20
30
$ python example.py multiply 10 20
200
复制代码

关于如何识别参数类型,好比上述 add 10 201020 是做为数字而非字符串,咱们会在下篇文章的参数解析章节中进行讲解。ui

2.1.2 定义若干函数,使用 fire.Fire()

2.1.1 的版本中,会把全部函数都当作是子命令。有时咱们可能只想把部分函数当作子命令,或者是但愿子命令名称和函数名称不同。这个时候咱们就能够经过字典对象显式地告诉 fire编码

字典对象的形式为 {'子命令名称': 函数},好比前面的示例中,咱们但愿最终的子命令为 addmul,那么就能够这么写:spa

fire.Fire({
  'add': add,
  'mul': multiply,
})
复制代码

而后咱们就能够在命令行中这么调用:命令行

$ python example.py add 10 20
30
$ python example.py mul 10 20
200
复制代码

2.1.3 定义类和方法,使用 fire.Fire()

定义类和方法的这种方式咱们在上一篇文章中介绍过,它和定义函数的方式基本相同,只不过是用类的方式来组织。

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

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)
复制代码

2.1.4 定义类和方法,使用 fire.Fire()

2.1.3 中的惟一不一样点是把类而非实例对象做为 fire.Fire 的入参:

fire.Fire(Calculator)
复制代码

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

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)
复制代码

查看帮助命令有:

$ 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

咱们能够在命令行中这么调用:

$ 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
复制代码

2.2 命令组/嵌套命令

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

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)
复制代码

在上面的示例中:

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

所以整个命令行程序支持以下命令:

  • run
  • ingestion run
  • digestion run
  • digestion status

而后咱们就能够在命令行中这么调用:

$ 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.
复制代码

2.3 属性访问

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

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

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)
复制代码

使用方式以下:

$ python example.py --code bj zipcode
100000
$ python example.py --code hz city
杭州
复制代码

3、小结

使用 fire 实现子命令和嵌套命令相对于其余命令行库来讲都更加简单清晰,不只如此,fire 还提供了属性访问这种较为独特的能力。

在下篇文章中,咱们将进一步深刻了解 fire,介绍其链式函数调用、自定义序列化、参数解析、fire 选项等更加高阶的功能。


『讲解开源项目系列』——让对开源项目感兴趣的人再也不畏惧、让开源项目的发起者再也不孤单。跟着咱们的文章,你会发现编程的乐趣、使用和发现参与开源项目如此简单。欢迎留言联系咱们、加入咱们,让更多人爱上开源、贡献开源~

相关文章
相关标签/搜索