当前位置: 首页 > news >正文

python闭包与装饰器

函数参数

函数名的作用

  • 函数名存放的是函数所在内存空间的地址,即函数名代表函数入口地址
  • 函数名() 执行函数名所存放空间地址上的代码,即 函数名() 代表函数调用,直接调用
  • 函数名可以像普通变量一样赋值,函数值后的结果与原函数名作用是一样的,即函数名可以做函数参数

例:定义一个无返回值的函数func01,并直接输出函数名查看

# 定义函数
def func01():print('func01')
# 函数名() 执行函数名所存放空间地址上的代码
func01() 
# 函数名存放的是函数所在空间上的地址
print(func01) # fun01函数在内存中的地址 <function func01 at 0x000001AE86427880>print(func01()) # None func01() 是调用函数,print打印的是该函数的返回值,无返回值则为None# 函数名也可以像普通变量一样赋值
func02 = func01 # 把 func01 函数的 地址值 赋值给func02,即 func02()=func01() 
func02()

函数作为参数使用

函数名作为实参传递,本质上传递的是对应函数的地址

例:将函数作为实参来传递:

  1. 定义一个无参函数method()
  2. 定义一个有一个参数的函数func()
  3. 把无参函数method()函数名传递给有参函数func(),观察效果
def method():print('--- method函数 ---')def func(fn_name):print('--- func函数 ---')fn_name() # 执行传递进来的fn_name函数if __name__ == '__main__':print('--- 程序开始 ---')func(method) # 把method函数的内存地址传递给fn_nameprint('--- 程序结束 ---')

闭包

当调用完函数后,函数内定义的变量就销毁了,但有时候需要保存函数内的这个变量,并在这个变量的基础上完成一系列的操作

闭包语法

在函数嵌套的前提下,内部函数使用了外部函数的变量,并且外部函数返回了内部函数,像这种使用外部函数变量的内部函数称为闭包

闭包的前提条件

  1. 有嵌套:即有外部函数,有内部函数
  2. 有引用:即在内部函数中,使用外部函数的变量
  3. 有返回:即在外部函数中,返回内部函数(对象)
# 外部函数
def 外部函数名(外部参数):# 内部函数def 内部函数名(内部参数):...[使用玩不函数的变量]return 内部函数名

例:定义一个函数用于保存变量10,然后调用函数返回值变量并重复累加数值

def method():a = 10return adef outer(num1):def inner(num2):sum = num1 + num2print(f'求和结果为:{sum}')return inner # 返回inner函数的内存地址,此时inner函数没有被执行if __name__ == '__main__':print('--- 程序开始 ---')# 把outer函数的内存地址赋值给fnfn = outer(10) #fn = outer函数的返回值 = inner这个内部函数对象print(fn) # 地址值print(fn(1)) # 11print(fn(1)) # 11print(fn(1)) # 11

nolocal关键字

nolocal 用于嵌套函数中,允许内部函数修改外部函数(非全局)作用域的变量。要求变量在外层函数中已定义并赋值,且不能在内部函数中首次赋该变量值。

def outer():a = 100def inner():# nonlocal a # 声明a为外部函数的局部变量nonlocal aa += 1print(f'--- inner函数 --- a = {a}')return innerif __name__ == '__main__':print('--- 程序开始 ---')fn = outer()fn() # 101fn() # 102fn() # 103

装饰器

装饰器的作用是不改变原有函数的基础上,给原有函数增加额外功能,其本质上就是一个闭包函数

装饰器的构成条件

  1. 有嵌套:在函数嵌套(函数里面再定义函数) 的前提下
  2. 有引用:内部函数使用了外部函数的变量(还包括外部函数的参数)
  3. 有返回:外部函数返回了内部函数名
  4. 有额外功能:给需要装饰的原有函数增加了额外功能
# 1. 定义装饰器(闭包函数),用于对指定函数的功能 进行扩展
def check_login(fn_name):# 2. 定义内部函数,用于对指定的 fn_name函数 进行功能扩展def inner():print('--- 登录验证 ---')fn_name()  # 调用原函数return inner  # 返回内部函数的引用# 3. 定义函数
@check_login  # 装饰器写法2:@装饰器名
def comment():print('--- 发布评论 ---')# 4. 调用装饰器,传入被装饰的函数,返回一个新的函数对象
if __name__ == '__main__':print('--- 程序开始 ---')# 装饰器写法1:变量= 装饰器名(要被装饰的原函数名)# hg = check_login(comment)# hg()comment()  # 调用装饰器,传入被装饰的函数,返回一个新的函数对象

装饰器的使用

无参无返回值的函数

# 在无参无返回值的原有函数求和计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...def print_info(fn):def inner():print('正在努力计算中...')fn()return inner@print_info
def sum_num():a = 10b = 20result = a + bprint(f'计算结果是:{result}')if __name__ == '__main__':sum_num()

有参无返回值的函数

