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

Python小白学习教程从入门到入坑------第二十课 闭包修饰器(语法基础)

一、递归函数

1.1 基本信息

递归函数是指一个函数在其定义中直接或间接地调用了自身

递归在解决许多问题(如树的遍历、图的搜索、数学中的分治算法等)时非常有用

在Python中,递归函数可以通过简单的语法来实现

然而,使用递归时需要小心,以避免导致无限递归(栈溢出)或性能低下的问题

1.2 递归函数使用条件

1、明确的结束条件
2、每进行更深一层的递归时,问题规模相比上次递归都要有所减少
3、相邻两次重复之间有紧密的联系

eg1:分别用普通函数和递归函数来实现计算1-100累加和

普通函数:

def add():s = 0for i in range(1,101):s += iprint(s)
add ()
# 输出结果:5050

递归函数:

def add2(n):   # 要累加到第n项# 如果是1,就返回1  ---明确的结束条件if n == 1:return 1# 如果不是1,重复执行累加并返回结果return n + add2(n-1)
print(add2(100))
# 输出结果:5050

eg2:斐波那契数列(1,1,2,3,5,8,13...)

规律:从第三项开始,每一项都等于前两项之和,即 n = (n-2)+ (n-1)

n:当前项         n-1:前一项       n-2:前两项

def funa(n):    # n代表第n项if n <= 1:return nreturn funa(n-2)+funa(n-1)
print(funa(5))
# 输出结果:5

1.3 递归函数的优缺点

优点:简洁、逻辑清晰、解题更具有思路

缺点:使用递归函数时,需要反复调用函数,耗内存,运行效率低(用循环容易解决的问题,首选循环)

二、闭包

2.1 含义&使用条件

含义:在嵌套函数的前提下,内部函数使用了外部函数的变量,而且外部函数返回了内部函数,我们就把使用了外部函数变量的内部函数称为闭包

在Python中,闭包(Closure)是指一个函数对象,它记住了其创建时的环境(即外部作用域中的变量)。即使这个函数对象被传递到其他地方调用,它仍然可以访问这些外部变量。闭包的一个常见用途是创建带有私有变量的函数工厂或数据封装

使用前提条件:

1、嵌套函数:闭包通常涉及嵌套函数,即在一个函数内部定义另一个函数

2、非局部变量:内部函数可以访问外部函数的局部变量(这些变量在外部函数返回后通常会被销毁,但由于闭包的存在,它们被保留了下来)

3、返回内部函数:外部函数返回内部函数对象,这个返回的函数对象就是闭包

eg1:

def outer():      # 外层函数n = 10        # 外层函数的局部变量def inner():  # 内层函数print(n)  # 内层函数使用外层函数的局部变量# 外层函数的返回值是内层函数的函数名return inner
# print(outer()) # 返回的是内部函数的内存地址# 第一种调用写法
outer()()   # 输出结果:10# 第二种调用写法
ot = outer()  # 调用外函数
ot()          # 调用内函数
# 输出结果:10

eg2:

def outer(m):       # 外函数,m是形参,也是外函数的局部变量n = 10def inner():    # 内函数print("计算结果:",m+n)return inner    # 返回函数名,而不是inner(),因为inner函数里面参数比较多时或者说受限制时,写法不太规范
ot = outer(20)      # 调用外函数
ot()                # 调用内函数
# 输出结果:计算结果: 30

2.2 函数引用

eg1:

def funa():print(123)
print(funa)    # 输出内容:<function funa at 0x00000265916D6948>: 函数名里面保存了函数所在位置的引用
# id():判断两个变量是否是同一个值的引用
a = 1   # a只不过是一个变量名,存的是1这个数值所在的地址,就是a里面存了数值1的引用
print(a)   # 1
print(id(a))  # 输出内容:140720708025408
a = 2    # 修改a,生成了新的值,重新赋值给变量a
print(id(a))  # 输出内容:140720708025440

eg2:

def test1():    # test1也只不过是一个函数名,里面存了这个函数所在位置的引用print("这是test函数")
test1()
print(test1)  # 内存地址(引用)
te = test1
te()  # 通过引用调用函数

每次开启内函数都在使用同一份闭包变量:

eg:

def outer(m):print("outer()函数中的值:",m)def inner(n):print("inner()函数中的值:",n)return m+n #在inner函数中返回mtn的值return inner
ot=outer(10)#调用外的数,给outer()传值
# print(ot)
# 第一次调用内函数,给inner()函数传值
print(ot(20))     # 调用内函数,给inner()传值   10+20
# 输出结果:
# outer()函数中的值: 10
# inner()函数中的值: 20
# 30
# 第二次调用内函数
print(ot(40))    # 10+40
# 第三次调用内函数
print(ot(80))    # 10+80

