闭包
在函数嵌套的前提下,内部函数使用了外部函数的变量,把这个内部函数成为闭包。
- 闭包构成条件
1.1 函数嵌套(函数里面再定义函数)
1.2 内部函数使用外部函数的变量
1.3 外部函数返回了内部函数
def func_out1():
num1 = 10
def func_inner(num2):
result = num1 + num2
print(f'result = {result}')
return func_inner
# 闭包保存了外部函数的变量num1,执行闭包都是在num1 = 10的基础上进行计算。
func_out1()(2) # result = 13
f = func_out1()
f(3) # result = 14
def func_out2(num1):
def func_inner(num2):
result = num1 + num2
print(f'result = {result}')
return func_inner
f = func_out2(1)
f(1) # result = 2
- 修改外部函数中的变量
python3: nonlocal修饰
def func_out3(num1):
def func_inner():
# 在闭包内修改外部函数变量,需要使用nonlocal关键字修饰
nonlocal num1
num1 += 1
print(f'修改前:num1 = {num1}')
func_inner()
print(f'修改后:num1 = {num1}')
return func_inner
func_out3(1)()
def func_out4(num1):
def func_inner():
nonlocal num1
num1 += 1
return num1
return func_inner
f = func_out4(10)
print(f()) # 11
装饰器
装饰器本质是一个闭包函数,可以对已有函数进行额外的功能扩展。
装饰器执行时机:
当前模块加载完成时,装饰器会立即执行,对已有函数进行装饰
- 装饰器(decorator)功能
- 不修改已有函数的源代码
- 不修改已有函数的调用方式
- 给已有函数增加额外功能
- 装饰器语法格式
def decorator(func): # func被装饰的目标函数
def inner():
'''执行函数之前'''
func() # 执行被装饰的目标函数
'''执行函数之后'''
return inner
# 装饰器语法糖用法:
@装饰器名称 修饰被装饰函数
- 装饰器示例
- 装饰无参数的函数
# 如果闭包函数有且只有一个参数,并且是函数类型,那么这个闭包函数称为装饰器
def outter(func):
def inner():
print("登录验证")
func()
return inner
# 装饰器语法糖写法 等价于comment = outter(comment)
@outter
def comment():
print("发表评论")
comment()
# 调用装饰器对已有函数进行装饰
# comment = outter(comment)
# comment()
"""
登录验证
发表评论
"""
- 装饰有参数的函数
def decorator_add(func):
def inner(num1, num2):
print('正在努力执行加法运算....')
func(num1, num2)
return inner
@decorator_add
def add_num(num1, num2):
result = num1 + num2
print(f'结果为:{result}')
add_num(1, 4)
"""
正在努力执行加法运算....
结果为:5
"""
- 装饰器带有返回值的函数
def decorator_add2(func):
def inner(num1, num2):
print('2正在努力执行加法运算....')
return func(num1, num2)
return inner
@decorator_add2
def add_num2(num1, num2):
return num1 + num2
result = add_num2(1, 2)
print(f'有返回值函数:result = {result}')
'''
正在努力执行加法运算....
有返回值函数:result = 3
'''
- 装饰带有不定长参数的函数
def decorator_add3(func):
def inner(*args, **kwargs):
print('3正在努力执行加法运算....')
return func(*args, **kwargs) # 拆包
return inner
@decorator_add3
def add_num3(*args, **kwargs):
print("-----call_func:args =", args, ",kwargs =", kwargs)
result = 0
for value in args:
result += value
for value in kwargs.values():
result += value
return result
result = add_num3(1, 3)
print(f'不定长参数函数:result = {result}')
result = add_num3(1, 3, num=4)
print(f'不定长参数函数:result = {result}')
'''
3正在努力执行加法运算....
-----call_func:args = (1, 3) ,kwargs = {}
不定长参数函数:result = 4
3正在努力执行加法运算....
-----call_func:args = (1, 3) ,kwargs = {'num': 4}
不定长参数函数:result = 8
'''
- 通用装饰器
def decorator(func):
def inner(*arg, **kwargs):
print('通用装饰器')
res = func(*arg, **kwargs)
return res
return inner
@decorator
def show():
print('哈哈哈哈哈哈')
show()
- 多个装饰器对同一个函数装饰
"""
多个装饰器的执行过程:
由内到外装饰,先执行内部装饰器,再执行外部装饰器
"""
def make_p(func):
print('make_p装饰器执行了')
def inner():
content = '<p>' + func() + '</p>'
return content
return inner
def make_div(func):
print('make_div装饰器执行了')
def inner():
content = '<div>' + func() + '</div>'
return content
return inner
@make_div
@make_p
def content():
return "装饰器使用练习"
print(content())
"""
make_p装饰器执行了
make_div装饰器执行了
<div><p>装饰器使用练习</p></div>
"""
- 带有参数的装饰器
带有参数的装饰器就是使用装饰器的时候,可以传入指定参数;
语法格式:@装饰器(参数...)
带有参数的装饰器其实就是在装饰器外面又包了一层函数,使用该函数接收参数,返回装饰器。
def return_decorator(flag):
def decorator(func):
def inner(num1, num2):
if flag == '+':
print('正在努力执行加法运算')
elif flag == '-':
print('正在努力执行减法运算')
func(num1, num2)
return inner
return decorator
@return_decorator('+')
def add_num(a, b):
res = a + b
print(res)
@return_decorator('-')
def sub_num(a, b):
res = a - b
print(res)
add_num(2, 5)
sub_num(5, 2)
'''
正在努力执行加法运算
7
正在努力执行减法运算
3
'''
- 类装饰器
class Check(object):
def __init__(self, func):
self._func = func
# 实现__call__方法,表示对象是一个可调用对象,可以像调用函数一样进行调用。
def __call__(self, *args, **kwargs):
print('添加装饰功能')
self._func()
@Check
def show():
print('快要下雪了')
show()
'''
添加装饰功能
快要下雪了
'''
- 装饰器使用场景
- 引入日志
- 函数执行时间统计
- 执行函数前预备处理
- 执行函数后清理功能
- 权限校验等场景
- 缓存
网友评论