# 在有参无返回值的原有函数求和计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...def print_info(fn):def inner(x,y):print('正在努力计算中...')fn(x,y)return inner@print_info
def sum(x,y):z = x + yprint(f'计算结果是:{z}')if __name__ == '__main__':sum(10,20)

无参有返回值的函数

# 在无参有返回值的原有函数求和计算结果之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...def print_info(fn):def inner():print('正在努力计算中...')result = fn()  # 调用原函数,获取结果return result  # 返回结果return inner@print_info
def sum():a = 10b = 20result = a + breturn resultif __name__ == '__main__':result = sum()  # 调用装饰器,传入被装饰的函数,返回一个新的函数对象print(f'计算结果是:{result}')

有参有返回值的函数

# 在有参有返回值的原有函数求和计算之前,添加一个友好提示(注意:不能改变源码):正在努力计算中...def print_info(fn):def inner(a, b):  print('正在努力计算中...')result = fn(a, b)  return result return inner@print_info
def sum_num(x, y):z = x + yreturn zif __name__ == '__main__':result = sum_num(10, 20)print(f'计算结果是:{result}')

通用装饰器(函数参数不定长,有返回值)

# 定义一个可以计算多个数据和多个字典value值之和的函数,并调用。在原有函数的计算结果之前,添加一个友好提示:正在努力计算中...def print_info(func):def inner(*args, **kwargs):  print("正在努力计算中...")result = func(*args, **kwargs)  return resultreturn inner# *args 元组类型
# **kwargs 字典类型
def get_sum(*args, **kwargs):result = 0for value in args:result += valuefor value in kwargs.values():result += valuereturn resultif __name__ == '__main__':result = get_sum(1, 2, 3, 4, 5, a=10, b=20, c=30)print(f"计算结果是:{result}")

多个装饰器装饰一个函数

多个装饰器的装饰过程是:离函数最近的装饰器先装饰,然后外面的装饰器在进行装饰,由内到外的装置过程

例:发表评论之前,需要先登录用户,再进行校验验证码。先定义有发哦表评论的个功能函数,然后在不改变原有函数的基础上,需要先检查用户登录和输入验证码

def check_user(fn):def inner():print('输入用户名和密码')print('检查用户名和密码')print('登录成功')fn()return innerdef check_code(fn):def inner():print('校验登录验证码')fn()return inner@check_user
@check_code
def comment():print('发表评论')
if __name__ == '__main__':comment()"""
输入用户名和密码
检查用户名和密码
登录成功
校验登录验证码
发表评论
""" 

带参数的装饰器

使用带参数的装饰器,其实是在装饰器外面又包裹了一个函数,使用该函数接收参数,返回装饰器

def logging(flag):def decorator(fn):def inner(a,b):if flag == '+':print('正在进行加法运算')elif flag == '-':print('正在进行减法运算')result = fn(a,b)return resultreturn innerreturn decorator@logging('+')
def add(a,b):result = a+breturn result@logging('-')
def sub(a,b):result = a-breturn resultif __name__ == '__main__':add_result = add(1,2)print(f"加法计算结果是:{add_result}")sub_result = sub(5,3)   print(f"减法计算结果是:{sub_result}")
http://www.lqws.cn/news/193897.html

相关文章:

  • 【大厂机试题解法笔记】区间交集
  • Linux文件系统详解:从入门到精通
  • 编译原理笔记
  • ComfyUI 文生图教程,进行第一次的图片生成
  • curl获取ip定位信息 --- libcurl-multi(三)
  • RocketMQ入门5.3.2版本(基于java、SpringBoot操作)
  • c++算法学习5——贪心算法
  • 类Transformer架构
  • 在线OJ项目测试
  • JMM初学
  • 51单片机——计分器
  • 【Go面试陷阱】对未初始化的chan进行读写为何会卡死?
  • 【汇编逆向系列】八、函数调用包含混合参数-8种参数传参,条件跳转指令,转型指令,movaps 16字节指令
  • 第J3-1周:DenseNet算法 实现乳腺癌识别
  • 消防一体化安全管控平台:构建消防“一张图”和APP统一管理
  • 【驱动】Orin NX恢复备份失败:does not match the current board you‘re flashing onto
  • 大模型如何革新用户价值、内容匹配与ROI预估
  • SQLServer中的存储过程与事务
  • 柴油发电机组接地电阻柜的作用
  • 【大模型】大模型数据训练格式
  • UFC911B108 3BHE037864R0108
  • SOC-ESP32S3部分:31-ESP-LCD控制器库
  • 2025年SDK游戏盾实战深度解析:防御T级攻击与AI反作弊的终极方案
  • 在Linux查看电脑的GPU型号
  • Nest框架: 日志功能之收集,筛选,存储,维护
  • C++ --- vector
  • [Java恶补day17] 41. 缺失的第一个正数
  • Python训练第四十六天
  • 如何选择正确的团队交互模式:协作、服务还是促进?
  • 【Linux】(1)—进程概念-⑤进程调度