浅谈python3的装饰器
浅谈python3的装饰器
作者信息:
Author : 黄志成(小黄)
博客地址: 博客
首先来简述一下什么是装饰器?
装饰器本质上是一个python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象.
装饰器也是一种设计模式.它遵守着开放-封闭原则.对于开放封闭原则我在这里用一句话总结:一个模块在扩展性方面应该是开放的而在更改性方面应该是封闭的.
先说一个需求吧.需要完成两个函数,一个求和函数另一个求平均值函数.
这个很好实现哇.
def func_sum(*arg):
return sum(arg)
def func_average(*arg):
return sum(arg) / len(arg)
print(func_sum(1,2,3,4))
print(func_average(1,2,3,4))
输出结果:
10
2.5
看似没问题,能计算出结果.但是如果传入一个字符串或者其他类型该怎么办呢.
那也很简单,我们改造一下这两个函数
def func_sum(*arg):
if len(arg) == 0:
return 0
for i in arg:
if not isinstance(i,int):
return 0
return sum(arg)
def func_average(*arg):
if len(arg) == 0:
return 0
for i in arg:
if not isinstance(i,int):
return 0
return sum(arg) / len(arg)
print(func_sum(1,2,3,4,'asd'))
print(func_average(1,2,3,4))
在运行下
0
2.5
至少不会报错了.但是问题又来了.我们最开始说了开放-封闭原则.但现在已经完全违背了这个原则.那如何改写才能遵守呢.
在如何改写之前咱再说说闭包。闭包这个概念可能有些涩会难懂
在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
def outer():
def inner():
return "inner"
return inner
wai = outer()
print(wai())
结果打印出 inner。现在我们将那两个函数共同的验证部分复用起来.
实现代码如下:
def func_sum(*arg):
return sum(arg)
def func_average(*arg):
return sum(arg) / len(arg)
def validate(func):
def fn(*arg):
if len(arg) == 0:
return 0
for i in arg:
if not isinstance(i,int):
return 0
return func(*arg)
return fn
func_sum = validate(func_sum)
func_average = validate(func_average)
print(func_sum(1,2,3,4))
print(func_average(1,2,3,4))
在python中函数也是对象,也可以传递.
这样验证的部分复用就实现了.这就是开发-封闭原则.
继续优化下.使用python提供给我们的语法糖 装饰器
@demo @符号后面跟上函数 就是所谓的装饰器.如果你已经理解了闭包.在看下去就会更加简单.
下面给出装饰器版的复用
def validate(func):
def fn(*arg):
if len(arg) == 0:
return 0
for i in arg:
if not isinstance(i,int):
return 0
return func(*arg)
return fn
@validate
def func_sum(*arg):
return sum(arg)
@validate
def func_average(*arg):
return sum(arg) / len(arg)
print(func_sum(1,2,3,4,'1'))
print(func_average(1,2,3,4))
如果还没有理解装饰器,在列举一个例子.
计算函数运算的时间
大部分人会使用下面这种写法
import time
def func_a():
time.sleep(1)
start = time.time()
func_a()
end = time.time()
print(end - start)
最后返回结果
1.003756046295166
用装饰器来编写计算函数运行时间的代码
import time
def func_time(func):
def fn():
start = time.time()
func()
end = time.time()
print(end - start)
return fn
@func_time
def func_a():
print("i'm func_a")
time.sleep(1)
func_a()
结果返回:
i'm func_a
1.003925085067749
这篇文章就到此结束了.如果本月有时间的话.会再来一篇细说下装饰器.
又到了愉快的周末!今天写的内容.可能会对初学者有些难懂.看不懂的话请多敲几遍.代码是敲出来的.不是看出来的.
写于 2018年07月13日18:38
发表评论