使用Python编写命令行工具的库很多,我最推荐的还是Google Fire

Hello World

要介绍Fire是什么,看一个简单的例子就明白了

# calc.py

import fire

class Calculator(object):

"""A simple calculator class."""

def double(self, number):

return 2 * number

if __name__ == '__main__':

fire.Fire(Calculator)

接下来我们进入bash来执行上面编写的脚本

> python calc.py double 10

20

> python calc.py double --number=16

32

上面是官方的示例代码,有了fire,编写Python的命令行程序就变得非常简单,我们无需再去处理繁琐的命令行参数解析了。接下来我们仿照HelloWorld,编写一个圆周率和阶乘计算的命令行脚本。 />

实战

import math

import fire

class Math(object):

def pi(self, n):

s = 0.0

for i in range(n):

s += 1.0/(i+1)/(i+1)

return math.sqrt(6*s)

def fact(self, n):

s = 1

for i in range(n):

s *= (i+1)

return s

if __name__ == '__main__':

fire.Fire(Math)

接下来我们运行一下

> python maths.py pi 10000

3.14149716395

> python maths.py pi 100000

3.14158310433

> python maths.py pi 1000000

3.14159169866

> python maths.py fact 10

3628800

> python maths.py fact 15

1307674368000

> python maths.py fact 20

2432902008176640000

Cool,真的非常方便!fire对当前对象结构进行了暴露,将结构信息映射到shell命令行参数上。fire其实有多种暴露模式,接下来我们逐个来看fire都有哪些暴露模式。

暴露模块

fire如果不传递任何参数就可以直接暴露当前模块结构,我们对上面的例子做一下改造,去掉类信息

import math

import fire

def pi(n):

s = 0.0

for i in range(n):

s += 1.0/(i+1)/(i+1)

return math.sqrt(6*s)

def fact(n):

s = 1

for i in range(n):

s *= (i+1)

return s

if __name__ == '__main__':

fire.Fire()

注意Fire函数调用没有任何参数,运行一下

> python maths.py fact 20

2432902008176640000

> python maths.py pi 1000000

3.14159169866

暴露函数

fire还可以传递一个函数对象来暴露单个函数,可以让我们在命令行参数上省掉函数名称

import math

import fire

def pi(n):

s = 0.0

for i in range(n):

s += 1.0/(i+1)/(i+1)

return math.sqrt(6*s)

if __name__ == '__main__':

fire.Fire(pi)

如果暴露函数那就只能暴露一个函数,如果暴露了两个,那就只有后面一个生效,运行一下

> python maths.py 1000

3.14063805621

暴露字典

fire可以直接暴露一个模块,将当前模块的所有函数全部暴露,函数名和第一个参数名一致。我们也可以不用暴露整个模块的所有函数,使用字典暴露法就可以选择性地对模块的某些函数进行暴露,顺便还可以替换暴露出来的函数名称。

import math

import fire

def pi(n):

s = 0.0

for i in range(n):

s += 1.0/(i+1)/(i+1)

return math.sqrt(6*s)

def fact(n):

s = 1

for i in range(n):

s *= (i+1)

return s

if __name__ == '__main__':

fire.Fire({

"pi[n]": pi

})

我们只暴露了pi函数,并且把名字还换掉了,运行一下,看效果

> python maths.py pi[n] 1000

3.14063805621

如果我们使用原函数名称,就会看到fire列出的友好的报错信息

> python maths.py pi 1000

Fire trace:

1. Initial component

2. ('Cannot find target in dict:', 'pi', {'pi[n]': })

Type: dict

String form: {'pi[n]': }

Length: 1

Usage: maths.py

maths.py pi[n]

暴露对象

import math

import fire

class Maths(object):

def pi(self, n):

s = 0.0

for i in range(n):

s += 1.0/(i+1)/(i+1)

return math.sqrt(6*s)

def fact(self, n):

s = 1

for i in range(n):

s *= (i+1)

return s

if __name__ == '__main__':

fire.Fire(Maths())

运行

> python maths.py pi 1000

3.14063805621

> python maths.py fact 20

2432902008176640000

暴露类

这个我们在上面的实战环节已经演示过了,这里就不在重复粘贴

类 vs 对象

通过上面的例子,我们发现暴露类和暴露对象似乎没有任何区别,那到底该选哪种比较优雅呢?这个要看类的构造器有没有参数,如果是不带参数的构造器,那么类和对象的暴露是没有区别的,但是如果类的构造器有参数,那就不一样了,下面我们改造一下Maths类,增加一个放大系数。

import math

import fire

class Maths(object):

def __init__(self, coeff):

self.coeff = coeff

def pi(self, n):

s = 0.0

for i in range(n):

s += 1.0/(i+1)/(i+1)

return self.coeff * math.sqrt(6*s)

def fact(self, n):

s = 1

for i in range(n):

s *= (i+1)

return self.coeff * s

