命令行程序是平时写一些小工具时最常用的方式。

为了让命令行程序更加灵活,我们常常会设置一些参数,根据参数让程序执行不同的功能。
这样就不用频繁的修改代码来执行不同的功能。

随着命令行程序功能的丰富,也就是参数多了以后,解析和管理参数之间的关系会变得越来越繁重。
而本次介绍的 Fire 库,正好可以解决这个问题。
使用 Fire 库,我们只要关心具体功能的实现,最后Fire会帮助我们自动把所有功能组织成一个命令行程序。

Fire库在github上的地址:https://github.com/google/python-fire

1. 一般命令

一般的命令,也就是带有几个参数的一段程序,比如:

# -*- coding:utf-8 -*-

def import_file(fp):
print("import file from: {}".format(fp)) def export_file(fp):
print("EXPORT file to: {}".format(fp))

这是模拟文件导出功能的两个函数。

使用 Fire 转换成命令行程序非常简单,下面介绍几种常用的方式。

1.1. 默认方式

# -*- coding:utf-8 -*-

import fire

def import_file(fp):
print("IMPORT file from: {}".format(fp)) def export_file(fp):
print("EXPORT file to: {}".format(fp)) if __name__ == "__main__":
# fire默认会将所有函数转换成子命令
fire.Fire()

然后,就可以通过子命令的方式执行导入导出功能。

$ python main.py import_file --fp ./path/xxx.csv
IMPORT file from: ./path/xxx.csv $ python main.py export_file --fp ./path/xxx.csv
EXPORT file to: ./path/xxx.csv

函数的名称自动变为子命令的名称函数的参数自动变成子命令的参数

1.2. Fire

Fire库的默认方式会把所有的函数都转换为子命令,
如果只想导出一个函数的话,可以用 Fire<fn>的方式。

if __name__ == "__main__":
# 只导出 import_file 函数作为子命令
fire.Fire(import_file)

只导出一个函数的时候,执行命令的时候不需要输入子命令的名称。

$ python main.py --fp ./path/xxx.csv
IMPORT file from: ./path/xxx.csv

1.3. Fire

导出多个函数作为子命令时,默认是使用函数名作为子命令名称的,函数名称有时候会非常长,输入很麻烦。
这时,可以用 Fire<dict> 方式。

if __name__ == "__main__":
# 子命令的名称分别是:import 和 export
fire.Fire({
"import": import_file,
"export": export_file,
})

执行时,使用简化的子命令名称。

$ python main.py import --fp ./path/xxx.csv
IMPORT file from: ./path/xxx.csv $ python main.py export --fp ./path/xxx.csv
EXPORT file to: ./path/xxx.csv

这种方式非常灵活,不仅可以设置子命令名称,还可以控制需要导出哪些函数。

1.4. Fire

除了导出函数,Fire<object>方式也可以导出对象的公有方法。

import fire

class FileHandler():

    def __init__(self):
pass def import_file(self, fp):
print("IMPORT file from: {}".format(fp)) def export_file(self, fp):
print("EXPORT file to: {}".format(fp)) if __name__ == "__main__":
fh = FileHandler()
fire.Fire(fh)

使用方式如下:

$ python main.py import_file --fp ./path/xxx.csv
IMPORT file from: ./path/xxx.csv $ python main.py export_file --fp ./path/xxx.csv
EXPORT file to: ./path/xxx.csv

使用对象的方式没有直接使用函数那么简单,但有个好处是可以在初始化时传入一些状态。

import fire
import os class FileHandler(): def __init__(self, folder=""):
self.folder = folder def import_file(self, fp):
print("IMPORT file from: {}".format(os.path.join(self.folder, fp))) def export_file(self, fp):
print("EXPORT file to: {}".format(os.path.join(self.folder, fp))) if __name__ == "__main__":
# 设置了默认文件夹,使用时直接传入文件名即可
fh = FileHandler("./default_path")
fire.Fire(fh)
$ python main.py import_file --fp xxx.csv
IMPORT file from: ./default_path/xxx.csv $ python main.py export_file --fp xxx.csv
EXPORT file to: ./default_path/xxx.csv

1.5. Fire

Fire<class>的方式也可以直接作用在类上,不用初始化对象。

if __name__ == "__main__":
fire.Fire(FileHandler)

Fire<object> 不同的是,__init__方法的参数也变成了命令的参数,也可以在命令行中调整了。

$ python main.py import_file --fp xxx.csv
IMPORT file from: xxx.csv $ python main.py import_file --fp xxx.csv --folder ./my_folder
IMPORT file from: ./my_folder/xxx.csv

2. 组合命令

当功能越来越多时,可能就会需要组合一些功能一起运行,省得输入一个一个的子命令。

