装饰器
定义:本质是函数,(功能:装饰其他函数);就是为其他函数添加附加功能
模拟场景一,在现有的函数中增加某个功能。现有的做法是定义新函数,并且加入函数中。需要修改源代码。
def logger(): print("logging") def test1(): logger() def test2(): logger()
场景二,如果是在生产环境中,需要增加功能。不能直接修改源代码。该怎么实现。
原则:1. 不能修改被装饰的函数的源代码
2. 不能修改被装饰的函数的调用方式
装饰器实例:直观感受一下装饰器的作用。
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. 函数即“变量”
通过例子来阐述函数即“变量”:
#例一:因为没有定义bar函数,程序报错 def foo(): print("in the foo") bar() foo() #例二:程序正常运行,相当于先定义变量x和y,再进行输出。 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() #例四:程序报错。因为执行foo函数的时候,当顺序执行到bar()语句的时候,这时候bar还没有被定义。 def foo(): print("in the foo") bar() foo() def bar(): print("in the bar")
2. 高阶函数
a: 把一个函数名当做实参传给另外一个函数(在不修改被装饰函数源代码的情况下为其添加功能)
举例:
import time def bar(): time.sleep(1) print("in the bar") def test1(func): start_time =time.time() func() stop_time =time.time() print("the func run time is %s" %(stop_time-start_time)) test1(bar)
b: 返回值中包含函数名(不修改函数的调用方式)
实例:
import time def bar(): time.sleep(2) print("in the bar") def test2(func): print(func) return func bar =test2(bar) bar()
3. 嵌套函数:在def定义的函数中用def再定义函数。里层的函数有局部变量的特性。
def foo(): print("in the foo") def bar(): print("in the bar") bar() foo()
总结:高阶函数+嵌套函数 => 装饰器
复习作用域内容,以供下面内容所需:局部作用域和全局作用域的访问顺序:由内而外。
#局部作用域和全局作用域的访问顺序 x = 0 def grandpa(): # x = 1 def dad(): x = 2 def son(): x = 3 print(x) son() dad() grandpa()
装饰器实例一:
import time def timer(func): #timer(test1) func=test1 def deco(): start_time = time.time() func() #运行被装饰的函数 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) #等待1秒 print("in the test1") def test2(): time.sleep(1) print("in the test2") test1() test2 = timer(test2) #python提供了语法糖@,用法看test1 test2()
由实例一引出的问题:如果test2是有参数需要传递的,那么以上代码在运行到test2()的时候就会报错。
需要把代码改成通用型。
实例二:通用型装饰器代码。
import time def timer(func): #timer(test1) func=test1 def deco(*args,**kwargs): #以实现任意参数的传递 start_time = time.time() func(*args,**kwargs) #运行被装饰的函数,不带参数或带参数都可以运行 stop_time=time.time() print("the func run time is %s" %(stop_time-start_time)) return deco @timer def test1(): time.sleep(1) #等待1秒 print("in the test1") @timer def test2(name,age,job): time.sleep(1) print("test2:",name, age, job) test1() test2("abc",23,"IT")
实例一没有解决函数有返回值的问题。导致虽然没有改变源代码和调用方式,但是运行的结果变了。需要修改代码如下:
import time 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("