python语法 闭包与装饰器

1.函数名-作为对象传递

  • 概述:

    • 1.python是一门以面向对象为基础的语言,一切皆为对象,函数名也是对象.

    • 2.直接打印函数名,打印的是函数的地址.函数名()在调用函数

    • 3.函数名可以作为对象使用,可以像变量一样被赋值,且赋值后的变量名()和调用函数一样.

#1.定义函数
def func01():
    print('Hello World')
#在main中测试 
if __name__ =='__main__':
    #2.直接打印函数名,打印的是函数的地址.   说明函数名 = 对象
	print(func01)
    
    #3.写函数名()在调用函数.
    func01()		#Hello World
	#4.给函数赋值
    f = func01
    print(f)		#地址值
    f()				#Hello World
    

2.函数名-作为实参传递

  • 回顾:
    Python是一门以面向对象为基础的语言, 所以: 一切皆对象.
    函数名 也是 对象, 代表着函数的入口.

  • 函数名 的作用如下:
    ​ 1.函数名可以作为对象,像变量那样赋值.
    2. 函数名可以作为实参传递.

需求: 定义1个无参函数method(), 定义1个带1个参数的函数func(), 把method()的函数名作为参数传递给func(), 并观察结果.

#1. 定义1个无参函数method()
def method():
	print('好好学习,天天向上!')
#2.定义1个带1个参数的函数func()
def func(fn_name):
    fn_name()
if __name__ =='__main__':
    func(method)		#结果为 好好学习,天天向上!

3.闭包入门

  • 概述:属于python独有的一种写法,可以实现:对外部函数的局部变量进行’临时的存储’.

  • 回顾:局部变量随着函数的调用而存在,当函数执行完后内部的变量也会消失.

  • 作用:可以延长函数内,局部变量的生命周期.

  • 构成条件:
    1.有嵌套. 外部函数内要嵌套内部函数.
    2.有引用. 在内部函数中要使用外部函数的变量.
    ​3.有返回. 在外部函数中要返回内部函数名,即:内部函数对象.

  • 格式:

  • def 外部函数名(形参列表):
    ​ …

    • def 内部函数名(形参列表): #有嵌套
      ​ …
      ​ 使用外部函数变量 #有引用
    • return 内部函数名 #有返回
# 需求2: 定义1个用于求和的闭包, 外部函数有num1参数, 内部函数有num2参数, 然后调用, 求两数之和, 观察结果.
def fn_outer(num1):		#外部函数
    def fn_inner(num2):	#内部函数
        #具体求和动作
        sum = num1 + num2 	#有引用, 内部使用外部变量
        #打印求和结果
        print(f'求和结果为:{sum}')
     return fn_inner	#有返回
#main中测试
if __name__ =="__main__":
    num = fn_outer(10)
    num(1)		#11
    num(1)   	#11

3.1 nonlocal关键字介绍

  • 概述:
    nonlocal 可以用来修改外部函数中的变量值.

用法:类似于 global 关键字.

#定义函数,实现内部函数访问外部函数的变量值
def fn_out():
	a = 100
	#定义内部函数
    def fn_inner():
        #在内部函数中修改外部函数的值
        nonlocal a
        a = a + 1
        #访问外部函数变量
        print(f'a:{a}')		#有引用
    return fn_inner
#main测试
if __name__ =='__main__':
    fn = fn_outer()
	fn()	#101
    fn()	#102
        

4.装饰器

  • 概述:装饰器 是闭包的一种形式(写法),即:装饰器 = 闭包 + 额外功能

  • 作用:在不改变原有函数的基础上,对其功能做增强.

  • 要求:

      1. 有嵌套
      1. 有引用
      1. 有返回值
      1. 有额外功能
  • 格式

  • def 外部函数名(形参列表):
    ​ …

    • def 内部函数名(形参列表): #有嵌套
      ​ 功能扩展 #有额外功能
      ​ 使用外部函数中的函数变量 #有引用
    • return 内部函数名 #有返回
  • 装饰器用法

    • 方式1: 传统用法
      ​ 变量名 = 装饰器名(被装饰的函数名)
      ​ 变量名()
    • 方式2: 语法糖,@标记符实现
      ​ 在被装饰的函数上,写:@装饰器名,和普通函数一样直接调用.
