目录
闭包
1. 闭包的定义:
在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数变量的内部函数称为闭包。
2. 闭包的构成条件:
- 在函数嵌套(函数里面再定义函数)的前提下;
- 内部函数使用了外部函数的变量(还包括外部函数的参数);
- 外部函数返回了内部函数。
示例:
# 定义一个外部函数 def func_out(num1): # 定义一个内部函数 def func_inner(num2): # 内部函数使用了外部函数的变量(num1) result = num1 + num2 print("结果是:", result) # 外部函数返回了内部函数,这里返回的内部函数就是闭包 return func_inner # 创建闭包实例 f = func_out(1) # 执行闭包 f(2) f(3)
运行结果:
结果是: 3 结果是: 4
注意:
- 闭包可以保存外部函数内的变量,不会随着外部函数调用完而销毁。
- 由于闭包引用了外部函数的变量,则外部函数的变量没有及时释放,消耗内存。
- 修改闭包内使用的外部函数变量使用 nonlocal 关键字来完成:
# 定义一个外部函数 def func_out(num1): # 定义一个内部函数 def func_inner(num2): # 这里本意想要修改外部num1的值,实际上是在内部函数定义了一个局部变量num1 nonlocal num1 # 告诉解释器,此处使用的是 外部变量a # 修改外部变量num1 num1 = 10 # 内部函数使用了外部函数的变量(num1) result = num1 + num2 print("结果是:", result) print(num1) func_inner(1) print(num1) # 外部函数返回了内部函数,这里返回的内部函数就是闭包 return func_inner # 创建闭包实例 f = func_out(1) # 执行闭包 f(2)
装饰器
就是给已有函数增加额外功能的函数,它本质上就是一个闭包函数。
装饰器的功能特点:
- 不修改已有函数的源代码
- 不修改已有函数的调用方式
- 给已有函数增加额外的功能
示例:
# 添加一个登录验证的功能 def check(fn): print("装饰器函数执行了") def inner(): print("请先登录....") fn() return inner # 使用语法糖方式来装饰函数 @check def comment(): print("发表评论") comment()
说明:
- @check 等价于 comment = check(comment)
- 装饰器的执行时间是加载模块时立即执行。
装饰器的使用场景如:函数执行时间的统计、输出日志信息 等
通用装饰器:
# 添加输出日志的功能
def logging(fn):
def inner(*args, **kwargs):
print("--正在努力计算--")
result = fn(*args, **kwargs)
return result
return inner
# 使用语法糖装饰函数
@logging
def sum_num(*args, **kwargs):
result = 0
for value in args:
result += value
for value in kwargs.values():
result += value
return result
@logging
def subtraction(a, b):
result = a - b
print(result)
result = sum_num(1, 2, a=10)
print(result)
subtraction(4, 2)
多个装饰器:
def make_div(func): """对被装饰的函数的返回值 div标签""" def inner(*args, **kwargs): return "<div>" + func() + "</div>" return inner def make_p(func): """对被装饰的函数的返回值 p标签""" def inner(*args, **kwargs): return "<p>" + func() + "</p>" return inner # 装饰过程: 1 content = make_p(content) 2 content = make_div(content) # content = make_div(make_p(content)) @make_div @make_p def content(): return "人生苦短" result = content() print(result)
说明:离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程。
类装饰器:
示例:
class Check(object): def __init__(self, fn): # 初始化操作在此完成 self.__fn = fn # 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。 def __call__(self, *args, **kwargs): # 添加装饰功能 print("请先登陆...") self.__fn() @Check def comment(): print("发表评论") comment()
执行结果:
请先登陆... 发表评论
说明:
- @Check 等价于 comment = Check(comment), 所以需要提供一个init方法,并多增加一个fn参数。
- 要想类的实例对象能够像函数一样调用,需要在类里面使用call方法,把类的实例变成可调用对象(callable),也就是说可以像调用函数一样进行调用。
- 在call方法里进行对fn函数的装饰,可以添加额外的功能。