最近一直没抽出时间来写博客,这篇博客在草稿箱里面躺了好久了,一直都只有一个标题。
现在终于要开始写了。
为什么要写这个篇文章
前段时间整天盯着python学习 群,发现好多同学对python很多内容并不是很理解,觉得有必要分享自己这段时间通过学习实践总结出来的一些东西。
写的过程中我会将一些自己理解的内容直接用文字写出来,感觉没必要去复制粘贴一些概念性的东西,若存在有理解错误的地方,欢迎各位在留言指出一起讨论提高,SO 废话不说开写吧。什么是装饰器
装饰器(Decorator):个人理解装饰器无非就是一个函数,函数的功能是传入一个源函数,丢回来一个包含原函数功能的闭包来替代原函数以供调用。
哎呀 又扯出一个闭包概念⊙﹏⊙b汗 关于闭包下次有空再写一篇装饰器的分类
以实现一个非常无聊的功能(控制函数运行次数)的装饰器进行举例
不带参数的装饰器
不带参数的装饰器是真正装的饰器,通过传入一个函数返回一个闭包代替原函数,不带参数的装饰器定义方式如下:
def my_decorator(func): li = list() limit = 5 def inner(*args, **kwargs): # do some thing li.append(1) if len(li) > limit: print(‘<%s>只能被调用%s次‘ % (func.__name__, limit)) return else: return func(*args, **kwargs) return inner @my_decorator def my_func1(n): print(‘n is %s‘ % n) def my_func2(n): print(‘func2 n is %s‘ % n) for i in range(10): my_func1(i) my_func2(i)
执行结果
n is 0 func2 n is 0 n is 1 func2 n is 1 n is 2 func2 n is 2 n is 3 func2 n is 3 n is 4 func2 n is 4 <my_func1>只能被调用5次 func2 n is 5 <my_func1>只能被调用5次 func2 n is 6 <my_func1>只能被调用5次 func2 n is 7 <my_func1>只能被调用5次 func2 n is 8 <my_func1>只能被调用5次 func2 n is 9
通过返回一个inner闭包 实现限制执行次数
带参数的装饰器
带参数的装饰器函数本身严格意义上并不能算是装饰器,实际上带参数的装饰器函数是一个返回值为装饰器函数的一个函数。
为什么要有带参数的装饰器?
就拿前面举的例子来说: 虽然my_decorator实现的功能比较无聊,但是我还是感觉这个无聊的功能不够完美,因为函数执行次数限制在装饰器里面写死了,假如我要限制好几个不同的函数,每个函数限制不同执行次数,那么按照不带参数的装饰器的写法每个限制的执行次数我都要重新写一个装饰器,这显然非常不合理。于是我需要一个带参数的装饰器来实现这种功能。
下面是实现该功能的函数写法:def my_decorator(limit): def outer(func): li = list() def inner(*args, **kwargs): # do some thing li.append(1) if len(li) > limit: print(‘<%s>只能被调用%s次‘ % (func.__name__, limit)) return else: return func(*args, **kwargs) return inner return outer @my_decorator(2) def my_func1(n): print(‘n is %s‘ % n) @my_decorator(4) def my_func2(n): print(‘func2 n is %s‘ % n) for i in range(5): my_func1(i) my_func2(i)
眼尖的同学可能注意到了这里装饰器装饰写法和不带参数的不同,不带参数时@后面直接接的装饰器函数名,此处@后面接了装饰器函数名后还有一对括号和参数。
带了括号和参数意味着函数已经被执行了,相当于@后面跟着的是函数执行的返回值,所以my_decorator函数返回的outer函数闭包才是真正意义上的装饰器函数,
通过my_decorator的参数limit 我们就可以每次装饰一个函数时都可以指定不同的函数执行次数上限。
执行结果n is 0 func2 n is 0 n is 1 func2 n is 1 <my_func1>只能被调用2次 func2 n is 2 <my_func1>只能被调用2次 func2 n is 3 <my_func1>只能被调用2次 <my_func2>只能被调用4次
关于“@”符号
@符号作用
@符号是python中的一个语法糖 为了让装饰语句写起来更加简单代码更加易读。
在函数定义前一行放置@符号后面接一个装饰器函数名代表该函数被装饰器装饰,相当于在函数定义之后立马执行了一条语句:
func=decorator(func)
此处func为被装饰函数,decorator为装饰器函数。@ 符号给初学者带来的障碍
@符号各种方便但是给初学者理解装饰器带来了一定障碍:初学者很容易忘掉@的实际作用,然后就会想不通装饰器到底是怎么装饰的。
So 其实这个障碍是我写这篇文章的主要原因。
装饰器的装饰过程
终于写到了正题 ,正题还是以限制