总结:使用闭包的过程中,一旦外函数被调用一次,返回了内函数的引用,虽然每次调用内函数,会开启一个函数,执行后消亡但是闭包变量实际上只有一份,每次开启内函数都在使用同一份闭包变量

三、装饰器

3.1 装饰器基础

在 Python 中,装饰器(decorator)是一种用于修改或扩展函数或方法行为的高级功能。它们本质上是一个闭包函数,它接受一个函数作为参数,并返回一个新的函数。装饰器使用@语法糖来应用 

装饰器非常有用,特别是当你需要在不修改原有函数代码的情况下,为其添加额外的功能(如日志记录、性能计时、权限检查等)时

3.1.1 标准版装饰器

装饰器的原理就是将原有的函数名重新定义为以原函数为参数的闭包

eg:

# 被装饰的函数
def send():print("发送消息")# 装饰器函数
def outer(fn):          # 外层函数,fn是形参,但是往里面传入的是被装饰的函数名:send# 既包含原有功能,又包含新功能def inner():      # 内函数print("登录...")# 执行被装饰的函数fn()     # send()return inner
print(outer(send))  # <function outer.<locals>.inner at 0x0000024D4FE069D8>
ot = outer(send)  # 调用外函数
ot()  # 调用内函数
 3.1.2 语法糖

Python提供了一种简洁的语法糖(syntactic sugar)来定义和使用装饰器,即使用@符号

格式:@装饰器名称

eg:

def outer(fn):def inner():print("登录...")# 执行被装饰的函数fn()return inner
# 注意:装饰器名称后面不要加上(),且语法糖最好紧挨着被修饰函数
@outer
def send():print("发送消息:笑死我了")
send()@outer
def send2():print("发送消息:哈哈哈")
send2()
# 输出结果:
# 登录...
# 发送消息:笑死我了
# 登录...
# 发送消息:哈哈哈

eg:一个简单的装饰器示例,它用于计算函数的执行时间:

import time  def timing_decorator(func):  def wrapper(*args, **kwargs):  start_time = time.time()  result = func(*args, **kwargs)  end_time = time.time()  elapsed_time = end_time - start_time  print(f"Function {func.__name__} executed in {elapsed_time:.4f} seconds")  return result  return wrapper  @timing_decorator  
def some_function(seconds):  print(f"Sleeping for {seconds} seconds...")  time.sleep(seconds)  print("Done sleeping!")  # 使用装饰器  
some_function(2)

在这个例子中:

timing_decorator 是一个装饰器函数,它接受一个函数 func 作为参数

wrapper 是装饰器内部定义的函数,它包裹了 func,并添加了计时功能 

*args 和 **kwargs 允许 wrapper 函数接受任意数量和类型的参数,并将它们传递给 func

在 wrapper 函数中,我们首先记录开始时间,然后调用 func 并保存其结果

接着,我们记录结束时间,计算并打印函数执行的时间

最后,wrapper 函数返回 func 的结果

通过使用 @timing_decorator 语法,我们轻松地将 timing_decorator 应用于 some_function,无需修改 some_function 的代码

3.2 带有参数的装饰器

装饰器本身也可以接受参数

eg1:标准版带参

def outer(fn):    # 外层函数,fn是形参,但是往里面传入的是被装饰的函数名:funcdef inner(name):  # 内函数,name是内函数的参数print(f"{name}是inner函数中的参数")print("哈哈哈哈")fn(name)return inner
def func(name):print("这是被修饰的函数")ot = outer(func)    # ot = inner
ot("junjun")     # 调用内函数# 输出结果:
# junjun是inner函数中的参数
# 哈哈哈哈
# 这是被修饰的函数

eg2:语法糖带参

def outer(fn):    # 外层函数,fn是形参,但是往里面传入的是被装饰的函数名:funcdef inner(name):  # 内函数,name是内函数的参数print(f"{name}是inner函数中的参数")print("哈哈哈哈")fn(name)return inner
@outer
def func(name):print("这是被修饰的函数")
func('junjun')
# 输出结果:
# junjun是inner函数中的参数
# 哈哈哈哈
# 这是被修饰的函数

为了实现这一点,可以使用嵌套函数:(被装饰函数为可变参数*args、**kwargs)

