闭包和装饰器

1.函数基本知识点回顾

知识点:

函数定义格式:  def 函数名(): 函数体
​
函数的注意事项: 
1:先定义再调用,
2:不调用不执行,
3:每调用一次执行一次
4:如果函数没有返回值,默认返回的是None

示例:

# 函数特点:  必须先定义再调用   如果函数没有返回值,默认返回的是None
# 定义一个函数 : def 函数名(): 函数体
def func1():
    print('我是func1函数')
    # 省略了return None
​
​
# 调用函数 : 函数名()
print(func1())  # 先调用func1(),然后打印func1的返回值
​
print('-------------------------------')
# 定义一个函数 : def 函数名(): 函数体
def func2():
    print('我是func2函数')
    return 2
​
​
# 调用函数 : 函数名()
print(func2())  # 先调用func2(),然后打印func2的返回值
​

2.函数名记录的是函数引用地址

知识点:

函数名:  记录的是当前对应函数的引用地址
​
函数名(): 调用函数,执行对应地址里函数内容

示例:

# 定义函数
def func1():
    print('我是func1函数')
    return 1
​
​
# 调用函数
print(func1())  # 结果? 先调用func1(),再打印func1()的返回值
​
print('---------------------------------------------')
# 基础班的时候错误写法?原来你们认为这是错误的,其实这是打印了func1函数的地址
# 因为函数名其实记录的就是函数的地址,所以打印函数名,结果出现地址
print(func1)  # 结果? 地址<function func1 at 0x0000013C23EF5310>
​
# 通过以上结果说明:  所有的函数名本质记录的就是当前函数的地址
​

3.函数作为参数传递

知识点:

定义带参函数:   def 函数名(形参): 函数体
​
调用带参函数:   函数名(实参)
​
函数名作为实参传递:  本质传递的是对应函数的引用地址

示例:

# 定义函数1
def func1():
    print('我是func1函数...')
​
​
# 1.测试
print(func1)  # func1记录的是func1函数的地址 <function func1 at 0x0000019D730A5310>
func1()
​
print('---------------------------------')
​
​
# 2.演示函数名作为参数传递
# 定义函数2
def func2(show):  # 形参show=func1=0x0000019D730A5310
    print(show)  # show此时记录的是传进来的func1的地址:<function func1 at 0x0000022D7E6F5310>
    show()  # show()=func1()   本质就是调用了func1函数:控制台结果是我是func1函数...
​
​
# 调用func2函数,把函数func1引用地址传递给show变量  # show=func1=0x0000019D730A5310
func2(func1)  # 实参func1
​

4.闭包作用

知识点:

闭包作用:  能够保存外部函数变量值(让外部函数变量一直不销毁),重复使用

示例:

# 定义函数
def outer():
    a = 10  # 函数运行完就销毁了
    return a
​
# 调用函数
b = outer()  # 新的变量b接收的:  b =10
print(b + 1)
print(b + 2)
print(b + 3)
print(b + 4)
print(b + 5)
# 需求:使用a变量 依次  +1=11  +2=12  +3=13   +4=14  +5=15
# 闭包作用:闭包可以解决以上问题,闭包可以不让a变量销毁,重复使用a
​

5.闭包使用

知识点:

闭包三个条件:
1:有嵌套(外部函数里嵌套内部函数)
2:有引用(内部函数使用了外部函数的变量或者形参)
3:有返回(外部函数把内部函数名返回,本质返回的是内部函数的地址)

示例:

"""
闭包条件:
1.有嵌套(外部函数套一个内部函数)
2.有引用(内部函数引用外部函数的变量或者形参)
3.有返回(外部函数把内部函数名返回)  本质返回的是地址
"""
​
​
# 定义闭包
def outer(a):  # 外部函数
    # a = 10
    def inner(b):  # 内部函数 有嵌套
        print(a + b)  # 有引用   # 由于内部函数在重复使用外部函数的a变量,所以外部函数的a变量一直没有销毁
​
    return inner  # 有返回,注意:此处一定不要多了括号!!!
​
​
# 需求依次a变量   +1=11  +2=12  +3=13   +4=14  +5=15
# 调用外部函数获取内部函数地址
# add = inner = 内部函数的地址
add = outer(10)  # 打开外面的盒子获取里面的盒子  外部函数的变量值只传1次即可
# 调用内部函数  内部函数就可以一直使用外部函数的变量
add(1)  # add(1) 本质根据内部函数的地址去调用内部函数把1传给b
add(2)  # add(2) 本质根据内部函数的地址去调用内部函数把2传给b
add(3)  # add(3) 本质根据内部函数的地址去调用内部函数把3传给b
add(4)  # add(4) 本质根据内部函数的地址去调用内部函数把4传给b
add(5)  # add(5) 本质根据内部函数的地址去调用内部函数把5传给b
​

6.拓展nonlocal关键字

知识点:

