在函数中可以(嵌套)定义另一个函数时,如果内部的函数引用了外部的函数的变量,则可能产生闭包。闭包可以用来在一个函数与一组“私有”变量之间创建关联关系。
闭包中被内部函数引用的变量,不会因为外部函数结束而被释放掉,而是一直存在内存中,知道内部函数被调用结束。
闭包的特点就是内部函数引用了外部函数中的变量。
闭包函数的必要条件:
def func(): name = 'python' def inner(): print(name) return inner f = func() # f = func() = inner f() # f() = inner # 输出结果:python
如何判断是否是闭包函数:
输出cell:
def func(): name = 'python' def inner(): print(name) print(inner.__closure__) # (<cell at 0x0000027C14EB85E8: str object at 0x0000027C14F54960>,) return inner f = func() f()
输出None:
name = 'python' def func(): def inner(): print(name) print(inner.__closure__) # None return inner f = func() f()
# 闭包函数是给函数体传参的另外一种方式 """函数体传参的方式1:形参""" def index(username): print(username) # 函数体代码需要什么就可以在形参中写什么 index('jason') """函数体传参的方式2:闭包""" # def outer(): # username = 'jason' # def index(): # print(username) # 永远使用的都是jason # return index # res = outer() def outer(username): # username = 'jason' def index(): print(username) # 永远使用的都是jason return index res = outer('kevin') # 形参username与值kevin临时绑定 >>>:outer局部名称空间中 res() res1 = outer('jason') # 形参username与值kevin临时绑定 >>>:outer局部名称空间中 res1()
‘装饰’代指为被装饰对象添加新的功能,’器’代指器具/工具,装饰器与被装饰的对象均可以是任意可调用对象。
装饰器的作用就是在不修改被装饰对象源代码和调用方式的前提下为被装饰对象添加额外的功能。
函数装饰器分为:无参装饰器和有参装饰两种,二者的实现原理一样,都是’函数嵌套+闭包+函数对象’的组合使用的产物。
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 res = outer(index) # 左侧的res就是一个普通的变量名 res() a = outer(index) # 左侧的a就是一个普通的变量名 a() b = outer(index) # 左侧的b就是一个普通的变量名 b() index = outer(index) index() # 看似调用的index其实调用的是get_time print(index) # 全局名称空间中的index指向的是get_time函数体代码 home = outer(home) # 狸猫换太子
# 解决的是参数问题 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
# 仅仅是让代码编写的更加好看、简洁!!! # Author:Jason 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) """ 语法糖内部原理 1.使用的时候最好紧跟在被装饰对象的上方 2.语法糖会自动将下面紧挨着的函数名传给@后面的函数调用 ps:针对之前的周末大作业 只需要单独写一个装饰器 之后使用语法糖装饰即可 """
今天的内容重在理解和练,理解很重要!!!