1 闭包
是么是闭包;定义在函数内部函数,引用了外部函数作用域的名字
闭包也可以是传参的一种方式
原来学过函数是通过形参,实参传递参数,现在又多了一种方式,闭包
比如;
def func(x): def index(): print(x) return index ret = func(12) ret()
2 装饰器
什么是装饰器;,装饰器就是一个可以给被装饰对象添加新功能的工具
装饰器的开放封闭原则;
对扩展开放
对修改关闭
装饰器必须准守的两个原则
不修改被装饰对象原代码
不修改被装饰对象的调用方式
我们先来定义一个函数
# 我们先来定义一个函数,在将这个函数扩展一些功能 # 我想要这个函数在具备一些特定的功能,比如我要知道这个函数运行了多少时间 # 那我们可以这么写 import time def func(): time.sleep(3) print("func") start_time = time.time() func() end_time = time.time() print("运行了%s"%(end_time-start_time))
但这样,如果是用户,他只会去调用这个函数,虽然没有改变函数源代码,也没有改变调用方式
但总感觉,不是太理想
那我们可以这样,将下面调用函数周围的代码封装到一个函数
import time def index(): time.sleep(2) print("func") def outer(func): def inner(): start_time = time.time() func() end_time = time.time() print("运行了%s"%(end_time-start_time)) return inner index = outer(index) index()
那如果说我们要修改的函数需要参数,那这种就不会满足了,就出现了下面这种情况
import time def index(x): time.sleep(2) print(x) def outer(func): def inner(*args,**kwargs): start_time = time.time() func(*args,**kwargs) end_time = time.time() print("运行了%s"%(end_time-start_time)) return inner index = outer(index) index(1)
但是除了这几种情况,我们还遇到了有返回值的函数,所以现在的装饰器还是不完美,我们还需要修改,做到以假乱真
import time def index(x): time.sleep(2) print(x) return x def outer(func): def inner(*args,**kwargs): start_time = time.time() ret = func(*args,**kwargs) end_time = time.time() print("运行了%s"%(end_time-start_time)) return ret return inner index = outer(index) set = index(1) print(set)
当装饰器,写完了过后,我们就要学习装饰器的语法糖
格式;
@函数名(函数可以这么理解;就是装饰器外围函数)
注意一点,装饰器语法糖它是装饰与自己紧挨这的那个函数名
书写语法,必须与函数紧挨着,不能有空格
如果接的装饰器不太好理解,我们也有办法,那就是装饰器模板
def outer(func): def inner(*args,**kwargs): print("执行被装饰的对象被调用之前的功能") ret = func(*args,**kwargs) print("执行被装饰的对象被调用之后的功能") return ret return inner
装饰器传值
def outer1(a,b,c): def outer(func): def inner(*args,**kwargs): print("你好帅") print(a,b,c) ret = func(*args,**kwargs) print("可以借点钱不") return ret return inner return outer @outer1(1,2,3)
#outer1(123) 返回的是outer 那么下一步就继续@outer 等价以index = outer(index)
def index(x): print("*"*10+"hello world"+"*"*10) return x ret = index(1) print(ret)
outer1(123) 返回的就是 outer
所以就继续下一步@outer装饰器的功能、
装饰修复技术
可以将装饰器的函数的地址,返回值都改为被装饰类型的地址
from functools import wraps def outer(func): @wraps(func) def inner(*args,**kwargs): print("$$$$$$$$$$$$$$$$$$$$$$") ret = func(*args,**kwargs) print("$$$$$$$$$$$$$$$$$$$$$$$") return ret return inner @outer def index(): print("index") return 111 ret = index() print(ret) print(help(index))
多层装饰器
def outer1(func): print("outer1") def inner1(*args,**kwargs): print("inner1") ret = func(*args,**kwargs) return ret return inner1 def outer2(func): print("outer2") def inner2(*args,**kwargs): print("inner2") ret = func(*args,**kwargs) return ret return inner2 def outer3(func): print("outer3") def inner3(*args,**kwargs): print("inner3") ret = func(*args,**kwargs) return ret return inner3 @outer1 #index = outer1(inner2) @outer2 #inner2 = outer2(inner1) @outer3 #inner = outer3(index) def index(): print("index") index()