本文主要是介绍[Python]闭包与装饰器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
闭包与装饰器
闭包:
python的一种独有写法,可以实现:对外部函数的局部变量进行’临时’存储
作用:
可以"延长"函数内 局部变量的生命周期.
构成条件:
1. 有嵌套. 外部函数内要嵌套 内部函数.
2. 有引用. 在内部函数中使用 外部函数的变量.
3. 有返回. 在外部函数中, 返回 内部函数名, 即: 内部函数对象
格式
def 外部函数名(形参列表):......def 内部函数名(形参列表): # 有嵌套......使用外部函数的变量 # 有引用return 内部函数名 # 有返回
代码举例:
# 需求1: 定义1个函数用于保存变量10, 然后调用函数返回值并重复累加数值, 观察结果.
# 1. 定义函数.
def fn():return 10
# 需求2: 定义1个用于求和的闭包, 外部函数有num1参数, 内部函数有num2参数, 然后调用, 求两数之和, 观察结果.
def fn_outer(num1): # 外部函数def fn_inner(num2): # 内部函数, 有嵌套# 具体的求和动作.sum = num1 + num2 # 有引用, 内部函数中, 使用了外部函数的变量 num1# 打印结果.print(f'求和结果: {sum}')return fn_inner # 有返回
# 在main函数中测试.
if __name__ == '__main__':# 3.测试: 非闭包写法.print(fn() + 1) # 11print(fn() + 1) # 11print(fn() + 1) # 11print('-' * 21)# 4. 测试: 闭包的写法.my_fn = fn_outer(10)my_fn(1) # 11my_fn(1) # 11my_fn(1) # 11
这里每次输出都是一样的结果,所以下面介绍一个关键字从而实现在 内部函数中, 修改外部函数的变量值.
"""
nonlocal介绍:概述:它可以实现在 内部函数中, 修改外部函数的 变量值.用法:类似于 global 关键字.
"""
# 1. 定义函数, 实现 内部函数访问外部函数的变量值.
def fn_outer(): # 外部函数a = 100 # 外部函数的局部变量def fn_inner(): # 内部函数, 有嵌套.# 在内部函数中, 修改外部函数的变量值, 需要通过 nonlocal 关键字实现.nonlocal aa = a + 1# 在内部函数中, 访问外部函数的变量print(f"a: {a}") # 有引用return fn_inner # 有返回# 在main函数中测试调用.
if __name__ == '__main__':fn = fn_outer() # fn = fn_inner 等价于 内部函数.fn() # 101fn() # 102fn() # 103
装饰器:
装饰器 = 闭包 +额外功能
在不改变原有函数的基础上,对其功能做增强
1.有嵌套
2.有引用
3.有返回值
4.有额外功能
格式:
def 外部函数名(形参列表):...def 内部函数名(形参列表): # 有嵌套功能扩展 # 有功能扩展...使用外部函数的变量 # 有引用return 内部函数名 # 有返回
用法:
1.传统用法:
变量名 = 装饰器名(被装饰的函数名)
变量名()
-
@标记符实现:
在要被装饰的函数上,写:@装饰器名
代码举例:
需求: 发表评论前, 需要先登录. 大白话翻译: 定义发表评论的函数, 在不改变该函数的基础上, 实现: 先登录, 后发表评论.
# 被装饰的函数: 发表评论.
# 装饰器: 登陆功能.# 1. 定义函数, 充当装饰器, 用来给函数增加: 登陆功能(额外功能).
def check_login(fn_name):def fn_inner(): # 有嵌套print('登陆中...') # 有额外功能fn_name() # 有引用return fn_inner # 有返回# 2. 定义函数, 表示: 发表评论.
@check_login
def comment():print('发表评论!...')# 在main函数中调用.
if __name__ == '__main__':# 3. 普通写法, 直接调用函数.# comment()# 4. 装饰器, 用法1: 传统格式.# comment = check_login(comment)# comment()# 5. 装饰器, 用法2: 语法糖格式.comment()
在创建装饰器的时候,需要考虑传入函数的参数问题.内部函数要和传入函数的参数一样:
如:
传入函数有参有返回值,内部函数也要有参有返回值
传入函数有参无返回值,内部函数也要有参无返回值
传入函数无参有返回值,内部函数也要无参有返回值
传入函数无参无返回值,内部函数也要无参无返回值
因为每个装饰器只允许传入一个参数,所以每当需要增加参数传入时,需要新增一层装饰器来修饰当前装饰器:
# 需求: 定义1个既能装饰加法运算, 也能装饰减法运算的装饰器, 即: 带有参数的装饰器, 并测试.# 1. 定义装饰器, 能装饰 加法, 减法运算.
def logging(flag):def decorator(fn_name):# def decorator(fn_name, flag): # decorator: 装饰的意思, 这行代码会报错, 因为装饰器的参数只能有1个.def fn_inner(): # 有嵌套if flag == '+':print('[友好提示] 正在努力计算 加法 中...') # 有额外功能elif flag == '-':print('[友好提示] 正在努力计算 减法 中...') # 有额外功能fn_name() # 有引用return fn_inner # 有返回return decorator # 有返回# 2. 定义原函数, 表示: 加法运算.
@logging('+')
def add():a, b = 10, 3sum = a + bprint(f'求和结果: {sum}')# 3. 定义原函数, 表示: 减法运算.
@logging('-')
def subtract():a, b = 22, 11sub = a - bprint(f'求差结果: {sub}')# 在main函数中测试调用.
if __name__ == '__main__':# 4. 测试加法.add()print('-' * 21)# 5. 测试减法.subtract()
当多个装饰器装饰一个函数时,参考:传统写法:由内到外,语法糖:由上到下:
# 需求: 发表评论前, 需要先登录, 再进行验证码校验.# 1. 定义装饰器, 增加 登陆功能.
def check_login(fn_name):def fn_inner(): # 有嵌套print('登陆校验中!.....') # 有额外功能.fn_name() # 有引用return fn_inner # 有返回# 2. 定义装饰器, 增加 验证码校验功能.
def check_code(fn_name):def fn_inner(): # 有嵌套print('验证码校验中!.....') # 有额外功能.fn_name() # 有引用return fn_inner # 有返回# 3. 定义原函数, 表示: 发表评论.
@check_login
@check_code
def comment():print("发表评论!")# 在main函数中, 测试.
if __name__ == '__main__':# 4. 测试: 装饰器的写法1 传统写法.cc = check_code(comment) # 增加: 验证码校验功能.cl = check_login(cc) # 增加: 登陆功能.cl()print('-' * 21)# 5. 测试: 装饰器的写法2 语法糖.comment()
这篇关于[Python]闭包与装饰器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!