day4-装饰器
装饰器定义
首先装饰器实现的条件:高阶函数+嵌套函数 =》装饰器
装饰器实现过程
在不修改源代码的情况下,给test1,2附加功能:
import time
def test1():
time.sleep(3)
print("in the test1")
def test2():
time.sleep(3)
print("in the test2")
test1()
test2()
1.加入高阶函数
import time
def deco(func):
start_time=time.time()
func()
stop_time=time.time()
print("the func run time is %s" %(stop_time-start_time))
def test1():
time.sleep(3)
print("in the test1")
def test2():
time.sleep(3)
print("in the test2")
deco(test1)
deco(test2)
尝试1:我们要求不改变调用方式,使用高阶函数的第二种方式——>返回值中包含函数名
def deco(func):
start_time=time.time()
return func #程序运行至此return语句停止
stop_time=time.time()
print("the func run time is %s" %(stop_time-start_time))
def test1():
time.sleep(3)
print("in the test1")
def test2():
time.sleep(3)
print("in the test2")
test1 = deco(test1)
test1 ()
test2 = deco(test2)
test2 ()
#输出
in the test1
in the test2
#没有改变源代码,没有改变调用方式,但是功能没有附加
2.加入嵌套函数
尝试2:因为尝试1没有附加功能,在这里我们加入了嵌套函数
import time
def timer(func): #timer(test1) func=test1
def deco():
start_time=time.time()
func() #run test1()
stop_time=time.time()
print("the func run time is %s"%(stop_time-start_time))
return deco
def test1():
time.sleep(3)
print("in the test1")
def test2():
time.sleep(3)
print("in the test2")
test1=timer(test1)
test1() #---->实际上是在执行deco()
#输出
in the test1
the func run time is 3.0035839080810547
#当我们执行test1()时,除了执行了test1(),还附加了其他的功能
装饰器的调用
在Python中,它给我们通过另一种方式调用装饰器,想在哪个函数上附加功能,就在该函数的头部加上@timer
import time
def timer(func):#timer(test1) func=test1
def deco():
start_time=time.time()
func() #run test1()
stop_time=time.time()
print("the func run time is %s"%(stop_time-start_time))
return deco
@timer
def test1(): #该函数调用装饰器,实现附加功能
time.sleep(3)
print("in the test1")
@timer
def test2():
time.sleep(3)
print("in the test2")
test1()
test2()
#输出
in the test1
the func run time is 3.0037789344787598
in the test2
the func run time is 3.0018179416656494
1.执行函数带参数
如果我们要在test函数里面传参数的话,我们可以:
import time
def timer(func): #timer(test2) func=test2
def deco(arg1):
start_time=time.time()
func(arg1) #run test2()
stop_time=time.time()
print("the func run time is %s"%(stop_time-start_time))
return deco
@timer #相当于test1=timer(test1), test1()=deco()
def test1():
time.sleep(3)
print("in the test1")
@timer #相当于test1=timer(test1), test1()=deco()
def test2(name):
time.sleep(3)
print("in the test2")
test2(“dick”) # 由于我们执行test2("dick")是执行deco(),所以我们要把一个参数传进去
#输出
in the test1: dick
the func run time is 3.0016181468963623
但是,我们装饰的函数是千奇百怪的,所以我们要把不止一个参数传进去,怎么办?
import time
def timer(func): #timer(test2) func=test2
def deco(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs) #run test2()
stop_time=time.time()
print("the func run time is %s"%(stop_time-start_time))
return deco
@timer #相当于test1=timer(test1), test1()=deco()
def test1():
time.sleep(3)
print("in the test1")
@timer #相当于test1=timer(test1), test1()=deco()
def test2(name,age):
time.sleep(3)
print("in the test2",name,age)
test1(“dick”,22)
test2()
#输出
in the test1: dick 22
the func run time is 3.001953125
in the test2
the func run time is 3.004183053970337
最后,我们通过一个例子来验证一下:
import time
user,passwd="huwei","qawsed"
def auth(func):
def wrapper(*args,**kwargs): #2
username=input("Username:")
password=input("Password:")
if user==username and password==passwd:
print("\033[32;1mUser has passed authenticate!\033[0m")
func(*args,**kwargs) #1 “from home”
else:
exit("\033[31;1mInvalid user name or password!\033[0m")
return wrapper
def index():
print("Welcome to index page")
@auth
def home():
print("welcome to homepage")
return"from home"
@auth
def bbs():
print("bbs page")
index()
print(home()) #home()---->实际上是在执行#2处的wrapper()
bbs()
#输出
Welcome to index page
Username:huwei
Password:qawsed
User has passed authenticate!
welcome to home page
None #home返回的结果不见了,我们虽然没有改变源代码和调用方式,但是在这里,代码的返回结果改变了,怎么办?
解析:说到底其实是,#1处的func()调用的是home(),#1处没有返回的func,所以#1处的func()执行结果没有传给任何变量.而调用home()其实是在调用#2处的wrapper(),那么wrapper()执行了,没有返回值,只有内存地址,当然为None
2.执行函数有返回值
所以在#1处我们做如下修改:
return func(*args,**kwargs)
#或赋给一个变量,如:
res = func(*args,**kwargs)
print("=========")
return res
再看看我们的代码:
import time
user,passwd="huwei","qawsed"
def auth(func):
def wrapper(*args,**kwargs): #2
username=input("Username:")
password=input("Password:")
if user==username and password==passwd:
print("\033[32;1mUser has passed authenticate!\033[0m")
res = func(*args,**kwargs)
print("=========")
return res
else:
exit("\033[31;1mInvalid user name or password!\033[0m")
return wrapper
def index():
print("Welcome to index page")
@auth
def home():
print("welcome to home page")
return"from home"
@auth
def bbs():
print("bbs page")
index()
print(home()) #home()----》实际上是在执行#2处的wrapper()
bbs()
#输出
Welcome to index page
Username:huwei
Password:qawsed
User has passed authenticate!
welcome to home page
from home
但是在现实情况中,认证方式会有多种,ssh key认证,ldap认证,本地认证等等,那如何实现?再加一个认证装饰器?
答:我们可以再加一层,同时print()参数,看看传入的究竟是什么?
3.带参数的装饰器
import time
user,passwd="huwei","qawsed"
def auth(func):#3
print("auth func:",func) #4
def out_wrapper(): #5 新加入的一层
def wrapper(*args,**kwargs): #2
print("wrapper func args:",*args,**kwargs)
username=input("Username:")
password=input("Password:")
if user==username and password==passwd:
print("\033[32;1mUser has passed authenticate!\033[0m")
func(*args,**kwargs) #1 “from home”
else:
exit("\033[31;1mInvalid user name or password!\033[0m")
return wrapper
return out_wrapper
def index():
print("Welcome to index page")
@auth(auth_type="local")
def home():
print("welcome to home page")
return"from home"
@auth(auth_type="ldap")
def bbs():
print("bbs page")
index()
home()
bbs()
#输出
@auth(auth_type="local")
TypeError: auth() got an unexpected keyword argument 'auth_type'
根据输出结果,我们将#3和#4处改为auth_type
def auth(auth_type):#3
print("auth func:",auth_type) #4
#输出
@auth(auth_type="local") #auth func: local #可以看到验证方式已经传进来了
TypeError: out_wrapper() takes 0 positional arguments but 1 was given
刚刚我们的#3处的func移下来了被我们删除了,其实我们删除的func传到#5处了(整体往下移了一层),接着我们将func在#5处传进来加上
import time
user,passwd="huwei","qawsed"
def auth(auth_type):
print("auth func:",auth_type)
def out_wrapper(func):
def wrapper(*args,**kwargs):
print("wrapper func args:",*args,**kwargs)
username=input("Username:")
password=input("Password:")
if user==username and password==passwd:
print("\033[32;1mUser has passed authenticate!\033[0m")
return func(*args,**kwargs) #return func()相当于home()
else:
exit("\033[31;1mInvalid username or password!\033[0m")
return wrapper
return out_wrapper
def index():
print("Welcome to index page")
@auth(auth_type="local")
def home(): #6 home = wrapper ————>>>home()相当于wrapper(),当执行home()时,直接执行wrapper函数
print("welcome to homepage")
return"from home"
@auth(auth_type="ldap")
def bbs():
print("bbs page")
#输出
Auth func: local
Auth func: ldap
Welcome to index page
wrapper func args:
Username:huwei
Password:qawsed
User has passed authenticate!
welcome to home page
wrapper func args:
Username:huwei
Password:qawsed
User has passed authenticate!
bbs page
如果我需要根据不同的参数输入执行不同的验证方式,那么:
import time
user,passwd="huwei","qawsed"
def auth(auth_type):
print("auth func:",auth_type)
def out_wrapper(func):
def wrapper(*args,**kwargs):
print("wrapper func args:",*args,**kwargs)
if auth_type=="local":
username=input("Username:")
password=input("Password:")
if user==username and password==passwd:
print("\033[32;1mUser has passed authenticate!\033[0m")
return func(*args,**kwargs)
else:
exit("\033[31;1mInvalid username or password!\033[0m")
elif auth_type=="ldap":
print("Access LDAP server.......")
return wrapper
return out_wrapper
def index():
print("Welcome to index page")
@auth(auth_type="local")
def home():
print("welcome to home page")
return"from home"
@auth(auth_type="ldap")
def bbs():
print("bbs page")
index()
home()
bbs()
#输出
auth func: local
auth func: ldap
welcome to index page
wrapper func args:
username:huwei
password:qawsed
user has passed authenticate!
welcome to home page
wrapper func args:
Access LDAP server.......

浙公网安备 33010602011771号