def repeat_decorator(num_times):  def decorator_func(func):  def wrapper(*args, **kwargs):  for _ in range(num_times):  result = func(*args, **kwargs)  return result  return wrapper  return decorator_func  @repeat_decorator(3)  
def greet(name):  print(f"Hello, {name}!")  # 使用装饰器  
greet("Alice")

在这个例子中,repeat_decorator 接受一个参数 num_times,并返回一个真正的装饰器函数 decorator_func。decorator_func 接受一个函数 func 并返回包裹 func 的 wrapper 函数

3.3 多个装饰器

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

eg:@deco1在前,@deco2在后

# 第一个装饰器
def deco1(fn):def inner():return "哈哈哈"+fn()+"呵呵呵"return inner
# 第二个装饰器
def deco2(fn):def inner():return "奈斯"+fn()+"非常优秀"return inner# 被装饰的函数
@deco1
@deco2
def test1():return "晚上在学习Python基础"
print(test1())
# 输出结果:哈哈哈奈斯晚上在学习Python基础非常优秀呵呵呵
# 多个装饰器的装饰过程,离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程

 @deco2在前,@deco1在后

# 第一个装饰器
def deco1(fn):def inner():return "哈哈哈"+fn()+"呵呵呵"return inner
# 第二个装饰器
def deco2(fn):def inner():return "奈斯"+fn()+"非常优秀"return inner# 被装饰的函数
@deco2
@deco1
def test1():return "晚上在学习Python基础"
print(test1())
# 输出结果:奈斯哈哈哈晚上在学习Python基础呵呵呵非常优秀
# 多个装饰器的装饰过程,离函数最近的装饰器先装饰,然后外面的装饰器再进行装饰,由内到外的装饰过程

3.4 保留函数元数据 

在装饰器内部定义的 wrapper 函数通常会覆盖被装饰函数的元数据(如 __name__ 和 __doc__)

为了保留这些元数据,可以使用 functools.wraps 装饰器:

eg:

from functools import wraps  def my_decorator(func):  @wraps(func)  def wrapper(*args, **kwargs):  print(f"Calling {func.__name__}")  result = func(*args, **kwargs)  print(f"{func.__name__} returned {result}")  return result  return wrapper  @my_decorator  
def add(a, b):  """Return the sum of a and b."""  return a + b  print(add.__name__)  # 输出: add  
print(add.__doc__)   # 输出: Return the sum of a and b.

functools.wraps 装饰器确保了 wrapper 函数保留了 func 的名称和文档字符串等元数据

今天的分享就到这里了,希望能帮助到大家~

相关文章:

Python小白学习教程从入门到入坑------第二十课 闭包修饰器(语法基础)

一、递归函数 1.1 基本信息 递归函数是指一个函数在其定义中直接或间接地调用了自身 递归在解决许多问题&#xff08;如树的遍历、图的搜索、数学中的分治算法等&#xff09;时非常有用 在Python中&#xff0c;递归函数可以通过简单的语法来实现 然而&#xff0c;使用递归…...

Vue+element-ui实现网页右侧快捷导航栏 Vue实现全局右侧快捷菜单功能组件

Vue+element-ui实现网页右侧快捷导航栏 Vue实现全局右侧快捷菜单功能组件 可视区域没超过当前屏幕高度时候只显示三个菜单效果 可视区域超过当前屏幕高度时,显示可回到顶部菜单的,当然这个菜单显示条件可以自定义,根据需求设置 然后将这个整体功能创建为一个全局组件 代…...

如何配置,npm install 是从本地安装依赖

在 Node.js 中&#xff0c;要使npm install从本地安装依赖&#xff0c;可以按照以下步骤进行配置&#xff1a; 一、准备本地依赖包 确保你有本地的依赖包。这个依赖包可以是一个包含package.json文件的文件夹&#xff0c;或者是一个已经打包好的.tgz文件。 二、使用相对路径…...

Python画图3个小案例之“一起看流星雨”、“爱心跳动”、“烟花绚丽”

源码如下&#xff1a; import turtle # 导入turtle库&#xff0c;用于图形绘制 import random # 导入random库&#xff0c;生成随机数 import math # 导入math库&#xff0c;进行数学计算turtle.setup(1.0, 1.0) # 设置窗口大小为屏幕大小 turtle.title("流星雨动画&…...

Knife4j配置 ▎使用 ▎教程 ▎实例

knife4j简介 支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术。 提供 Web 页面在线测试 API:光有文档还不够,Swagger 生成的文档还支持在线测试.参数和格式都…...

