装饰器总结
1. 闭包。
闭包定义:在函数嵌套的前提下,内层函数调用外层函数的变量,外层函数返回内层函数的引用。
闭包作用: 可以保存外部函数的变量,不会随着外部函数调用而销毁。
注意点:由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。
2.装饰器
目的:在不改变函数源代码和调用方式的前提下,给函数添加新的功能。
实质:闭包函数。内层函数调用外层函数的函数。就是给已有函数增加额外的功能函数。
装饰器的种类:
1 .最简单装饰器
比如添加一个登录功能
def logging(fn):
def inner():
print('logging..........')
fn()
return inner
def comment():
print('make comment')
comment = logging(comment)
comment()
简单吧? 就是这么简单。也可以用语法糖来装饰
def logging(fn):
def inner():
print('logging..........')
fn()
return inner
@logging
def comment():
print('make comment')
comment()
@logging 就等价于 comment = logging(comment)
再来一个应用场景吧。比如给函数添加一个计算执行时间的功能
我们来写一个这样的装饰器
import time
def CalculatingTime(fn):
def inner():
begin = time.time()
fn()
end = time.time()
print('use time: %f' %(end - begin))
return inner
@CalculatingTime
def Print1to100000():
for i in range(100000):
print(i)
Print1to100000()
- 装饰带有参数的函数
def logging(fn):
def inner(a, b):
print('logging.....')
fn(a, b)
return inner
@logging
def Calculating(a, b):
result = a + b
print(result)
Calculating(1, 2)
就是函数带了个参数,直接在内层函数带上就好了
3.装饰带有返回值的函数
def logging(fn):
def inner(a, b):
print('logging.....')
result = fn(a, b)
return result
return inner
@logging
def Calculating(a, b):
result = a + b
return result
result = Calculating(1, 2)
print(result)
是不是有点疑问啊?明明Calculating函数里面已经返回了,为什么在装饰器内层函数里面还要再返回一遍呢,因为被装饰的函数,装饰完实际上就是内层函数,不再是原来的Calculating函数了,要想装饰完也能返回result, 就得在内层函数再返回result, 不然是不会有返回值的。所以要在内层函数得到Calculating函数的返回结果然后再返回。
4.装饰带有不定长参数的函数
def logging(fn):
def inner(*args, **kwargs):
print('logging............')
fn(*args, **kwargs)
return inner
@logging
def Calculating(*args, **kwargs):
result =0
for value in args:
result += value
for value in kwargs.values():
result +=value
print(result)
Cauculating(1, 2, a=3, b=4)
也没什么。就是把参数换成不定长。一个元组传参,一个字典传参。字典循环的时候记得要加values
5.通用装饰器
顾名思义,就是把之前几个功能综合一下。
还是登录功能装饰器
def logging(fn):
def inner(*args, **kwargs):
print('logging..........')
result = fn(*args, **kwargs)
return result
return inner
@logging
def Calculating(*args, **kwargs):
result = 0
for value in args:
result += value
for value in kwargs.values():
result += value
return result
# 再写一个函数体现装饰器的通用性
@logging
def subCalculating(a, b):
result = a - b
print(result)
result = Calculating(1, 2, a=3, b=4)
print(result)
subCalculating(4, 2)
来写一下通用装饰器的语法格式吧:
def outer(fn):
def inner(*args, **kwargs):
print('do something before fn')
result = fn(*args, **kwargs)
print('do something after fn')
return result
return inner
6.多个装饰器装饰函数。
知道一点:装饰顺序由下到上,执行顺序由上到下,就不具体去写了。
7.带有参数的装饰器
在装饰器外面再包裹一个函数,让最外面的函数接受参数, 返回的是装饰器。三层嵌套。
def logging(flag):
def decorator(fn):
def inner(*args, **kwargs):
print('logging........')
if flag == '+':
print('add..........')
if flag == '-':
print('sub..........')
result = fn(*args, **kwargs)
return result
return inner
return decorator
@logging("+")
def add(a, b):
result = a + b
return result
@logging("-")
def sub(a, b):
result = a - b
return result
result = add(1, 2)
print(result)
result = sub(2, 1)
print(result)
8.类装饰器
通过定义一个类来装饰函数。利用 __call__方法实现调用实例对象可以像调用函数一样调用。
class logging(object):
def __init__(self, fn):
self.fn = fn
def __call__(self, *args, **kwargs):
print('logging..........')
self.fn()
def comment():
print('make comment.....')
comment = logging(comment)
comment()
@logging
def comment():
print('make comment.....')
comment()
9.带参数的类装饰器
class logging(object):
def __init__(self, flag):
self.flag = flag
def __call__(self, fn):
def inner(*args, **kwargs):
print('logging..........')
if self.flag == '+':
print('add........')
elif self.flag == '-':
print('sub.........')
result = fn(*args, **kwargs)
return result
return inner
@logging("+")
def add(a, b):
result = a + b
return result
@logging("-")
def sub(a, b):
result = a - b
return result
result = add(1, 2)
print(result)
result = sub(2, 1)
print(result)
在init函数里面传入参数。
先总结到这里吧。以后再慢慢更新一些例子。装饰器在flask里面用的比较多,必须牢牢掌握!