class FileHandler():

    def __init__(self, folder="./defalut_dir"):
self.folder = folder def import_file(self, fp):
print("IMPORT file from: {}".format(os.path.join(self.folder, fp))) def export_file(self, fp):
print("EXPORT file to: {}".format(os.path.join(self.folder, fp))) class DatabaseHandler(): def __init__(self, src="aliyun-mysql", dst="tecent-mysql"):
self.src = src
self.dst = dst def import_db(self):
print("IMPORT data from: {} to: {}".format(self.src, self.dst)) def export_db(self):
print("EXPORT data from: {} to: {}".format(self.src, self.dst)) # 组合 FileHandler 和 DatabaseHandler
class ComposeHandler():
def __init__(self):
self.fh = FileHandler()
self.dh = DatabaseHandler() def import_all(self, fp):
self.fh.import_file(fp)
self.dh.import_db() def export_all(self, fp):
self.fh.export_file(fp)
self.dh.export_db() if __name__ == "__main__":
fire.Fire(ComposeHandler)

导出组合命令之后,不仅可以执行组合命令,也可以只执行子命令。

$ python main.py import_all --fp xxx.csv
IMPORT file from: ./defalut_dir/xxx.csv
IMPORT data from: aliyun-mysql to: tecent-mysql $ python main.py export_all --fp xxx.csv
EXPORT file to: ./defalut_dir/xxx.csv
EXPORT data from: aliyun-mysql to: tecent-mysql $ python main.py fh export_file --fp xxx.csv
EXPORT file to: ./defalut_dir/xxx.csv $ python main.py dh export_db
EXPORT data from: aliyun-mysql to: tecent-mysql

3. 链式命令

链式命令和组合命令不一样的地方在于:
组合命令中,每个命令之间一般是相互独立的,
而链式命令中,上一个命令的执行结果会对下一个命令造成影响。
比如:

class Stat():
def __init__(self):
self.total = 0
self.avg = 0
self.n = 0 # 模拟统计合计值
def sum(self, n):
self.n += n
for i in range(n):
self.total += i return self # 模拟求平均值
def average(self):
if self.n == 0:
self.avg = 0
else:
self.avg = self.total / self.n return self # 显示分析结果
def show(self):
print("SUM: {}, and AVERAGE: {}".format(self.total, self.avg)) if __name__ == "__main__":
fire.Fire(Stat)

执行链式命令时,可以先求和,再求平均值,最后显示结果:

$ python main.py sum 10 average show
SUM: 45, and AVERAGE: 4.5

因为是链式命令,所以可以多次执行:

$ python main.py sum 10 sum 10 average show
SUM: 90, and AVERAGE: 4.5 $ python main.py sum 10 sum 20 sum 30 average show
SUM: 670, and AVERAGE: 11.166666666666666

4. 复杂命令参数

上面的示例中,参数都是简单的数据类型,比如字符串,数字之类的。

最后,介绍下复杂的命令参数如何使用,所谓复杂的参数,就是元组,列表,字典等等。

def hello(data):
tp = type(data).__name__
if tp == "tuple" or tp == "list":
for item in data:
print("hello: {}".format(item)) if tp == "dict":
for k, v in data.items():
print("hello: key {}, val {}".format(k, v)) if __name__ == "__main__":
fire.Fire(hello)

python是弱类型语言,函数的参数可以是任何类型。
主要看看命令行中如何传入复杂的类型:

$ python main.py "(aa, bb, cc)"
hello: aa
hello: bb
hello: cc $ python main.py "[aa, bb, cc]"
hello: aa
hello: bb
hello: cc $ python main.py "{aa: 11, bb: 22}"
hello: key aa, val 11
hello: key bb, val 22

5. 总结

PythonFire库是一个构思非常巧妙的命令行接口库,各种语言的命令行接口我接触过不少,还没有在其他编程语言中看到过类似的库。

Fire库最方便的地方在于,你不用再关心命令行的参数(参数的解析一直是命令行程序中最让人头疼的地方),只要专注于自己要实现的功能。
此外,如果你已经有一些python脚本的话,通过这个库把它们改造成命令行程序也非常简单。