nonlocal: 能够让内部函数去修改外部函数的变量
​
global: 声明全局变量

示例:

# 需求:闭包内部函数修改外部函数的变量值
"""
闭包条件:有嵌套 有引用  有返回
"""
​
​
# 定义外部函数
def outer():
    a = 100
    # 定义内部函数
    # 拓展: 内部函数想修改外部函数的变量用nonlocal
    def inner():
        nonlocal a
        a += 1
        print(f'内部函数修改完外部函数a值后:{a}') # 修改后
​
    print(f'外部函数a值:{a}') # 优先于内部函数执行了,打印的初始值100
​
    return inner
​
​
# 使用闭包
f = outer() # 先调用外部函数,再接收内部函数地址
f() # 调用内部函数
​

7.装饰器入门

知识点:

装饰器作用: 不改变原有函数(不改变源码和不改变调用方式)的基础上,去增加额外功能
​
装饰器本质: 就是一个闭包函数
​
装饰器条件: 
1:有嵌套(外部函数里嵌套内部函数)
2:有引用(内部函数使用了外部函数的变量或者形参)
3:有返回(外部函数把内部函数名返回,本质返回的是内部函数的地址)
4:有额外功能(给需要装饰的原有函数增加了额外功能)
​
装饰器使用:
方式1: 传统方式:  装饰完的函数 = 装饰器名(原有函数)
方式2: 语法糖方式: @装饰器名

示例:

"""
装饰器功能:  不改变原有函数(不改变源码,不改变调用方式)的基础上,去增加额外功能
​
装饰器条件
1.有嵌套 2.有引用 3.有返回 4.有额外功能
"""
​
​
# 需求: 已知一个函数comment,只有发表评论功能,需要写一个装饰器去装饰下comment函数
# 增加一个额外的功能:在发表评论前先提示登录
# 3.定义一个装饰器(形参是原有函数)
def outer(fun):  # fun = comment
    def inner():  # 有嵌套
        print('请先登录')  # 有额外功能
        fun()  # 有引用,调用传进来的原有函数  fun() == comment()
​
    return inner  # 有返回
​
​
# 1.定义原有函数
# 4.2 使用装饰器语法糖方式(不好理解但使用简单点): @装饰器名
@outer
def comment():
    print('发表评论')
​
​
# 4.1使用装饰器传统方式(好理解但使用麻烦点):  装饰完的原有函数 = 装饰器名(原有函数名)
comment = outer(comment)  # 传进去原有函数,出来的是装饰完的原有函数
# 2.调用原有函数
comment()  # 使用了装饰器后,调用的其实是装饰完的内部函数
​

8.回顾函数分类和不定长参数

知识点:

回顾函数分类:
无参无返回值的函数
    定义: def 函数名(): ...
    调用: 函数名()
    
无参有返回值的函数
    定义: def 函数名(): ... return 返回值
    调用: 用变量接收返回值 = 函数名()
    
有参无返回值的函数
    定义: def 函数名(形参): ...
    调用: 函数名(实参)
    
有参有返回值的函数
    定义: def 函数名(形参): ... return 返回值
    调用: 用变量接收返回值 = 函数名(实参)
    
回顾不定长参数:
*args: 底层是元组形式
**kwargs: 底层是字典形式

9.装饰器装饰无参无返回值的函数

示例:

"""
无参无返回值的函数
    定义: def 函数名(): ...
    调用: 函数名()
"""
​
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
def outer(func):
    def inner():
        print('正在努力计算中...')
        func()  # 调用传进来的原有函数
​
    return inner
​
​
# 1.定义原有函数
@outer  # 4.语法糖方式
def get_sum():
    a = 10
    b = 20
    sum = a + b
    print(sum)
​
​
# 2.调用原有函数
get_sum()
​

10.装饰器装饰有参无返回值的函数

示例:

"""
有参无返回值的函数
    定义: def 函数名(形参): ...
    调用: 函数名(实参)
"""
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
def outer(func):
    def inner(a,b):
        print('正在努力计算中...')
        func(a,b)  # 调用传进来的原有函数   get_sum(a,b)
​
    return inner
​
​
# 1.定义原有函数
@outer  # 4.语法糖方式
def get_sum(a,b):
    sum = a + b
    print(sum)
​
​
# 2.调用原有函数
# 如果使用了装饰器,再调用的时候其实本质调用的是装饰器里内部函数
get_sum(10,20)
​

11.装饰器装饰无参有返回值的函数

示例:

"""
无参有返回值的函数
    定义: def 函数名(): ... return 返回值
    调用: 用变量接收返回值 = 函数名()
"""
​
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
def outer(func):
    def inner():
        print('正在努力计算中...')
        sum = func()  # 调用传进来的原有函数  get_sum()
        return sum
​
    return inner
​
​
# 1.定义原有函数
@outer  # 4.语法糖方式
def get_sum():
    a = 10
    b = 20
    sum = a + b
    return sum
