闭包
1. 什么是闭包
在 python 中创建一个闭包一般有3个要求:
(1)闭包函数必须有内嵌函数
(2)内嵌函数必须要引用外层函数的变量
(3)闭包函数返回内嵌函数的地址(函数名称)
作用:可以在不修改目标源码的前提下,加功能
注意:闭包函数中的变量的生命周期得到延长
2. 创建一个闭包函数
def funcOut():
name = 'Jery'
def funcIn():
# format的简写方式
print(f"姓名 = {name}")
return funcIn
f = funcOut()
f()
运行结果:
姓名 = Jery
3. 判断是否为闭包函数
闭包函数相对与普通函数会多出一个__closure__的属性,里面定义了一个元组用于存放所有的cell对象,每个cell对象保存了这个闭包中所有的外部变量。
funcIn.__closure__:返回None,则不是闭包函数
如:
def funcOut():
name = 'Jery'
def funcIn():
print(f"姓名 = {name}")
print(funcIn.__closure__)
print(funcIn.__closure__[0].cell_contents) # 第一个外部变量
return funcIn
f = funcOut()
f()
运行结果
(,)
Jery
姓名 = Jery
装饰器
1. 本质及作用
装饰器的本质
闭包函数
装饰器的作用:
在不修改原函数及其调用方式的情况下对原函数功能进行扩展
2. 装饰器的使用
需求:为现有功能fun1增加日志功能
传统方案解决 —— 使用闭包
def writeLog(fn):
print("记录日志")
print('访问方法:'+fn.__name__)
def funcOut(func):
def funcIn():
writeLog(func)
func()
return funcIn
def fun1():
print("使用功能1")
def fun2():
print("使用功能2")
fun1 = funcOut(fun1)
# 装饰器(闭包)
fun1()
运行结果:
记录日志
访问方法:fun1
使用功能1
使用装饰器(语法糖)解决
def writeLog(fn):
print("记录日志")
print('访问方法:'+fn.__name__)
def funcOut(func):
def funcIn():
writeLog(func)
func()
return funcIn
@funcOut
def fun1():
print("使用功能1")
@funcOut
def fun2():
print("使用功能2")
fun1()
fun2()
运行结果:
记录日志
访问方法:fun1
使用功能1
记录日志
访问方法:fun2
使用功能2
3. 多个装饰器的使用
如:
def war1(func):
print("war 1")
def inner(*args, **kwargs):
print("======war1 start=====")
func(*args, **kwargs) # inner
print("======war1 end=====")
return inner
def war2(func):
print("war2")
def inner(*args, **kwargs):
print("======war2 start=====")
func(*args, **kwargs)
print("======war2 end=====")
return inner
@war1
@war2
def f():
print("****self****")
f()
运行结果:
war2
war1
======war1 start=====
======war2 start=====
****self****
======war2 end=====
======war1 end=====
解释:
(1)
@war1
@war2 之后相当于 --> f = war1(war2(f))
其中war2(f)是一个函数,作为实参传递
war2(f):
print("======war2 start=====")
print("****self****")
print("======war2 end=====")
war1(war2(f)):
print("======war1 start=====")
war2(f)
print("======war1 end=====")
(2)
f() 相当于执行 --> war1(war2(f))()
4. 对有参数的函数进行装饰
def funcOut(fn):
print("funcOut")
def funcIn(aa, bb):
print("funcIn1")
fn(aa,bb)
print("funcIn2")
return funcIn
@funcOut
def test(a, b):
print("a=%d,b=%d" % (a, b))
# 装饰器装饰之后,这不是直接调用test方法,而是调用func_in方法
test(1,2)
结果
funcOut
funcIn1
a=1,b=2
funcIn2
5. 通用装饰器的使用
一个装饰器可以装饰多个不同参数、不同返回值的函数
如:
def funcOut(fn):
# 需要有参数,*args,**kwargs
def funcIn(*args,**kwargs):
print("记录日志")
print('访问方法:'+fn.__name__)
# 需要有参数,*args,**kwargs
# 需要有返回值
return fn(*args,**kwargs)
return funcIn
# 待装饰函数1:无参数,无返回值
@funcOut
def test1():
print("test1")
test1()
print("---------")
# 待装饰函数2:无参数,有返回值
@funcOut
def test2():
return "Hello"
print(test2())
print("---------")
# 待装饰函数3:有参数,无返回值
@funcOut
def test3(a):
print('a=%d'%a)
test3(1)
print("---------")
# 待装饰函数3:有键值对参数,无返回值
@funcOut
def test4(**kwargs):
print(kwargs)
test4(a=1)
结果
记录日志
访问方法:test1
test1---------记录日志
访问方法:test2
Hello---------记录日志
访问方法:test3
a=1
---------记录日志
访问方法:test3
{'a': 1}