‘总结一句话来说‘ : 就是定义一个函数, 用该函数去为其他函数添加新功能
‘总结来说‘ : 装饰器就是在遵循开放封闭原则的前提下为被装饰对象添加新功能
??不修改被装饰对象的源代码
??不修改被装饰对象的调用方式
需求 : 为 index 函数加上计时功能
import time # time模块
#time.time() 返回的是时间戳,从1970年1月1日凌晨到现在的秒数
def index():
time.sleep(1)
print(‘from index‘)
index()
import time
def index():
start=time.time() #开始时间
time.sleep(1) #睡"1"秒
print(‘from index‘)
stop=time.time() #结束时间
print(‘run time is %s‘ %(stop - start)) #运行时间
index()
????结果 : 没有修改调用方式,但修改了源代码
import time
def index():
time.sleep(1)
print(‘from index‘)
start=time.time()
index()
stop=time.time()
print(‘run time is %s‘ %(stop - start))
????结果 : 没有修改调用方式,没有修改源代码,但代码冗余
import time
def index():
time.sleep(1)
print(‘from index‘)
def wrapper():
start=time.time()
index()
stop=time.time()
print(‘run time is %s‘ %(stop - start))
wrapper()
????结果 : 解决了代码冗余的问题,但把"index"写死了,只能计算"index"的运行时间
import time
def index():
time.sleep(1)
print(‘from index‘)
def index2():
time.sleep(1)
print(‘from index2‘)
def wrapper(f):
start=time.time()
f() # 函数index的内存地址()
stop=time.time()
print(‘run time is %s‘ %(stop - start))
wrapper(index) # wrapper(函数index的内存地址)
wrapper(index2) # wrapper(函数index2的内存地址)
????结果 : 在上一个版本的基础上把被装饰的对象写活了,可以装饰任何无参函数,但还是改变了调用方式
import time
def index():
time.sleep(1)
print(‘from index‘)
def outter(f): # f=函数index的内存地址
def wrapper():
start=time.time()
f() # 函数index的内存地址()
stop=time.time()
print(‘run time is %s‘ %(stop - start))
return wrapper
index=outter(index) # outter(函数index的内存地址)
index() #??偷梁换柱法,让使用者感觉不到变化,之前怎么使用"index",现在还是怎么使用
????结果 : 没有改变调用方式,没有改变源代码,还实现了功能
以上版本对于不需要参数传入的函数使用没有问题, 但对有参数传入函数进行装饰就会报错
def home(name):
time.sleep(2)
print(‘home page,welecome %s‘ %name)
def outter(f): # f=函数home的内存地址
def wrapper(name): # 设置形参可进行传值
start=time.time()
f(name) # 函数home的内存地址(name)
stop=time.time()
print(‘run time is %s‘ %(stop - start))
return wrapper
home=outter(home) # outter(函数home的内存地址)
home("egon") # 偷梁换柱
????结果 : 设置形参后可以进行传值,但也就只能对"home"这个函数进行装饰了,写死了!
import time
def index():
time.sleep(1)
print(‘from index‘)
def home(name):
time.sleep(2)
print(‘home page,welecome %s‘ %name)
def outter(f): # f=函数home的内存地址
def wrapper(*args,**kwargs):
start=time.time()
f(*args,**kwargs) # 函数home的内存地址(name)
stop=time.time()
print(‘run time is %s‘ %(stop - start))
return wrapper
index=outter(index) # outter(函数index的内存地址)
index() # 偷梁换柱
home=outter(home) # outter(函数home的内存地址)
home("egon") # 偷梁换柱
????结果 : 实现了可以装饰无参和有参,并且遵循了开放封闭原则,但是还有一个问题:就是没有返回值!
import time
def index():
time.sleep(1)
print(‘from index‘)
def home(name):
time.sleep(2)
print(‘home page,welecome %s‘ %name)
return 123 #有返回值的
def outter(f): # f=函数home的内存地址
def wrapper(*args,**kwargs):
start=time.time()
res=f(*args,**kwargs) # 函数home的内存地址(name),并接收返回值
stop=time.time()
print(‘run time is %s‘ %(stop - start))
return res # 设置返回值
return wrapper
index=outter(index)
home=outter(home)
res=index()
print(res) # None
res=home("egon")
print(res) # 123
????结果 : 完美!
def outter(func):
def wrapper(*args,**kwargs):
res=func(*args,**kwargs)
return res
return wrapper
??"@"的作用就是将"index"的内存地址传递到"timmer"中??"func=index"
import time
def timmer(func):
def wrapper(*args,**kwargs):
start_time=time.time() #开始时间
res=func(*args,**kwargs)
stop_time=time.time() #结束时间
print(stop_time-start_time) #使用时间
return res
return wrapper
@timmer # index=timmer(index)
def index():
time.sleep(1)
print(‘welcome to index page‘)
return 122
@timmer # home=timmer(home)
def home(name):
time.sleep(2)
print(‘welcome %s to home page‘ %name)
index() # 调用该怎么调还是怎么调
home(‘egon‘) # 调用该怎么调还是怎么调
??实现的功能就是用户登入了才能使用"index"或者"home"
import time
current_user={
‘username‘:None, #判断用户是否已经登入,有值就是已登入,"None"就是未登入
}
def auth(func):
def wrapper(*args,**kwargs):
if current_user[‘username‘]: # 这里开始判断了
print(‘已经登陆过了‘)
res=func(*args,**kwargs) #如果已经登入就直接运行被装饰的函数
return res
uname=input(‘用户名>>: ‘).strip() # 如果未登入则输密码
pwd=input(‘密码>>: ‘).strip()
if uname == ‘egon‘ and pwd == ‘123‘:
print(‘登陆成功‘)
current_user[‘username‘]=uname
res=func(*args,**kwargs)
return res
else:
print(‘用户名或密码错误‘)
return wrapper
@auth #index=auth(index)
def index():
time.sleep(1)
print(‘welcome to index page‘)
return 122
@auth
def home(name):
time.sleep(2)
print(‘welcome %s to home page‘ %name)
index()
home(‘egon‘)
??实现用户认证,还可以计算程序运行的时间
##############用户认证装饰器##################
import time
dic = {
‘username‘: None,
}
def login(func):
def wrapper(*args, **kwargs):
if dic[‘username‘]:
print(‘已登入‘)
res = func(*args, **kwargs)
return res
name = input(‘姓名>>:‘).strip()
pwd = input(‘密码>>:‘).strip()
if name == ‘song‘ and pwd == ‘123‘:
print(‘登入成功‘)
dic[‘username‘] = name
res = func(*args, **kwargs)
return res
else:
print(‘用户名或密码错误‘)
return wrapper
##############计算时间装饰器###################
def timer(func):
def wrapper(*args,**kwargs):
start_time=time.time()
res=func(*args,**kwargs)
stop_time=time.time()
print(‘时间%s‘%(stop_time-start_time))
return res
return wrapper
##############开始装饰###################
??有前后顺序,这里计算 login()+index() 的时间(也就是加上了认证的时间)
@timer # timer在前
@login
def index():
time.sleep(1)
print(‘欢迎宋海星‘)
return 125
??只计算程序的运行时间(正确顺序)
@login
@timer #这里只计算 home() 的时间
def home(name):
time.sleep(2)
print(‘欢迎%s‘ %name)
index()
home(‘hai‘)
??观察下面,装饰器函数内部需要传入一个值"xxx",从哪里来?
def outter(func):
def wrapper(*args,**kwargs):
if xxx == "login":
res=func(*args,**kwargs)
return res
elif xxx == "login2":
print("22222")
elif xxx == "login3":
print("33333")
return wrapper
??简单语法
def auth(xxx): #再包一层
def outter(func):
def wrapper(*args,**kwargs):
if xxx == "login":
res=func(*args,**kwargs)
return res
elif xxx == "login2":
print("22222")
elif xxx == "login3":
print("33333")
return wrapper
return outter #同时也要有返回值
??通过不同的选择进行不同的身份认证(比如商家认证,买家认证等等)
import time
dic = {
‘username‘: None,
}
def auth(engine):
def auth2(func):
def wrapper(*args, **kwargs):
if engine == ‘login1‘: #如果传入的是"login1",就进入这种身份的认证
if dic[‘username‘]:
print(‘已经登陆过了‘)
res = func(*args, **kwargs)
return res
name = input(‘用户名>>: ‘).strip()
pwd = input(‘密码>>: ‘).strip()
if name == ‘egon‘ and pwd == ‘123‘:
print(‘登陆成功‘)
dic[‘username‘] = name
res = func(*args, **kwargs)
return res
else:
print(‘用户名或密码错误‘)
elif engine == ‘login2‘: #"login2"这种模式的身份认证
print(‘xx认证‘)
elif engine == ‘login3‘: #"login3"
print(‘xxxxxx认证‘)
return wrapper
return auth2
@auth(‘login3‘) #以"login3"模式的身份认证来使用"index"
def index():
time.sleep(1)
print(‘欢迎登入‘)
return 123
@auth(‘login1‘) #以"login1"模式的身份认证来使用"home"
def home(song):
time.sleep(2)
print(‘啧啧啧%s‘ % song)
index()
home(‘哈哈‘)
原文:https://www.cnblogs.com/songhaixing/p/14051171.html