​
​
# 2.调用原有函数(不能改变原有调用方式的)
sum = get_sum()  # 调用的是装饰完的内部函数  inner()
print(sum)
​

12.装饰器装饰有参有返回值的函数

示例:

"""
有参有返回值的函数
    定义: def 函数名(形参): ... return 返回值
    调用: 用变量接收返回值 = 函数名(实参)
"""
​
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
def outer(func):
    def inner(a,b):
        print('正在努力计算中...')
        sum = func(a,b)  # 调用传进来的原有函数  get_sum(a,b)
        return sum
​
    return inner
​
​
# 1.定义原有函数
@outer  # 4.语法糖方式
def get_sum(a,b):
    sum = a + b
    return sum
​
​
# 2.调用原有函数(不能改变原有调用方式的)
sum = get_sum(10,20)  # 调用的是装饰完的内部函数  inner(10,20)
print(sum)
sum = get_sum(30,40)  # 调用的是装饰完的内部函数  inner(30,40)
print(sum)
​

13.装饰器装饰有可变参数无返回值的函数

示例:

"""
有参无返回值的函数
    定义: def 函数名(形参): ...
    调用: 函数名(实参)
*args: 元组
**kwargs: 字典
"""
​
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
def outer(func):
    def inner(*args, **kwargs):  # args = (10,20) kwargs={'a': 30, 'b': 40}
        print('正在努力计算中...')
        func(*args, **kwargs)  # 调用传进来的原有函数   get_sum(*args, **kwargs)
​
    return inner
​
# 1.定义原有函数
@outer  # 4.语法糖方式
def get_sum(*args, **kwargs):  # args = (10,20) kwargs={'a': 30, 'b': 40}
    sum = 0
    # 遍历元组求和
    for i in args:
        sum += i
    # 遍历字典求和
    for i in kwargs.values():
        sum += i
​
    print(sum)
​
# 2.调用原有函数
# 如果使用了装饰器,再调用的时候其实本质调用的是装饰器里内部函数
get_sum(10, 20, a=30, b=40)  # 调用的内部函数  inner(*args, **kwargs)
​

14.通用装饰器

示例:

"""
有参有返回值的函数
    定义: def 函数名(形参): ...return 返回值
    调用: 变量接收返回值 = 函数名(实参)
"""
​
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
def outer(func):
    def inner(*args, **kwargs):  # args = (10,20) kwargs={'a': 30, 'b': 40}
        print('正在努力计算中...')
        sum = func(*args, **kwargs)  # 调用传进来的原有函数   get_sum(*args, **kwargs)
        return sum
    return inner
​
# 1.定义原有函数
@outer  # 4.语法糖方式
def get_sum(*args, **kwargs):  # args = (10,20) kwargs={'a': 30, 'b': 40}
    sum = 0
    # 遍历元组求和
    for i in args:
        sum += i
    # 遍历字典求和
    for i in kwargs.values():
        sum += i
​
    return sum
​
# 2.调用原有函数
# 如果使用了装饰器,再调用的时候其实本质调用的是装饰器里内部函数
sum = get_sum(10, 20, a=30, b=40)  # 调用的内部函数  inner(*args, **kwargs)
print(sum)
​

15.带参数的装饰器(了解)

示例:

"""
有参数的装饰器:
有嵌套+1
有引用
有返回+1
有额外功能+1
"""
​
​
# 需求: 在原有函数计算结果之前,加一个友好提示(不能改变源码):正在努力计算中...
# 5.编写带有参数的装饰器
def logging(flag):
    # 3.编写装饰器(有嵌套,有引用,有返回,有额外功能)
    def outer(func):
        def inner(*args, **kwargs):  # args = (10,20) kwargs={'a': 30, 'b': 40}
            if flag == '+':
                print('正在努力做加法计算中...')
            elif flag =='-':
                print('正在努力做减法运算中...')
            sum = func(*args, **kwargs)  # 调用传进来的原有函数   get_sum(*args, **kwargs)
            return sum
​
        return inner
​
    return outer
​
​
# 1.定义原有函数
@logging("+")  # 4.语法糖方式 6.修改成最外层装饰器
def get_sum(*args, **kwargs):  # args = (10,20) kwargs={'a': 30, 'b': 40}
    sum = 0
    # 遍历元组求和
    for i in args:
        sum += i
    # 遍历字典求和
    for i in kwargs.values():
        sum += i
​
    return sum
​
​
# 2.调用原有函数
# 如果使用了装饰器,再调用的时候其实本质调用的是装饰器里内部函数
sum = get_sum(10, 20, a=30, b=40)  # 调用的内部函数  inner(*args, **kwargs)
print(sum)
​
# 7.测试减法
@logging('-')
def sub(a,b):
    cha = a-b
    return cha
cha = sub(20,10)
print(cha)
​

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值