在面向对象中装饰器也被成为装饰器模式,Python在语法层对装饰器提供了支持.在工作中,我也经常使用Python的这个特性.在不改变原有代码的同时,对程序功能进行扩展,同时也能有效地降低各模块间的耦合度,提高代码的可重用性和开发效率.
在我的另外一篇博客Python的AOP利器:装饰器,也对装饰器进行了介绍.使用@foo
形式的装饰器本质上是执行foo
这个callable
对象,参数是被装饰的对象.因此,其意义与foo(func)
相同.此时,对该可执行对象的调用类似执行foo(func)(*args,**kwargs)
.
ugly-code是我开发的一个工具库,其中的命令行模块就是使用Python的装饰器实现的.
# 克隆项目到本地
$ git clone https://git.oschina.net/irealing/ugly-code.git
# 编译项目,此操作会在dist目录生成可以用 pip 工具安装的whl文件
$ python3 setup.py bdist_wheel
# 安装依赖
$ pip install dist/ugly_code****.whl
安装该依赖,创建cmd_debug.py
,内容如下:
from ugly_code.cmd import Command
@Command
def main(a: int, b: str = "default"):
print("{} {}".format(a, b))
if __name__ == '__main__':
main()
执行该脚本会发现,main
函数被包装为一个可以处理命令行参数的脚本.有默认值的参数会被设置为可选参数,无默认值则设置为必选.使用Type Hints的参数亦可自动进行类型检查.
在当前目录下,执行python3 -c 'from cmd_debug import main;print(type(main))'
观察输出:
mars:ugly-code/ (master) $ python3 -c 'from cmd_debug import main;print(type(main))'
<class 'ugly_code.cmd.Command'>
我们可以发现,main
函数的类型变成了ugly_code.cmd.Command
.
ugly_code.cmd.Command
是一个类,也是一个装饰器,主要代码如下:
class Command(object):
"""
Command object
"""
def __init__(self, func):
self.func=func
def __call__(self):
args=self.parse_args()
return self.func(*args)
Command
的__init__
方法接收一个函数类型的参数func
,在__call__
函数调用时对命令行参数进行解析,并执行了func
函数.所以上面的例子中函数main
的类型变成了ugly_code.cmd.Command
.
该工具的完成代码可在irealing/ugly-code - 码云 - 开源中国看到:)
author:Memory_Leak