Python Fire:自动生成命令行接口的更多相关文章

  1. (Python)自动生成代码(方法一)

    在写某个平台的自动化脚本时,笔者把全部的操作都封装到了两个类中,page.py和commonpage.py: page.py部分代码: class BasePage(object): ''' 页面基础 ...

  2. Python项目自动生成当前项目的requirements文件

      使用pip freeze $ pip freeze > requirements.txt 这种方式是把整个环境中的包都列出来了,如果是虚拟环境可以使用. 通常情况下我们只需要导出当前项目的r ...

  3. Pycharm 设置python文件自动生成头部信息模板

    设置头部信息路径: 打开File—Settings—Editor—File and Code Templates—Python Script 输入要自动生成的头部信息模板 这样,新建py文件就会自动生 ...

  4. python pandas 自动生成批量测试数据插入数据库 mysql

    1.python连接数据库游标 # coding:utf-8 from sqlalchemy import create_engine class connet_databases: def __in ...

  5. Python实现自动生成小学四则运算题目

    Github地址: https://github.com/guoyuyi/gyy.github.io/blob/%E4%BD%9C%E4%B8%9A1/zy1.py 题目描述: 通过python语言编 ...

  6. python 项目自动生成 requirements.txt 文件

    生成 requirements.txt 文件的目的: 安装 pthon 项目时需要把此项目所有依赖的第三方包安装完成.项目依赖的第三方包统一放到 requirements.txt 文件中即可. 怎么自 ...

  7. python 项目自动生成requirements.txt文件

    主要使用目的: 任何应用程序通常需要设置安装所需并依赖一组类库来满足工作要求.通过requirements.txt可以一次性安装程序所需要和依赖的包. 为工程生成requirements.txt的两种 ...

  8. python实现自动生成小学四则运算题目(软工第二次项目作业)

    前言 软件工程 传送带 作业要求 传送带 作业目标 结对编程:代码实现.性能分析.异常处理说明.记录PSP表格 代码见: github 个人信息:朱育清 3118005437 信安二班 我的partn ...

  9. 【Python】自动生成html文件查看指定目录中的所有图片

    获取本目录下的pic子目录中的所有图片(jpg,png,bmp,gif等,此处以jpg文件为例),然后生成一个image.html文件,打开该html文件即可在浏览器中查看pic子目录中的所有图片. ...

  10. python SQLAlchemy自动生成models文件

    1.安装SQLAcodegen pip install sqlacodegen 2.执行 sqlacodegen mysql://root:123456@127.0.0.1:3306/test > ...

随机推荐

  1. Android 加载图片占用内存分析

    本文首发于 vivo互联网技术 微信公众号 链接:https://mp.weixin.qq.com/s/aRDzmMlkqB14Ty67GJs9vg作者:Xu Jie 不同Android版本,对一张图 ...

  2. vue 状态管理 五、Module用法

    系列导航 vue 状态管理 一.状态管理概念和基本结构 vue 状态管理 二.状态管理的基本使用 vue 状态管理 三.Mutations和Getters用法 vue 状态管理 四.Action用法 ...

  3. java实现mysqlplus查询一个月之间的数据

    先说需求使用mysqlplus查询一个月之内的数据,传入的参数是202108 要求就查8月份这个月的所有数据,oracle数据中数据记录的时间类型是Date类型 public static void ...

  4. 问题--去除CSDN水印

    1.问题如上 有时候需要使用其中的图片,但是水印很让人烦恼 确实可以用PS中的修复画笔工具,修复工具等进行处理 但是当水印覆盖到字体时,就会破坏到原有字体 2.解决方式 从CSDN添加水印的方式入手 ...

  5. 4. Oracle数据库提示ERROR: ORA-12560: TNS: 协议适配器错误

    问题如下 造成ORA-12560: TNS: 协议适配器错误的问题的原因有两个: 有关服务没有启动 windows平台个一如下操作:开始-程序-管理工具-服务,打开服务面板,启动TNSlistener ...

  6. crypto常用算法

    欧几里得算法(辗转相除法) def gcd(a, b): if b == 0: return a else: return gcd(b, a % b) 扩展欧几里得算法 def ext_euclid( ...

  7. [转帖]TiKV 内存参数性能调优

    https://docs.pingcap.com/zh/tidb/stable/tune-tikv-memory-performance 本文档用于描述如何根据机器配置情况来调整 TiKV 的参数,使 ...

  8. [转帖]shell脚本字符串截取的8种方法

    https://www.cnblogs.com/zwgblog/p/6031256.html 假设有变量 var=http://www.aaa.com/123.htm. 1. # 号截取,删除左边字符 ...

  9. ESXi虚拟化的坑-细微区别下虚拟机性能差异巨大

    ESXi虚拟化的坑-细微区别下虚拟机性能差异巨大 背景 周末在公司无偿加班. 同组的小伙伴周一有一个需求, 我想着周六乘着机器压力不大进行一下虚拟机的clone 但是截止到晚上快十点都没有完全Clon ...

  10. [转帖]兆芯官方的CPU测试成绩,我复现不了

      https://baijiahao.baidu.com/s?id=1734998483605483848 下图是兆芯网官上的公开测试成绩,测试对象是3.0GHz的KX-U6880A. 有几个问题: ...