装饰器
Pyhon装饰器
标签(空格分隔): 进阶
装饰器:本质是函数,(装饰其他函数)就是为其它函数提供附加功能
原则:
1、不能修改被装饰函数的源代码
2、不能修改被装饰函数的调用方式
#下面定义了一个装饰器应用的例子。timmer函数作为装饰器,来给test1()函数增加了一个打印函数运行时间的功能
import time
def timmer(func):
def warpper(*args,**kwargs):
start_time=time.time()
func()
stop_time=time.time()
print('the func run time is %s' %(stop_time-start_time))
return warpper
@timmer
def test1():
time.sleep(3)
print('in the test1')
test1()
实现装饰器知识储备:
1、函数即“变量”
2、高阶函数
a)把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
b)返回值中包含函数名 (不修改函数的调用方式)
3、嵌套函数
高阶函数+嵌套函数=》装饰器
1、函数即变量
定义了一个函数就相当于把函数体赋值给了函数名
def test()
pass
#上面的test()函数就相当于: test = '函数体'
看以下三种调用foo()函数的结构,思考
1、哪种能正常运行
2、为什么
#示范一:
def bar():
print('in the bar')
def foo():
print('in the foo')
bar()
foo()
#示范二:
def foo():
print('in the foo')
bar()
def bar():
print('in the bar')
foo()
#示范三:
def foo():
print('in the foo')
bar()
foo()
def bar():
print('in the bar')
2、高阶函数
a)把一个函数名当作实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
##下面这段代码把bar做为实参传给函数test
def bar():
print ("in the bar")
def test(func):
print (func)
func()
test(bar)
##下面这段代码通过把函数bar做为实参传给函数test,在不修改函数bar源代码的情况下,增加了计算了函数bar的运行时间的功能
import time
def bar():
time.sleep(3)
print('in the bar')
def test(func):
start_time=time.time()
func() #run bar
stop_time=time.time()
print("the func run time is %s" %(stop_time-start_time))
test(bar)
b)返回值中包含函数名 (不修改函数的调用方式)
##下面这段代码仍然是把函数bar做为实参传给函数test。然后先调用高阶函数test实现了一些附加功能(计算函数bar的运行时间),再返回函数bar的地址。最终通过增加代码“bar = test()”实现既执行了函数test,又
import time
def bar():
time.sleep(3)
print('in the bar')
def test(func):
print(func)
return func
bar=test(bar)
bar() #run bar
3、嵌套函数
定义:在一个函数的函数体内用def去声明一个新的函数(不是调用)
def foo():
print('in the foo')
def bar():
print('in the bar')
bar()
foo()
装饰器
通过前面的知识储备,下面可以开始学些装饰器了。
##下面代码通过高阶函数+嵌套函数的功能实现了既不修改函数test代码,又不修改函数test调用方式,而增加了打印函数test运行时间的功能
import time
def timer(func): #timer(test) func=test
def deco():
start_time=time.time()
func() #run test()
stop_time = time.time()
print("the func run time is %s" %(stop_time-start_time))
return deco
def test():
time.sleep(1)
print('in the test')
test = timer(test)
test()
利用语法糖来实现上述功能
import time
def timer(func): #timer(test) func=test
def deco():
start_time=time.time()
func() #run test()
stop_time = time.time()
print("the func run time is %s" %(stop_time-start_time))
return deco
@timer # 等于 test = timer(test)
def test():
time.sleep(1)
print('in the test')
test()
装饰带参数的函数
上面代码已经实现了装饰器的功能,没修改被装饰函数的源代码也没修改调用方式,但是却只能装饰简单的函数,如果被装饰函数带有参数就无法实现了。下面看怎么装饰带参数的函数。
##利用可变参数来装饰带有任何数量参数的函数
import time
def timer(func): #timer(test1) func=test1
def deco(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs) #run test1()
stop_time = time.time()
print("the func run time is %s" %(stop_time-start_time))
return deco
@timer #test1=timer(test1)
def test1():
time.sleep(1)
print('in the test1')
@timer # test2 = timer(test2) = deco test2(name) =deco(name)
def test2(name,age):
print("test2:",name,age)
test1()
test2("alex",22)
装饰带返回值的函数
上节通过可变参数来实现装饰带任意参数的函数。但是只能装饰不带返回值的函数,仍有一定的局限性,下面看怎么装饰带返回值的函数。
##下面这段代码装饰了带返回值的函数home,但是打印函数运行结果时,却未能将返回值打印出来,思考下为什么,怎样才能得到返回值
user,passwd = 'alex','abc123'
def auth(func):
def wrapper(*args, **kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
func(*args,**kwargs)
else:
exit("\033[31;1mInvalid username or password\033[0m")
return wrapper
@auth
def home():
print("welcome to home page")
return "from home"
print (home())
##下面这段代码解决了上述问题
user,passwd = 'alex','abc123'
def auth(func):
def wrapper(*args, **kwargs):
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs)
#此处也可直接用 return (func (*args, **kwargs))
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
return wrapper
@auth
def home():
print("welcome to home page")
return "from home"
print (home())
修饰符带参数的装饰器
user,passwd = 'alex','abc123'
def auth(auth_type):
print("auth func:",auth_type)
def outer_wrapper(func):
def wrapper(*args, **kwargs):
print("wrapper func args:", *args, **kwargs)
if auth_type == "local":
username = input("Username:").strip()
password = input("Password:").strip()
if user == username and passwd == password:
print("\033[32;1mUser has passed authentication\033[0m")
res = func(*args, **kwargs) # from home
print("---after authenticaion ")
return res
else:
exit("\033[31;1mInvalid username or password\033[0m")
elif auth_type == "ldap":
print("搞毛线ldap,不会。。。。")
return wrapper
return outer_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local") # home = wrapper()
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap")
def bbs():
print("welcome to bbs page")
index()
print(home()) #wrapper()
bbs()