目录
1.闭包
闭包的本质就是函数的嵌套,函数内部再定义函数
闭包的定义:内外函数嵌套,内部函数引用外部函数作用域下的非全局变量,外函数返回内函数对象
创建一个闭包必须满足以下几点:
-
必须有一个内嵌函数
-
内嵌函数必须引用外部函数中的变量
-
外部函数的返回值必须是内嵌函数
闭包有两种不同的方式,第一种是“返回一个函数名称”,第二种是在函数内部就“直接调用”
1.1 返回一个函数名称:
# 定义外层函数
def outer():
# 外函数临时变量num1
num1 = 100
def inner():
# 内函数里运用了外函数的临时变量
num2 = num1 + 1
print("num2 =",num2)
# 外函数的返回值是内函数的引用
return inner
outer()()
#结果: num2=101
1.2 直接调用:
def outer():
# 外函数临时变量num1
num1 = 100
def inner():
# 内函数里运用了外函数的临时变量
num2 = num1 + 1
print("num2 =",num2)
# 外函数的返回值是内函数的引用
return inner()
outer()
# 结果:num2=101
1.3 闭包的优缺点
优点:
- 可以避免使用全局变量,防止全局变量污染
- 可以读取函数内部的变量
- 延长了局部变量的作用域范围
缺点:
- 变量不会被收回,消耗内存
- 会造成内存泄漏
2.装饰器
装饰器作用:采用了闭包的思路,在不改变原函数名(或类名)的情况下,给函数增加新的功能
装饰器的语法以@开头,接着是装饰器函数的名字和可选的参数。紧跟着装饰器声明的是被修饰的函数和装饰函数的可选参数
装饰器的应用场景:引入日志、函数执行时间统计、执行函数前预备处理、执行函数后清理功能、权限校验等场景、缓存、事务处理、数据清理、数据添加、附加功能等
格式:
# 外层函数
def outer(func):
# 内层函数
def inner():
func()
# 额外添加的功能
print("hello")
# 外层函数返回内层函数的引用
return inner
@outer # 给index函数添加 outer装饰器
def index():
pass
index()
# 结果:hello
参数传递
2.1 装饰器形式
def outer(func):
def inner():
print("装饰器开始执行")
print("功能添加")
func()
print("装饰器结束执行")
return inner
@outer # 给add函数添加 outer装饰器
def add():
print("hello")
add()
# 结果: 装饰器开始执行
# 功能添加
# hello
# 装饰器结束执行
2.2 装饰器传参形式
def outer(func):
def inner(a, b):
print("装饰器执行")
print("A---B")
func(a, b)
print("装饰器结束执行")
return inner
@outer # 给add函数添加一个outer装饰器
def add(a, b):
print("a+b = ", (a+b))
add(10,20)
# 结果: 装饰器执行
# A---B
# a+b = 30
# 装饰器结束执行
2.3 不定长参数传参
def outer(func):
def inner(*args, **kwargs):
print("装饰器执行")
print("A---*---B")
func(*args, **kwargs)
print("装饰器结束执行")
return inner
@outer # 给add函数添加一个outer装饰器
def add(a, b,c,d):
print("a+b+c+d = ", (a+b+c+d))
add(10, 20, 30, 40)
# 结果: 装饰器执行
# A---*---B
# a+b+c+d = 100
# 装饰器结束执行
2.4 装饰器的优缺点
优点
- 灵活性高,当需要扩展多个功能时,只需要增加新的具体装饰类即可
- 装饰类和被装饰类可以独立发展,耦合性低,装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能
缺点
- 多层装饰较为复杂
- 不能装饰@staticmethod 或者 @classmethod已经装饰过的方法
- 装饰器会对原函数的元信息进行更改
3.闭包装饰器区别
闭包和装饰器的区别:闭包传递的是变量,而装饰器传递的是函数,除此之外没有任何区别,或者说装饰器是闭包的一种,它只是传递函数的闭包。