# 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()

4.1装饰无参无返回值的函数

装饰器的内置函数格式要与被装饰函数格式保持一致.

# 1. 装饰器.
def print_info(fn_name):    # fn_name: 要被装饰的函数名(原函数名)
    def fn_inner():         # 有嵌套.  装饰器的内部函数 格式 要和 原函数 格式保持一致.
        print('[友好提示] 正在努力计算中...')  # 有额外功能
        fn_name()                          # 有引用
    return fn_inner         # 有返回


# 2. 要被装饰的函数, 即: 原函数(这里是: 无参无返回值的)
@print_info
def get_sum():
    a = 10
    b = 20
    # 求和
    sum = a + b
    # 打印结果.
    print(f'sum: {sum}')

# 在main函数中测试调用.
if __name__ == '__main__':
    # 装饰器 写法1: 传统写法.
    # get_sum = print_info(get_sum)
    # get_sum()

    # 装饰器 写法2: 语法糖
    get_sum()

4.2装饰有参无返回值

装饰器的内置函数格式要与被装饰函数格式保持一致.

# 1. 装饰器.
def print_info(fn_name):    # fn_name: 要被装饰的函数名(原函数名)
    def fn_inner(a, b):         # 有嵌套.  装饰器的内部函数 格式 要和 原函数 格式保持一致.
        print('[友好提示] 正在努力计算中...')  # 有额外功能
        fn_name(a, b)                      # 有引用
    return fn_inner         # 有返回


# 2. 要被装饰的函数, 即: 原函数(这里是: 有参无返回值的)
@print_info
def get_sum(a, b):
    # 求和
    sum = a + b
    # 打印结果.
    print(f'sum: {sum}')

# 在main函数中测试调用.
if __name__ == '__main__':
    # 装饰器 写法1: 传统写法.
    # get_sum = print_info(get_sum)
    # get_sum(100, 200)

    # 装饰器 写法2: 语法糖
    get_sum(10, 3)

4.3装饰无参有返回值

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.

# 1. 装饰器.
def print_info(fn_name):  # fn_name: 要被装饰的函数名(原函数名)
    def fn_inner():  # 有嵌套.  装饰器的内部函数 格式 要和 原函数 格式保持一致.
        print('[友好提示] 正在努力计算中...')  # 有额外功能
        return fn_name()  # 有引用

    return fn_inner  # 有返回


# 2. 要被装饰的函数, 即: 原函数(这里是: 无参有返回值的)
@print_info
def get_sum():
    a, b = 10, 3
    # 求和
    sum = a + b
    # 返回结果.
    return sum


# 在main函数中测试调用.
if __name__ == '__main__':
    # 装饰器 写法1: 传统写法.
    # get_sum = print_info(get_sum)
    # sum1 = get_sum()
    # print(f'sum1: {sum1}')

    # 装饰器 写法2: 语法糖
    sum2 = get_sum()
    print(f'sum2: {sum2}')

4.4装饰有参有返回值

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.

# 1. 装饰器.
def print_info(fn_name):  # fn_name: 要被装饰的函数名(原函数名)
    def fn_inner(a, b):  # 有嵌套.  装饰器的内部函数 格式 要和 原函数 格式保持一致.
        print('[友好提示] 正在努力计算中...')  # 有额外功能
        return fn_name(a, b)  # 有引用

    return fn_inner  # 有返回


# 2. 要被装饰的函数, 即: 原函数(这里是: 有参有返回值的)
@print_info
def get_sum(a, b):
    # 求和
    sum = a + b
    # 返回结果.
    return sum


# 在main函数中测试调用.
if __name__ == '__main__':
    # 装饰器 写法1: 传统写法.
    # get_sum = print_info(get_sum)
    # sum1 = get_sum(10, 20)
    # print(f'sum1: {sum1}')

    # 装饰器 写法2: 语法糖
    sum2 = get_sum(11, 22)
    print(f'sum2: {sum2}')

