Python学习----闭包和装饰器

情景:
当我们调用函数的时候,函数调用完成之后,函数内定义的变量都会被销毁,但是我们有时候需要保存函数内的这个变量,每次在这个变量的基础上完成一系列的操作,比如:每次在这个变量的基础上和其他数字进行求和计算。

我们可以通过闭包来实现这个问题。

闭包作用:

闭包可以保存函数内的变量,不会随着函数调用完成而销毁。

闭包的定义

在函数嵌套调用的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,我们把这个使用外部函数的内部函数称为闭包。

闭包构成条件:
1、在函数嵌套的前提下
2、内部函数使用了外部函数的变量(还包括外部函数的参数)
3、外部函数返回了内部函数
结论:闭包可以对外部函数的变量进行保存
在这里插入图片描述

闭包内修改外部变量
def func_out(num1):
	def func_inner(num2):
		num1 = num2 + 10
	return func_inner

问题:在func内中的num1,能否通过func_inner内的 num1=num2+10 进行修改
通过下面代码演示可以看出,inner内部的num1 相当于在inner作用域内重新定义了一个变量num1,是不会影响外部函数out的num1的。
使用 nonlocal关键字,可以在内部函数使用外部函数的参数。
和global关键一样,在函数内部使用全局变量。
在这里插入图片描述
使用nonlocal关键字之后
在这里插入图片描述


装饰器的作用

在不改变原有函数的源代码的情况下,给函数增加新的功能

装饰器的功能特点:
1、不修改已有函数的源代码
2、给已有函数增加额外的功能

装饰器使用步骤

1、定义一个装饰器(装饰器的本质是闭包)
2、使用装饰器装饰函数
在这里插入图片描述
自己总结:因为闭包,在内部函数里面使用了外部函数的参数,所以在外部函数使用结束之后,因为内部函数引用的关系,外部函数的参数并不会消失。
现在将需要被装饰的函数(源函数),作为外部函数的参数传入,在内部函数里面对 源函数 进行代码增强并且调用源函数。
这样子,就达到了不修改 原函数 但是起到了增加额外功能的目的。

语法糖简化代码
# comment = check(comment)
# 解释器遇到@check 会立即执行comment = check(comment)
@check
def comment():
	print("发表评论")
装饰器使用实例

获得函数执行时间
这个装饰器可以在任意函数进行使用,代码复用性大大提高

import time

# 定义装饰器
def get_time(fn):
    def inner():
        start_time = time.time()
        fn()
        enn_time = time.time()
        print("时间:", enn_time - start_time)

    return inner

# 被装饰的函数
@get_time
def func():
    for i in range(100000):
        print(i)


func()

装饰带有参数的函数
最后结论就是:inner参数要和被装饰的函数保质一致,因为最终返回的是inner
在这里插入图片描述

装饰带有返回值的函数
只要你明白上面的了,就可以举一反三明白下面的, inner 对标 被装饰后的,那么你装饰之前有什么,就在inner里面补什么。
在这里插入图片描述

装饰带有不定长参数的函数
和第一个装饰带有参数的是同样的道理
在这里插入图片描述

通用装饰器

def logging(fn):  # fn = sum_num
    def inner(*args, **kwargs):
        print("装饰代码")
        return fn(*args, **kwargs)

    return inner


@logging  # sum_num = logging(sum_num) ; 所以现在sum_num  = inner
def sum_num(*args, **kwargs):
    print(args)
    print(kwargs)
    return None


print("装饰之后:", sum_num(1, 2, 3, 4, 5, 6, age=19))
多个装饰器的使用
# 装饰器1
def check1(fn):
    def inner():
        print("登录验证1")
        fn()

    return inner


# 装饰器2
def check2(fn):
    def inner():
        print("登录验证2")
        fn()

    return inner


# 需要被装饰的函数
# 装饰顺序和语法糖位置写的位置一致
@check2
@check1
def comment():
    print("发表评论")

comment()

带有参数的装饰器

语法规则:装饰器的外部函数只能有一个参数,闭包不存在这个规则,只针对装饰器
但是哈,只是针对语法糖的规则
在这里插入图片描述
你不是用语法糖,上面语法规则不成立
在这里插入图片描述

如果你要使用语法糖进行传参数,那就只能多包一层。我觉得这个很鸡肋,还不如不使用语法糖
第一个@logging 第一层根本没有起到装饰器作用,外层的只是起到一个传参作用。因为add函数没有作为它的参数,虽然logging任然是闭包,但是针对add函数来说,logging作用只是传参,针对 flag函数来说,logging函数是闭包。(完美理解)
add = logging(“+”) = decorator(add) = inner(num1,num2)
在这里插入图片描述

类装饰器

__call__的使用
一旦一个类里面实现了 call方法,那么这个类创建的对象就是一个可调用对象,可以像调用函数一样进行调用。
在这里插入图片描述
类装饰器的实现,这个使用比较少,我感觉不好,和java相比,你这个类型都变了
在这里插入图片描述
同样语法糖规则也适用,comment已经变成了一个类
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值