if __name__ == '__main__':

fire.Fire(Maths)

因为Maths的构造器带有参数,所有运行命令行时需要指定构造器参数值

> python maths.py pi 1000 --coeff=2

6.28127611241

如果不指定参数的值,运行时就会报错

> python maths.py pi 1000

Fire trace:

1. Initial component

2. ('The function received no value for the required argument:', 'coeff')

Type: type

String form:

File: ~/source/rollado/maths.py

Line: 5

Usage: maths.py COEFF

maths.py --coeff COEFF

如果改成暴露对象,那么放大系数就是在代码里写死的,无法在命令行进行参数定制了。这就是暴露对象和暴露类的差别,似乎暴露类在功能上更强大一些。

暴露属性

上面的所有例子我们最终暴露的都是函数,要么是模块里的函数,要么是类里的函数。但实际上fire还可以暴露属性,比如我们可以将上面的coeff参数通过命令行进行输出。

> python maths.py coeff --coeff=2

2

> python maths.py coeff --coeff=3

3

再来一个更加简单的例子

# example.py

import fire

english = 'Hello World'

spanish = 'Hola Mundo'

fire.Fire()

运行

$ python example.py english

Hello World

$ python example.py spanish

Hola Mundo

原理 />

命令行中的参数顺序和代码内部对象的树状层次结构呈现一一对应关系。如果fire不带参数暴露了当前的模块,那么第一个参数就应该是这个模块内部的函数名、类名或者是变量名。如果第一个参数是函数,那么接下来的参数就是函数的参数。如果第一个参数是类,那么接下来的参数可能是这个类实例内部的方法或者字段。如果第一个参数是变量名,后面没有参数的话,就直接显示这个变量。如果后面还有参数,那么就把这个变量看成一个对象,然后继续使用后续参数来深入解析这个对象。

在Python里面所有的变量都是对象,包括普通的整数、字符串、浮点数、布尔值等。理论上可以一直将对象结构递归下去,形成一个复杂的链式调用。

链式暴露

接下来我们验证这个理论,尝试一下复杂的链式暴露。

import fire

class Chain(object):

def __init__(self):

self.value = 1

def incr(self):

print "incr", self.value

self.value += 1

return self

def decr(self):

print "decr", self.value

self.value -= 1

return self

def get(self):

return self.value

if __name__ == '__main__':

fire.Fire(Chain)

运行一下

> python chains.py incr incr incr decr decr get

incr 1

incr 2

incr 3

decr 4

decr 3

2

Cool! 我们通过在每个方法里面方法self对象自身来实现了漂亮的链式调用效果。

接下来我们尝试对内置字符串对象进行解构

# xyz.py

import fire

value = "hello"

if __name__ == '__main__':

fire.Fire()

字符串有upper和lower方法,我们反复使用upper和lower,然后观察结果

> python xyz.py value

hello

> python xyz.py value upper

HELLO

> python xyz.py value upper lower

Traceback (most recent call last):

File "xyz.py", line 7, in

fire.Fire()

File "/Users/pyloque/source/pys/.py/lib/python2.7/site-packages/fire/core.py", line 127, in Fire

component_trace = _Fire(component, args, context, name)

File "/Users/pyloque/source/pys/.py/lib/python2.7/site-packages/fire/core.py", line 366, in _Fire

component, remaining_args)

File "/Users/pyloque/source/pys/.py/lib/python2.7/site-packages/fire/core.py", line 542, in _CallCallable

result = fn(*varargs, **kwargs)

TypeError: upper() takes no arguments (1 given)

很不幸,内置的字符串对象似乎不支持链式调用,第一个upper倒是执行成功了。不过fire提供了一个特殊的符号用来解决这个问题。

> python xyz.py value upper - lower

hello

> python xyz.py value upper - lower - upper

HELLO

> python xyz.py value upper - lower - upper - lower

hello

减号用来表示参数的结束,这样后续的参数就不会被当成函数的参数来映射了。

让redis-py秒变命令行

最后我们再来一个酷炫的小例子,把redis-py的StrictRedis暴露一下变身命令行

import fire

import redis

if __name__ == '__main__':

fire.Fire(redis.StrictRedis)

就这么简单,接下来就可以玩命令行了

> python client.py flushdb

True

> python client.py set codehole superhero

True

> python client.py get codehole

superhero

> python client.py exists codehole

True

> python client.py keys "*"

codehole

> python client.py delete codehole

1

# 指定地址

> python client.py set codehole superhero --host=127.0.0.1 --port=6379

True

总结

有了Google Fire这样一个小巧的类库,我们就可以从复杂的命令行参数分析中解脱出来了。我们常说写代码要漂亮优雅,没有好的类库,这种理想也不是非常容易实现的。

