闭包背景介绍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
"""
案例目的: 引出闭包相关知识点
"""


# 定义一个函数用于保存变量10,然后调用函数返回值变量并重复累加数值,观察效果。

def func():
num = 10
return num


num = func()
print(num + 1) # 11 想要结果是 11
print(num + 1) # 11 vs 12
print(num + 1) # 11 vs 13

# 你会发现无法实现累加!那么如何实现累加呢!! 闭包

闭包入门

1742729820839

1742729926650

1742729941350

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
# 定义一个用于求和的闭包。
# 其中,外部函数有参数num1,内部函数有参数num2,
# 然后调用,并用于求解两数之和,观察效果
"""
闭包解释:
概述: 内部函数使用外部函数的变量,这种写法称之为闭包
格式:
def 外部函数(形参列表):
外包函数(局部)变量
def 内部函数(形参列表):
使用外部函数的变量
return 内部函数名
!!!注意这里不要括号
总结:闭包前提
1:有嵌套
2:有引用
3:有返回
细节:1:函数名 和函数名() 不是一个概念,前者是表示 函数对象(函数变量)后者表示函数调用返回值
"""


# 解释1:定义一个函数 函数名 函数名()
def get_sum(a, b):
return a + b


print(get_sum) # <function get_sum at 0x0000019EDD1DACA0> 函数对象
print(get_sum(20, 30)) # 此句是函数调用,有返回值 50

# 既然是变量,那么函数名可以赋值给一个变量,这个就是函数对象
# 函数名 get_sum
# 赋值给一个变量 my_sum
my_sum = get_sum
# my_sum是一个什么 ? 函数对象 、函数变量
print(my_sum) # <function get_sum at 0x000001AF4666ACA0>
# 此时我们知道my_sum是一个函数对象、函数变量。使用
print(my_sum(100, 200))


# 定义一个用于求和的闭包。
# 其中,外部函数有参数num1,内部函数有参数num2,
# 然后调用,并用于求解两数之和,观察效果

# 1:外部函数
def fu_outer(num1):
# 2.内部函数
def fu_inner(num2): # ①有嵌套
# 3.两数之和
sum = num1 + num2 # ②有引用
print(f"求和结果{sum}")
return fu_inner # ③有返回
# 4.调用上面函数
fn_inner = fu_outer(10)
fn_inner(1)
fn_inner(1)
fn_inner(1)


nonlocal关键字介绍

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    """
    nonlocal:
    他是一个python内置的关键字,可以实现在内部函数中,修改外部函数的变量值
    编写一个闭包,让内部函数去访问外部函数内的参数a = 100,观察效果。
    """
    def fn_outer():
    a = 100 # 有嵌套
    def fn_inner():
    # a = a + 1 # 有引用 #生命周期不同
    nonlocal a
    a=a+1
    print(f"a:{a}")
    return fn_inner
    if __name__ == '__main__':
    a = fn_outer()
    a() # 101
    a() #102
    a() #103

装饰器入门

  • 图解

  • 代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    # 例如,发表评论前,都是需要先登录的。
    # 先定义有发表评论的功能函数,然后在不改变原有函数的基础上,
    # 需要提示用户要先登录。

    """
    装饰器介绍:
    概述/作用:
    他的本质是一个闭包函数,目的:就是在不改变原有函数的基础上,对其功能做了增强
    前提条件:
    1:有嵌套
    2:有引用
    3:有返回
    4:有额外功能
    装饰器的用法:
    格式1:传统写法
    装饰后的函数名=装饰器名(被装饰的原函数名)
    装饰后的函数名() !!!一般修饰前和修饰后的函数名保持一致
    格式2:语法糖 (推荐)
    在要被装饰的原函数头上,直接@装饰器名,直接调用原函数即可
    """
    # 编写装饰器
    def check_login(fn_name):
    # 1.1定义内部函数
    def fn_inner(): # 有嵌套
    # 1.2增加额外功能
    print("校验登录.....登录成功") # 有引用
    # 1.3访问原函数 , 即外部函数的引用
    fn_name()

    # 1.4返回内部函数对象(名)
    return fn_inner
    @check_login
    def comment():
    print("发表评论")
    if __name__ == '__main__':
    #1:传统写法
    # 装饰后的函数名 = 装饰器名(被装饰的原函数名)
    # 装饰后的函数名() !!!一般修饰前和修饰后的函数名保持一致
    #!!!一般修饰前和修饰后的函数名保持一致
    # # 修饰后 修饰前
    # comment = check_login(comment)
    # comment()
    #2:语法糖
    comment()