电子电气架构 --- 车载芯片现状

我是穿拖鞋的汉子&#xff0c;魔都中坚持长期主义的汽车电子工程师。 老规矩&#xff0c;分享一段喜欢的文字&#xff0c;避免自己成为高知识低文化的工程师&#xff1a; 所有人的看法和评价都是暂时的&#xff0c;只有自己的经历是伴随一生的&#xff0c;几乎所有的担忧和畏惧…...

Unity 二次元三渲二

三渲二 注意&#xff1a;Unity必须是2022.3LTS及以上和URP项目&#xff01;&#xff01;&#xff01; 下载三渲二插件 【如何将原神的角色导入Unity】全网最细致教程&#xff0c;全程干货。不使用任何收费插件&#xff0c;使用Spring Bone对头发和衣服进行物理模拟。_原神 步…...

echart实现地图数据可视化

文章目录 [TOC](文章目录) 前言一、基本地图展示2.数据可视化 总结 前言 最近工作安排使用echarts来制作图形报表&#xff0c;记录一下我的步骤&#xff0c;需求呈现一个地图&#xff0c;地图显示标签&#xff0c;根据业务指标值给地图不同省市填充不同颜色&#xff0c;鼠标放…...

网关三问:为什么微服务需要网关?什么是微服务网关?网关怎么选型?

文章整体介绍 本文旨在解答关于微服务网关的三个核心问题&#xff1a; 1&#xff09;为什么需要网关&#xff1f;也即在何种场景下应采用微服务网关以优化系统架构&#xff1b; 2&#xff09;什么是微服务网关&#xff1f;主要讲构成微服务网关的关键能力&#xff0c;包括但…...

Mybatis-plus解决兼容oracle批量插入

本博客借鉴网上很多大佬的答案&#xff0c;东拼西凑&#xff0c;最终在项目中完成批量插入&#xff0c;仅供参考~~~ 1. 自定义SQL注入器 新建一个名为EasySqlInjector的类&#xff0c;继承DefaultSqlInjector。 public class EasySqlInjector extends DefaultSqlInjector {O…...

Kaggle竞赛——灾难推文分类(Disaster Tweets)

目录 1. 准备工作2. 资源导入3. 数据处理4. 绘制词云图5. 数据可视化5.1 词数和字符数可视化5.2 元特征可视化5.3 类别可视化 6. 词元分析6.1 一元语法统计6.2 多元语法统计 7. 命名实体识别8. 推文主题提取9. 构建模型9.1 数据划分与封装9.2 模型训练与验证 10. 模型评估11. 测…...

SC2601音频编解码器可pin to pin兼容ES8311

SC2601 是一款低功耗单声道音频编解码器&#xff0c;具有全差分输出&#xff0c;支持在全差分配置下可编程模拟输入。可pin to pin兼容ES8311。 录音路径包含一个全差分输入&#xff0c;低噪声可编程增益放大器和自动增益控制&#xff08;ALC&#xff09;。在录音过程中,通过内…...

通用AT指令

1、查询SIM卡状态 ATCPIN?2、查询信号强度 ATCSQ //99,99 表示无信号3、查询IMEI ATCGSN4、查询4G/5G模式 ATCOPS? //7表示在4G模式&#xff0c;13表示在5G模式5、设置接入点 ATCGDCONT1,"IP","uninet" //联通 ATCGDCONT1,"IP","…...

二进制狼群算法

本文所涉及所有资源均在 传知代码平台 可获取。 目录 一、背景及意义介绍 背景 意义...

STL——list的介绍和使用

前言 本篇博客我们继续来介绍STL的内容&#xff0c;这次我们要介绍的是list这个容器&#xff0c;可以简单地理解为顺序表&#xff0c;当然和我们之前学过顺序表还是有区别的&#xff0c;具体内容大家可以继续往下阅读&#xff0c;下面进入正文。 1. list简介 1.list是一种可…...

二百七十六、ClickHouse——Hive和ClickHouse非常不同的DWS指标数据SQL语句

一、目的 在完成数据之后对业务指标进行分析&#xff0c;Hive和ClickHouseSQL真不一样 二、部分业务指标表 2.1 统计数据流量表1天周期 2.1.1 Hive中原有代码 2.1.1.1 Hive中建表语句 --1、统计数据流量表——动态分区——1天周期 create table if not exists hurys_d…...

Elasticsearch Date类型,时间存储相关说明

