[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)     # 11
    print(fn() + 1)     # 11
    print(fn() + 1)     # 11
    print('-' * 21)
    # 4. 测试: 闭包的写法.
    my_fn = fn_outer(10)
    my_fn(1)    # 11
    my_fn(1)    # 11
    my_fn(1)    # 11

这里每次输出都是一样的结果,所以下面介绍一个关键字从而实现在 内部函数中, 修改外部函数的变量值.

"""
nonlocal介绍:
    概述:
        它可以实现在 内部函数中, 修改外部函数的 变量值.
    用法:
        类似于 global 关键字.
"""
# 1. 定义函数, 实现 内部函数访问外部函数的变量值.
def fn_outer():     # 外部函数
    a = 100         # 外部函数的局部变量
    def fn_inner(): # 内部函数, 有嵌套.
        # 在内部函数中, 修改外部函数的变量值, 需要通过 nonlocal 关键字实现.
        nonlocal a
        a = a + 1
        # 在内部函数中, 访问外部函数的变量
        print(f"a: {a}")        # 有引用

    return fn_inner             # 有返回


# 在main函数中测试调用.
if __name__ == '__main__':
    fn = fn_outer()     # fn = fn_inner  等价于 内部函数.
    fn()    # 101
    fn()    # 102
    fn()    # 103

装饰器:

​ 装饰器 = 闭包 +额外功能

​ 在不改变原有函数的基础上,对其功能做增强

​ 1.有嵌套

​ 2.有引用

​ 3.有返回值

​ 4.有额外功能

格式:

def 外部函数名(形参列表):
    ...
    def 内部函数名(形参列表):  # 有嵌套
        功能扩展			 # 有功能扩展
        ...
        使用外部函数的变量     # 有引用
    return 内部函数名         # 有返回

用法:

1.传统用法:

​ 变量名 = 装饰器名(被装饰的函数名)

​ 变量名()

  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, 3
    sum = a + b
    print(f'求和结果: {sum}')


# 3. 定义原函数, 表示: 减法运算.
@logging('-')
def subtract():
    a, b = 22, 11
    sub = a - b
    print(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()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值