装饰器案例

  • 场景1: ==无参无返回值的原函数==

    1742097567109

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    """
    在无参无返回值的原有函数求和
    计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...。

    细节:
    1:装饰的内部函数格式要和被装饰器的原函数保持一致
    解释:
    1-1:原函数是无参无返回值的。则装饰器的内部函数也必须是无参无返回值。
    1-2:原函数是有参有返回值的,则装饰器的内部函数必须也是有参有返回值。
    """


    # 添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    # 完成一个可以有提示功能的装饰器
    # 【装饰器】
    def my_sum(fn_name):
    def fn_inner():
    print("正在努力计算中.....")
    fn_name()

    return fn_inner


    # 【原函数】在参无返回值的原有函数求和
    def get_sum():
    a = 10
    b = 20
    sum = a + b
    print(f"sum求和结果:{sum}")


    """
    在无参无返回值的原有函数求和
    计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    细节:
    1:装饰的内部函数格式要和被装饰器的原函数保持一致
    解释:
    1-1:原函数是无参无返回值的。则装饰器的内部函数也必须是无参无返回值。
    1-2:原函数是有参有返回值的,则装饰器的内部函数必须也是有参有返回值。
    """


    # 添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    # 完成一个可以有提示功能的装饰器
    # 【装饰器】
    def my_sum(fn_name):
    def fn_inner(): # 有嵌套
    print("正在努力计算中.....") # 有额外功能
    fn_name() # 有引用

    return fn_inner # 有返回值


    # 【原函数】在参无返回值的原有函数求和
    @my_sum
    def get_sum():
    a = 10
    b = 20
    sum = a + b
    print(f"sum求和结果:{sum}")


    if __name__ == '__main__':
    # get_sum = my_sum(get_sum)
    # get_sum()

    get_sum()

  • 场景2: ==有参无返回值的原函数==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    # 在有参无返回值的原有函数求和计算结果之前,
    # 添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    # 【装饰器】
    def my_sum(fn_name):
    def fn_inner(x, y): # 有嵌套
    print("正在努力计算中....") # 有增强
    fn_name(x,y) # 有引用
    return fn_inner # 有返回
    # 【原函数】
    # @my_sum
    def get_sum(a, b):
    sum = a + b
    print(f"sum求和结果:{sum}")

    if __name__ == '__main__':
    # get_sum(10,20)
    get_sum=my_sum(get_sum)
    get_sum(10,20)
  • 场景3:==无参有返回值装饰器==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    """
    在无参有返回值的原有函数求和计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    在有参有返回值的原有函数求和计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    """


    # 在无参有返回值的原有函数求和计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...。
    # 【装饰器】 有嵌套、 有引用 、有返回值、有增加功能
    def my_sum(fn_name):
    def fn_inner():
    print("正在努力计算中...。")
    return fn_name() # 有引用

    return fn_inner
    # 【原函数】
    # @my_sum
    def get_sum(): # 无参有返回值
    a = 10
    b = 20
    return a + b
    # 两种写法
    # 传统写法
    get_sum=my_sum(get_sum)
    print(get_sum())




    # 语法糖
    # print(get_sum())
    # gs = get_sum()
    # print(gs)
  • 场景4:==有参有返回值装饰器==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 在有参有返回值的原有函数求和计算结果之前,
    # 添加一个友好提示(注意:不能改变源码):正在努力计算中...。

    # 【装饰器】
    def my_sum(fn_name):
    def fn_inner(x,y):
    print("正在努力计算中...。")
    return fn_name(x,y) #有返回值,有引用
    return fn_inner


    @my_sum
    # 【原函数:有参、有返回值】
    def get_sum(a, b):
    return a + b


    print(get_sum(20, 20))

    场景5:==不定长参数装饰器==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    # 定义一个可以计算多个数据和多个字典value值之和的函数,并调用。
    # 在原有函数的计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...。

    # 【2.装饰器】
    def my_sum(fn_name):
    def fn_inner(*args,**kwargs):
    print("正在努力计算中...。")
    return fn_name(*args,**kwargs)
    return fn_inner



    # 【1.原函数】
    #取结果之和
    # @my_sum
    def get_sum(*args,**kwargs):
    # args 数据元组
    # **kwargs 字典
    # 定义求和计数器
    sum= 0
    #遍历获取元组中的值
    for i in args:
    sum+=i

    for v in kwargs.values():
    sum+=v
    return sum
    # return sum(args)+sum(kwargs.values())

    if __name__ == '__main__':
    get_sum=my_sum(get_sum)
    # get_sum()
    print(get_sum(1, 2, 3, a=4, b=5, c=6)

    场景6:==多个装饰器装饰一个函数==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    """
    例如,发表评论前,都是需要 先登录用户 再进行 验证码验证。
    先定义有发表评论的功能函数,然后在不改变原有函数的基础上,需要先检查用户登录和输入验证码。

    记忆: 多个装饰器装饰一个原函数,就按照 由内向外的顺序来装饰
    但是你要用装饰器写法来做的话,看到的效果是从上往下执行
    """


    # 【装饰器check_login】
    def check_login(fn_name):
    def fn_inner():
    print("校验登录")
    fn_name()

    return fn_inner


    # 【装饰器check_code】
    def check_code(fn_name):
    def fn_inner():
    print("校验验证码")
    fn_name()

    return fn_inner


    # 【原函数:comment】
    def comment():
    print("发表评论")

    # 【测试】
    # 传统方法

    # A
    comment = check_code(comment)
    comment=check_login(comment)
    comment()

    # B
    # comment=check_login(comment)
    # comment = check_code(comment)
    # comment()

    # comment()

    场景7:==一个装饰器装饰多个函数==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    """
    定义一个既能装饰减法运算,又能装饰加法运算的装饰器,即带有参数的装饰器。

    记忆:
    1:1个装饰器的参数有且只能有1个
    2:如果装饰器有多个参数,可以在该装饰器外面在包裹一层装饰器,把该装饰器当做内部函数即可
    """
    # 【装饰器】
    def my_sum_sub(fn_name):
    def fn_inner(a,b):
    print("正在努力计算中.....")
    return fn_name(a,b)
    return fn_inner
    # 【原函数】
    @my_sum_sub
    def get_sum(a, b):
    return a + b
    @my_sum_sub
    def get_sub(a, b):
    return a - b

    if __name__ == '__main__':
    print(get_sum(10,20))
    print(get_sub(10, 20))

    场景8:==一个装饰器装饰多个函数嵌套版==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    # 【装饰器】
    def logging(flag):
    # 定义内部函数 ,格式要和原函数保持一致 参数和返回值
    def my_sum_sub(fn_name):
    def fn_inner(a, b):
    if flag == "+":
    print("正在努力计算【加法】中")
    elif flag == "-":
    print("正在努力计算【减法】中")
    return fn_name(a, b)

    return fn_inner

    return my_sum_sub


    # 【原函数】
    # @logging('+')
    def get_sum(a, b):
    return a + b


    # @logging('-')
    def get_sub(a, b):
    return a - b
    #
    #
    # # __name___
    # sub_str = logging("+")
    # get_sum_sub = sub_str(get_sub)
    # print(get_sum_sub(10, 5))

    场景9:==一个装饰器装饰多个函数魔法方法==

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    # 【装饰器】
    def my_sum_sub(fn_name):
    def fn_inner(a, b):
    if fn_name.__name__ == "get_sum":
    print("正在努力计算【加法】中")
    elif fn_name.__name__ == "get_sub":
    print("正在努力计算【减法】中")
    return fn_name(a, b)
    return fn_inner
    # 【原始】
    @my_sum_sub
    def get_sum(a, b):
    return a + b
    @my_sum_sub
    def get_sub(a, b):
    return a - b
    if __name__ == '__main__':
    print(get_sum(10, 20))
    print(get_sub(30,60))