装饰器
python装饰器个人的理解: 在原本函数基础上,在不改变原函数名和原函数代码的情况下,增加对这个函数的的拓展,本身也是函数. 特点就是返回值也是一个函数,这个函数就是被修饰的函数(当然他是包了一层).(比如: 函数A , B函数是A函数的装饰器,B的返回值其实就是A函数,不过是在执行A函数之前做了一些事'比如是否登录'和执行A函数之后做了一些事'比如记录登录的人员信息') 下面是的一个装饰器大概的样子:
def 装饰器的名字(func): #func被装饰的函数
def inner(*args,**kwargs): # *args,**kwargs 为参数可有可无或普通参数,看使用场景
'''在执行被装饰的函数之前要做的事儿'''
'''判断是否登录'''
ret = func(*args,**kwargs)
'''在执行被装饰的函数之后要做的事儿'''
'''写log'''
return ret # 返回值可有可无,看使用场景
return inner
什么情况下会使用装饰器
一般情况在已经写好发版的程序的基础上,需要对一个函数执行前后增加功能的时候
开放封闭原则:
开放 :对扩展是开放的
封闭 :对修改是封闭
例子: 我这里有个论坛的三个页面比如:文章、日记、评论,我需要在进入前判断下用户是否登录,没有登录先去登录,登录之后直接进入页面,并把事件上传到服务器
import time
def za_loginWraps(func):
'''
登录装饰器
:param func:
:return:
'''
def inner(*args,**kargs):
#判断登录与否的逻辑
ret = func(*args,**kargs)
#写入文件,并上传服务器
return ret
return inner
@za_loginWraps
def za_article():
'''
文章详情
:return:
'''
print('欢迎 *** 用户访问 文章 页面')
@za_loginWraps
def za_diary():
'''
日记详情
:return:
'''
print('欢迎 *** 用户访问 日记 页面')
@za_loginWraps
def za_comment():
'''
评论详情
:return:
'''
print('欢迎 用户访问 评论 页面')
文章、日记、评论三个函数在执行前都被za_loginWraps
装饰器装饰
了,所有会先执行装饰器的代码.
@za_loginWraps
这句话就代表装饰下面的函数了.等价于: za_comment = za_loginWraps(za_comment)
za_loginWraps
是一个函数,参数也是一个函数,返回值也是一个函数.(参数和返回值就是被装饰的函数)
za_article``````za_diary``````za_comment
这三个函数就相当于在不改变原函数代码和名字的前提下被注入了是否登录功能,现在只要调用这三个函数,它就变成了先去执行装饰器然后再去执行原函数,原函数不会被重复执行.
一个简单的装饰器就完事了.
扩展:
这个时候你去打印下 文章、日记、评论的 函数名字你会发现是一样的.
print([za_comment.__name__])
print([za_article.__name__])
print([za_diary.__name__])
['inner']
['inner']
['inner']
出现这情况是因为,·@za_loginWraps
这句话等于 za_comment = za_loginWraps(za_comment)
. 把被装饰的函数,传到装饰器中,装饰器最后返回的是 里面的函数inner
方法,所有这里其实是 inner
函数的内存地址.
想打印原方法名称可以引用: from functools import wraps
在装饰器中加入:
@wraps(func)
代码变为:
from functools import wraps
import time
def za_loginWraps(func):
'''
登录装饰器
:param func:
:return:
'''
@wraps(func)
def inner(*args,**kargs):
#判断登录与否的逻辑
ret = func(*args,**kargs)
#写入文件,并上传服务器
return ret
return inner
这个时候再去打印三个函数名就变为:
['za_comment']
['za_article']
['za_diary']
传递参数
因为参数会有很多种,一般把参数都写成*args,**kwargs
这样为了能够适配所有参数类型.(当时参数类型简单的话,可以直接去写.) 比如我要在详情页面传递用户名
from functools import wraps
import time
def za_loginWraps(func):
'''
登录装饰器
:param func:
:return:
'''
@wraps(func)
def inner(*args,**kargs):
#打印传递过来的用户名
print(args[0])#参数如果传递就如何获取
ret = func(*args,**kargs)
#写入文件,并上传服务器
return ret
return inner
@za_loginWraps # za_comment = za_loginWraps(za_comment(username))
def za_comment(username):
'''
评论详情
:return:
'''
print('欢迎 %s 用户访问 评论 页面'%username)
多个装饰器修饰一个函数
有的时候一个装饰器代表一个功能,比如现在我要在文章函数执行前加上是否登录和统计页面的使用时长,这个时候我加一个装饰器代码如下:
def login(func):
print('----正在装饰01----')
def inner():
print('----正在执行01----')
func()
print('----执行后01----')
return inner
def time(func):
print('----正在装饰02----')
def inner():
print('----正在执行02----')
func()
print('----执行后02----')
return inner
@login
@time
def func():
'''
文章详情
:return:
'''
print('欢迎 *** 用户访问 文章 页面')
func()
func
函数上面有两个装饰器了,执行代码结果如下:
----正在装饰02----
----正在装饰01----
----正在执行01----
----正在执行02----
欢迎 *** 用户访问 文章 页面
----执行后02----
----执行后01----
来分析下:
看执行结果得知装饰器先走的离函数进的,但是执行的时候是由上往下的.所以得出: 装饰是从下往上,调用是从上往下
再看下执行开始和结束: 先说一下
@login
@time
def func():
*****
等价于:
func = login(time(func()))
.......未完......
网友评论