本文介绍了在SpringBoot中处理Elasticsearch中日期时间格式的问题。当时间输出为UTC格式并存在时区差异时&#xff0c;可通过设置字段格式如yyyy-MM-dd HH:mm:ss并指定时区为GMT8来解决。存储Date类型数据时&#xff0c;可以使用JSON库如json-lib, fastjson, Jackson或gson进行…...

mathorcup2024台风 我all in ai

三个问题&#xff0c;力大砖飞。 不建物理模型&#xff0c;直接all in好吧 第一个故意无监督 第二个LSTMCNN注意力&#xff0c;刚好时间空间 第三个在第二个上加了个transfomer &#xff0c;然后LSTM变双向&#xff0c;增加层数&#xff08;基线模型选的经验公式&#xff0c;少…...

android 10 后台启动activity

摘要&#xff1a;Android 10&#xff08;API 级别 29&#xff09;及更高版本会限制应用何时可以启动 activity 背景。这些限制有助于最大限度地减少对用户的干扰&#xff0c; 让用户能够更好地控制其屏幕上显示的内容。本文以此为出发点&#xff0c;基于展锐平台对系统代码进行…...

文案创作新思路:Python与文心一言API的完美结合

在这个信息爆炸的时代&#xff0c;内容创作似乎成了一项需要魔法才能完成的任务。不过&#xff0c;别担心&#xff01;今天&#xff0c;我们将向你介绍一种新的“魔法”工具——百度文心一言 API。这款大语言模型不仅能与人对话互动&#xff0c;还能高效便捷地协助你获取创意灵…...

MMaDA: Multimodal Large Diffusion Language Models

CODE &#xff1a; https://github.com/Gen-Verse/MMaDA Abstract 我们介绍了一种新型的多模态扩散基础模型MMaDA&#xff0c;它被设计用于在文本推理、多模态理解和文本到图像生成等不同领域实现卓越的性能。该方法的特点是三个关键创新:(i) MMaDA采用统一的扩散架构&#xf…...

五年级数学知识边界总结思考-下册

目录 一、背景二、过程1.观察物体小学五年级下册“观察物体”知识点详解&#xff1a;由来、作用与意义**一、知识点核心内容****二、知识点的由来&#xff1a;从生活实践到数学抽象****三、知识的作用&#xff1a;解决实际问题的工具****四、学习的意义&#xff1a;培养核心素养…...

虚拟电厂发展三大趋势:市场化、技术主导、车网互联

市场化&#xff1a;从政策驱动到多元盈利 政策全面赋能 2025年4月&#xff0c;国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》&#xff0c;首次明确虚拟电厂为“独立市场主体”&#xff0c;提出硬性目标&#xff1a;2027年全国调节能力≥2000万千瓦&#xff0…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...

【Java】Ajax 技术详解

文章目录 1. Filter 过滤器1.1 Filter 概述1.2 Filter 快速入门开发步骤:1.3 Filter 执行流程1.4 Filter 拦截路径配置1.5 过滤器链2. Listener 监听器2.1 Listener 概述2.2 ServletContextListener3. Ajax 技术3.1 Ajax 概述3.2 Ajax 快速入门服务端实现:客户端实现:4. Axi…...

[10-1]I2C通信协议 江协科技学习笔记(17个知识点)

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17...

DL00871-基于深度学习YOLOv11的盲人障碍物目标检测含完整数据集

基于深度学习YOLOv11的盲人障碍物目标检测&#xff1a;开启盲人出行新纪元 在全球范围内&#xff0c;盲人及视觉障碍者的出行问题一直是社会关注的重点。尽管技术不断进步&#xff0c;许多城市的无障碍设施依然未能满足盲人出行的实际需求。尤其是在复杂的城市环境中&#xff…...

C++ 变量和基本类型

1、变量的声明和定义 1.1、变量声明规定了变量的类型和名字。定义初次之外&#xff0c;还申请存储空间&#xff0c;也可能会为变量赋一个初始值。 如果想声明一个变量而非定义它&#xff0c;就在变量名前添加关键字extern&#xff0c;而且不要显式地初始化变量&#xff1a; e…...

2025年ESWA SCI1区TOP,自适应学习粒子群算法AEPSO+动态周期调节灰色模型,深度解析+性能实测

目录 1.摘要2.粒子群算法PSO原理3.改进策略4.结果展示5.参考文献6.代码获取7.算法辅导应用定制读者交流 1.摘要 能源数据的科学预测对于能源行业决策和国家经济发展具有重要意义&#xff0c;尤其是短期能源预测&#xff0c;其精度直接影响经济运行效率。为了更好地提高预测模型…...