4.3装饰器-装饰不定长参数

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.

# 1. 定义装饰器.
def print_info(fn_name):
    def fn_inner(*args, **kwargs):          # 有嵌套
        print('[友好提示]正在努力计算中...')    # 有额外功能.
        return fn_name(*args, **kwargs)     # 有引用
    return fn_inner                         # 有返回


# 2. 定义原函数, 表示具体的累加动作.
# @print_info
def get_sum(*args, **kwargs):  # (1, 2, 3, 4, 5),  {'a':1, 'b':2, 'c':3}
    # 2.1 定义求和变量, 记录求和结果.
    sum = 0

    # 2.2 回顾: *args, 接收所有的 位置参数, 封装成 元组, 即: (1, 2, 3)
    # 所以这里 等于 元组求和.
    for value in args:
        sum += value

    # 2.3 回顾: **kwargs, 接收所有的 键值对参数, 封装成 字典, 即: {'a':1, 'b':2, 'c':3}
    # 所以这里 等于 字典value值求和.
    for value in kwargs.values():
        sum += value

    # 2.4 返回求和计算结果.
    return sum


# 3. 在main函数中测试.
if __name__ == '__main__':
    # 4. 直接: 调用 get_sum()函数
    #                    位置参数       关键字参数
    # sum = get_sum(11, 22, 33, a=1, b=2, c=3)
    # print(f'求和结果: {sum}')

    # 5. 装饰器, 写法1: 传统方式.
    get_sum = print_info(get_sum)
    sum = get_sum(11, 22, 33, a=1, b=2, c=3)
    print(f'求和结果: {sum}')

    # 6. 装饰器, 写法2: 语法糖.
    # sum = get_sum(11, 22, 33, a=1, b=2, c=3)
    # print(f'求和结果: {sum}')

4.4多个装饰器装饰一个函数

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.

# 需求: 发表评论前, 需要先登录, 再进行验证码校验.

# 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()

4.5 带参数的装饰器

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.
# 需求: 定义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()

4.6 带参数装饰器-优化版

装饰器的内置函数 格式要和 被装饰的函数 格式保持一致.
案例:
演示 带有参数的装饰器, 即: 一个装饰器 装饰多个 原函数.

  • 结论:
    1. 一个装饰器的参数只能有1个.
    2. 如果装饰器有多个参数, 则可以在该装饰器的外边再定义1个函数, 用于封装多个参数, 并返回一个装饰器.
扩展:
    Python中的每个函数(对象)都有一个属性 __name__, 可以获取该函数的 名字.
"""


# 需求: 定义1个既能装饰加法运算, 也能装饰减法运算的装饰器, 即: 带有参数的装饰器, 并测试.

# 1. 定义装饰器, 能装饰 加法, 减法运算.
def decorator(fn_name):
    def fn_inner():         # 有嵌套
        # fn_name = 函数名 = 函数对象.
        # print(fn_name)      # 地址值, 说明 fn_name = 函数对象
        # print(fn_name.__name__) # 根据函数对象, 获取该函数的名字.

        if fn_name.__name__ == 'add':
            print('[友好提示] 正在努力计算 加法 中...')  # 有额外功能
        elif fn_name.__name__ == 'subtract':
            print('[友好提示] 正在努力计算 减法 中...')  # 有额外功能
        fn_name()           # 有引用
    return fn_inner         # 有返回

# 2. 定义原函数, 表示: 加法运算.
@decorator
def add():
    a, b = 10, 3
    sum = a + b
    print(f'求和结果: {sum}')


# 3. 定义原函数, 表示: 减法运算.

@decorator
def subtract():
    a, b = 22, 11
    sub = a - b
    print(f'求差结果: {sub}')

# 在main函数中测试调用.
if __name__ == '__main__':
    # 4. 测试加法.
    add()
    print('-' * 21)

    # 5. 测试减法.
    subtract()

总结

持续更新中~~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值