python工具是什么-使用Python编写命令行工具有什么好的库?相关推荐

  1. java 编写命令行工具_编写命令行工具

    1.使用common-cli编写命令行工具 commons-cli是Apache开源组织提供的用于解析命令行参数的包. 先引用common-cli依赖包: commons-cli commons-cl ...

  2. 使用.Net Core编写命令行工具(CLI)

    使用.Net Core编写命令行工具(CLI) 命令行工具(CLI) 命令行工具(CLI)是在图形用户界面得到普及之前使用最为广泛的用户界面,它通常不支持鼠标,用户通过键盘输入指令,计算机接收到指令后 ...

  3. go编写命令行工具_编写者的命令行文档转换工具

    go编写命令行工具 今天,我们有足够的工具可用于在我们的计算机上编辑备忘录,信件,论文,书籍,演示幻灯片和其他文档. 这既有好处也有缺点:一方面,如果您不喜欢某个软件,则可以随时随地转到另一个软件上: ...

  4. 【Android 命令行工具】Android 命令行工具简介 ( 官方文档 | SDK 命令行工具 | SDK 构建工具 | SDK 平台工具 | 模拟器工具 | Jetifier 工具 )

    文章目录 一.官方文档 二.Android 命令行工具简介 1.SDK 命令行工具 2.SDK 构建工具 3.SDK 平台工具 4.模拟器工具 5.Jetifier 工具 一.官方文档 Android ...

  5. win7 命令行工具_7个很棒的命令行工具

    win7 命令行工具 The terminal/command line is a sacred tool that developers have under their belt. It is p ...

  6. swift编写命令行工具

    2019独角兽企业重金招聘Python工程师标准>>> 原文: https://www.raywenderlich.com/128039/command-line-programs- ...

  7. 自己写的python软件可以在哪发布-如何发布一个Python命令行工具

    本文简介 上次写的一个终端里面斗鱼TV弹幕Python版本和Ruby版本,并且发布到PIP和RubyGems上面.在发布PIP包的时候,居然Google不到一篇可以非常好的讲解这个流程的文章.于是整理 ...

  8. python3命令需要使用命令行开发者工具_3 个 Python 命令行工具

    用 Click.Docopt 和 Fire 库写你自己的命令行应用. 有时对于某项工作来说一个命令行工具就足以胜任.命令行工具是一种从你的 shell 或者终端之类的地方交互或运行的程序.Git 和 ...

  9. 通过命令行工具使用阿里云资源编排服务

    资源编排ROS 是一种简单易用的云计算资源管理和自动化运维服务.用户通过模板描述多个云计算资源的依赖关系.配置等,并自动完成所有资源的创建和配置,以达到自动化部署.运维等目的. 了解更多 通过命令行工 ...

最新文章

  1. Cloneable接口和循环冗余校验算法
  2. 如何pspice模型转成saber模型
  3. LHF Objective-C语法(7)id类型、动态判断与选择器
  4. flutter 真机无法调试 sdk报错_老许,你要转Flutter不要?只要你开金口,面试题现在就给你送来...
  5. Asp.Net 4.0 新特性 系列 之一 从页面标记%%说起
  6. 解构给默认值_使用 JavaScript 解构让代码更优雅
  7. kkfile跨域预览_kkFileView开源项目实现office各种格式在线预览
  8. 小程序和H5 之间的通信
  9. 用c语言编程解决数学实际问题,运用C语言解决爱因斯坦的数学题
  10. 多媒体计算机室的好处,多媒体会议室系统带来的好处有什么
  11. 轻量级架构和重量级架构
  12. 关于IE6无法升级为IE7或者IE8的问题
  13. latex大括号 多行公式_怎样在word中快速输入复杂的公式(在线识别数学、物理或化学公式)?...
  14. 我灰是啥意思是什么_色彩老师说我的静物脏乱花灰是啥意思?
  15. 2012-2-15雨
  16. hive 启动报错java.net.URISyntaxException: Relative path in absolute URI: ${system:java.io.tmpdir%7D/$%..
  17. 人工智能是引领未来的战略性技术 推动人工智能多学科交叉融合
  18. c语言led左右循环程序,c语言编写程序,将led从左往右,再从右往左依次往返点亮...
  19. 汉高2019年第三季度销售额增长0.8%,达50.77亿欧元
  20. Unity3d搭建HTTP弱联网的服务器搭建及客户端编写(一)之java服务器

热门文章

  1. Nlpir大数据知识图谱的落地指南
  2. Django----缓存
  3. iframe父页面获取iframe子页面的元素 与 iframe子页面获取父页面元素
  4. 【BZOJ-1367】sequence 可并堆+中位数
  5. iframe父子页面间通信总结
  6. Type difference of character literals in C and C++
  7. 安装Nginx过程中,使用make时出现 make: *** 没有规则可以创建“default”需要的目标“build”...
  8. Java设计模式(20)——行为模式之命令模式(Command)
  9. 2017沈阳站流水账+感想
  10. Vofuria 的 imageTarget 的图片无法显示或者显示为空白