作者:HelloGitHub-Prodesire

HelloGitHub 的《讲解开源项目》系列,项目地址:https://github.com/HelloGitHub-Team/Article

一、前言

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

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

本系列文章默认使用 Python 3 作为解释器进行讲解。
若你仍在使用 Python 2,请注意两者之间语法和库的使用差异哦~

二、功能

2.1 子命令

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

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

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

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 是作为数字而非字符串,我们会在下篇文章的参数解析章节中进行讲解。

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

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

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

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
杭州

三、小结

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

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


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

Google 开源的 Python 命令行库:深入 fire(一)的更多相关文章

  1. Google 开源的 Python 命令行库:fire 实现 git 命令

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  2. Google 开源的 Python 命令行库:初探 fire

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  3. Google 开源的 Python 命令行库:深入 fire(二)

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  4. 大家都说好用的 Python 命令行库:click

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  5. Python进阶:都说好用的 Python 命令行库click

    click 是一个以尽可能少的代码.以组合的方式创建优美的命令行程序的 Python 包.它有很高的可配置性,同时也能开箱即用. 它旨在让编写命令行工具的过程既快速又有趣,还能防止由于无法实现预期的 ...

  6. 用什么库写 Python 命令行程序?看这一篇就够了

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  7. 让你如绅士般基于描述编写 Python 命令行工具的开源项目:docopt

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

  8. Python 命令行之旅 —— 初探 argparse

    『讲解开源项目系列』启动--让对开源项目感兴趣的人不再畏惧.让开源项目的发起者不再孤单.跟着我们的文章,你会发现编程的乐趣.使用和发现参与开源项目如此简单.欢迎联系我们给我们投稿,让更多人爱上开源.贡 ...

  9. Python 命令行之旅:使用 docopt 实现 git 命令

    作者:HelloGitHub-Prodesire HelloGitHub 的<讲解开源项目>系列,项目地址:https://github.com/HelloGitHub-Team/Arti ...

随机推荐

  1. AcWing95. 费解的开关 枚举+位运算

    这道题的确比较难想,首先我们知道图比较小,有可能是枚举,那么该如何枚举呢??? 你可以发现,我们只要把第一排定了,并且保证第一排不准动,那么答案就定了 也就是说,我们首先用二进制枚举,枚举第一行需要翻 ...

  2. 设置WPF窗口相对于非WPF窗口的位置

    原文:设置WPF窗口相对于非WPF窗口的位置 在前一个Post当中,指出了在WPF的WindowInteropHelper类中的一个BUG:通过WindowInteropHelper的Owner属性不 ...

  3. 冒泡排序&&选择排序 以及时间效率对比

    package com.test4; import java.util.*; //Calendar 显示时间 /** * @author qingfeng * 功能:冒泡排序 */ public cl ...

  4. 从零学React Native之03页面导航

    之前我们介绍了RN相关的知识: 是时候了解React Native了 从零学React Native之01创建第一个程序 从零学React Native之02状态机 本篇主要介绍页面导航 上一篇文章给 ...

  5. DataTable CAST 成集合后,进行自定义排序再转换回DataTable

    dt = dt.Rows.Cast<DataRow>().OrderBy(r => Convert.ToInt32(r["数量"])==0?1:0).ThenBy ...

  6. SuperSocket命令程序集定义

    是的,SuperSocket是用反射来查找哪些公开的类实现了基本的命令接口,但是它只在你的AppServer类定义的程序集中查找. 举例来说, 你的 AppServer 定义在程序集 GameServ ...

  7. Appium + python 自动化测试环境配置

    -------------------------------------------------------------- 1. jdk-8u121-window(32位的就下载32位的,64位的就 ...

  8. Python--day28--面试题

  9. pytorch实现BiLSTM+CRF用于NER(命名实体识别)

    pytorch实现BiLSTM+CRF用于NER(命名实体识别)在写这篇博客之前,我看了网上关于pytorch,BiLstm+CRF的实现,都是一个版本(对pytorch教程的翻译), 翻译得一点质量 ...

  10. 2018-2-13-win10-uwp-获取指定的文件-AQS

    title author date CreateTime categories win10 uwp 获取指定的文件 AQS lindexi 2018-2-13 17:23:3 +0800 2018-2 ...