闭包与装饰器

[toc]

1. 函数作为参数

alt

alt


# 函数定义的时候 ,函数内部的代码是不会执行  函数名 func_01 存储的是一个 内存 地址  0x1111
def func_01():
    print("我是函数 func_01, 这是我输出的内容.......")


# 函数定义的时候 ,函数内部的代码是不会执行  函数名 func_02 存储的是一个 内存 地址  0x2222
# 此函数有一个 形参   func , 后续要去接收 实参的值
def func_02(func):
    # 实参的值会传递给 形参, 将 func = 0x1111, 也就表示 现在的func 其实就是 func_01这个函数了
    print(func)  # 先输出的是 函数的地址
    func()  # 去调用了 函数 func_01()


# 调用 函数 func_02 ,并且传递了一个实参, func_01 ---> 0x1111  相当于 func_02(0x1111)
func_02(func_01)

1.1 结论

alt

2. 闭包

​ 闭包使用场景:我们前面已经学过了函数,我们知道当函数调用完,函数内定义的变量都销毁了,但是我们有时候需要保存函数内的这个变量,每次在这个变量的基础上完成一系列的操作,比如: 每次在这个变量的基础上和其它数字进行求和计算,那怎么办呢?我们就可以通过咱们今天学习的闭包来解决这个需求。

闭包的作用:

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

2.1 形成闭包的条件

  1. 函数嵌套的定义(在一个函数中又定义了另外一个函数)
  2. 内部函数使用外部函数的变量(外部函数的定义的变量,或者是外部函数的参数)
  3. 外部函数要返回内部函数的函数名(内部函数的引用地址)

2.2 闭包的定义

# 1.  函数嵌套的定义(在一个函数中又定义了另外一个函数)
# 2.  内部函数使用外部函数的变量(使用的变量:外部函数的定义的变量,或者是外部函数的参数)
# 3.  外部函数要返回内部函数的函数名(内部函数的引用地址)

def func_out(name):  # 这个name也是属于外部函数的变量
    # 属于外部函数 func_out 变量
    num = 100

    def func_inner():
        # 内部函数inner 中使用了 外部函数 out 的num 这个变量的数据
        print(f'外部函数的数据num是: {num}')

    return func_inner

2.3 闭包的流程图

alt

# 1.  函数嵌套的定义(在一个函数中又定义了另外一个函数)
# 2.  内部函数使用外部函数的变量(使用的变量:外部函数的定义的变量,或者是外部函数的参数)
# 3.  外部函数要返回内部函数的函数名(内部函数的引用地址)

def func_out():  # 这个name也是属于外部函数的变量
    # 属于外部函数 func_out 变量
    num = 100

    def func_inner():
        # 内部函数inner 中使用了 外部函数 out 的num 这个变量的数据
        print(f'外部函数的数据num是: {num}')

    return func_inner

# 上述代码中 就是闭包函数,那么这个闭包函数 跟普通函数调用是一样。
# 函数名()
f = func_out()   # 现在我们在调用 func_out 函数,这个函数是有返回值的,返回的是内部函数  inner 的内存地址 现在的 f 就是内部函数
f()

alt

3. 装饰器

3.1 装饰器的作用和定义

装饰器的作用:在不改变原有函数代码的基础上,给函数增加新的功能。

装饰器的语法: 装饰器函数在定义的时候 ,本质就是一个闭包, 使用的时候

  1. 使用 语法糖的方式, @闭包函数名
  2. f = 闭包函数(被装饰函数的函数名)

3.2 装饰器的执行流程

alt

3.3 装饰器装饰带有返回值的函数

alt

# 定义一个闭包
def func_out(func):

    def func_inner():
        print("进行登录操作,登录成功...")
        return func()

    return func_inner

@func_out
def user_center():
    return "用户中心....."


# 还是刚才的需求,不改变原来user_center代码基础上, 去实现让用户先进行登录,再访问个人中心操作
res = user_center()  # 执行这一句话的时候,相当于在执行 func_inner,因为func_inner中没有写return,
print(res)

3.4 装饰器装饰带有参数的函数

alt


def func_out(func):

    def func_inner(*args, **kwargs):
        print(f"{args} ---{kwargs}登录成功了")
        return func(*args, **kwargs)

    return func_inner


@func_out
def user_center(*args, **kwargs):
    return f"{args} ---{kwargs} 欢迎你访问个人中心"


res = user_center("张三", 19, "男", a=10, b=30, c=40)
print(res)

3.5 装饰器带参数


def foo(num):
    def func_out(func):
        def func_inner():
            print(f"登录成功.{num}....")
            func()
        return func_inner
    return func_out

"""
@func_out
def user_center():
    pass
这个地方:user_center = func_out(user_center) ==>  @func_out 
@foo ==> 先去执行 foo(100) ---> func_out  @foo = @func_out
"""

"""
@foo

@
foo(100)  ---> 相当于去执行 foo函数 并且传了一个实参 100, 执行foo函数的时候
因为这个函数有返回值,返回值是, func_out. 相当于foo(100) == func_out

执行完foo之后,得到了 @func_out
@func_out
def user_center():
	pass

user_center = func_out(user_center)

"""

@foo
def user_center():
    print("个人中心....")

user_center()

闭包 和 装饰器

闭包的三个条件:

  1. 函数嵌套的定义(在一个函数中又定义了另外的一个函数)
  2. 内部函数使用了外部函数的变量
  3. 外部函数返回内部函数的引用

能掌握:能够自己去定义出来闭包函数,并且能够搞清楚闭包函数执行的流程。

装饰器:装饰器本质就是闭包,作用就是在不改变原有函数的基础上,给原函数增加功能、

​ 使用: 先定义一个闭包函数,

​ 在被装饰的函数的头上,加 @闭包函数名 ==> 被装饰的函数名 = 闭包函数名(被装饰的函数名)