day03.18
作者:互联网
闭包函数
闭包函数的定义理解:
如果在一个函数的内部定义了另一个函数,外部的我们叫他外函数,内部的我们叫他内函数。在一个外函数中定义了一个内函数,内函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。
一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。
闭包函数的两大特征:
- 闭:定义在函数内部的函数
- 包:内部函数使用了外层函数名称空间中的名字
#闭包函数的实例 # outer是外部函数 a和b都是外函数的临时变量 def outer( a ): b = 10 # inner是内函数 def inner(): #在内函数中 用到了外函数的临时变量 print(a+b) # 外函数的返回值是内函数的引用 return inner if __name__ == '__main__': # 在这里我们调用外函数传入参数5 #此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo # 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数 demo = outer(5) # 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量 # demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数 demo() # 15 demo2 = outer(7) demo2()#17
def outer(): x = 999 def inner(): print('from outer>>>inner',x) return inner x = 666 res = outer() # 把outer的返回值赋予res res()
闭包函数的实际应用:
闭包函数是给函数体传参的另一种形式
- 函数体传参的方式:形参
def index(username): print(username) # 函数体代码需要什么就可以在形参中写什么 index('jason')
- 函数体传参的另一种方式:闭包
def outer(): username = 'jason' def index(): print(username) # 永远使用的都是jason return index res = outer()
#修改闭包变量的实例 # outer是外部函数 a和b都是外函数的临时变量 def outer( a ): b = 10 # a和b都是闭包变量 c = [a] #这里对应修改闭包变量的方法2 # inner是内函数 def inner(): #内函数中想修改闭包变量 # 方法1 nonlocal关键字声明 nonlocal b b+=1 # 方法二,把闭包变量修改成可变数据类型 比如列表 c[0] += 1 print(c[0]) print(b) # 外函数的返回值是内函数的引用 return inner if __name__ == '__main__': demo = outer(5) demo() # 6 11
note:使用闭包的过程中,一旦外函数被调用一次返回了内函数的引用,虽然每次调用内函数,是开启一个函数执行过后消亡,但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量!!!
装饰器
python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象!装饰器函数的外部函数传入我要装饰的函数名字,返回经过修饰后函数的名字;内层函数(闭包)负责修饰被修饰函数。
装饰器的本质:
在不改变被装饰对象原有的'调用方式'和'内部代码'的情况下,给被装饰对象添加新的功能。
装饰器的原则:对功能扩展开放、对代码修改封闭。
简易版本的装饰器
import time def index(): time.sleep(1) print('from index') def home(): time.sleep(3) print('from home') print(home) def outer(func): # 真正的index被outer局部名称空间存储了 def get_time(): start_time = time.time() # 函数执行之前获取一个时间戳 func() # 调用了真正的index函数 end_time = time.time() # 函数执行之后获取一个时间戳 print(end_time - start_time) # 两个时间戳的差值就是函数的执行时间 return get_time
进阶版本的装饰器
# 解决的是参数问题 def outer(func_name): def get_time(*args, **kwargs): start_time = time.time() func_name(*args, **kwargs) end_time = time.time() print(end_time - start_time) return get_time
完整版本的装饰器
# 解决的是返回值问题 def outer(func_name): def get_time(*args, **kwargs): start_time = time.time() res = func_name(*args, **kwargs) # 执行真正的index函数 end_time = time.time() print(end_time - start_time) # return '不要急躁' # 如何在此处返回真正index函数的返回值 return res return get_time
装饰器的模板
编写装饰器其实有一套固定的代码。
def outer(func_name): # func_name用于接收被装饰的对象(函数) def inner(*args, **kwargs): print('执行被装饰函数之前 可以做的额外操作') res = func_name(*args, **kwargs) # 执行真正的被装饰函数 print('执行被装饰函数之后 可以做的额外操作') return res # 返回真正函数的返回值 return inner
装饰器语法糖
仅仅是让代码编写的更加好看、简洁!!!
语法糖内部原理:
- 使用的时候最好紧跟在被装饰对象的上方
- 语法糖会自动将下面紧挨着的函数名传给@后面的函数调用
def outer(func_name): def inner(*args, **kwargs): print('执行函数之前的操作') res = func_name(*args, **kwargs) # 额外操作 return res return inner @outer # 等价于 index = outer(index) def index(*args, **kwargs): print('from index') # index = outer(index) # 总感觉这一行代码有点low!!! @outer # 等价于 home = outer(home) def home(*args,**kwargs): print('from home') print(index) print(home)
装饰器的修复技术
用@wraps来修复装饰器装饰后的函数的名称等属性发生的变化。
from functools import wraps def outer(func_name): @wraps(func_name) def inner(*args, **kwargs): print('执行被装饰对象之前可以做的操作') res = func_name(*args, **kwargs) return res return inner @outer def index(): print('from index') @outer def home(): print('from home')
标签:index,outer,函数,day03.18,time,print,def 来源: https://www.cnblogs.com/-sunflower-/p/16026668.html