当前位置: 首页 > 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;还能高效便捷地协助你获取创意灵…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

Leetcode 3577. Count the Number of Computer Unlocking Permutations

Leetcode 3577. Count the Number of Computer Unlocking Permutations 1. 解题思路2. 代码实现 题目链接&#xff1a;3577. Count the Number of Computer Unlocking Permutations 1. 解题思路 这一题其实就是一个脑筋急转弯&#xff0c;要想要能够将所有的电脑解锁&#x…...

屋顶变身“发电站” ,中天合创屋面分布式光伏发电项目顺利并网!

5月28日&#xff0c;中天合创屋面分布式光伏发电项目顺利并网发电&#xff0c;该项目位于内蒙古自治区鄂尔多斯市乌审旗&#xff0c;项目利用中天合创聚乙烯、聚丙烯仓库屋面作为场地建设光伏电站&#xff0c;总装机容量为9.96MWp。 项目投运后&#xff0c;每年可节约标煤3670…...

镜像里切换为普通用户

如果你登录远程虚拟机默认就是 root 用户&#xff0c;但你不希望用 root 权限运行 ns-3&#xff08;这是对的&#xff0c;ns3 工具会拒绝 root&#xff09;&#xff0c;你可以按以下方法创建一个 非 root 用户账号 并切换到它运行 ns-3。 一次性解决方案&#xff1a;创建非 roo…...

CRMEB 框架中 PHP 上传扩展开发:涵盖本地上传及阿里云 OSS、腾讯云 COS、七牛云

目前已有本地上传、阿里云OSS上传、腾讯云COS上传、七牛云上传扩展 扩展入口文件 文件目录 crmeb\services\upload\Upload.php namespace crmeb\services\upload;use crmeb\basic\BaseManager; use think\facade\Config;/*** Class Upload* package crmeb\services\upload* …...

selenium学习实战【Python爬虫】

selenium学习实战【Python爬虫】 文章目录 selenium学习实战【Python爬虫】一、声明二、学习目标三、安装依赖3.1 安装selenium库3.2 安装浏览器驱动3.2.1 查看Edge版本3.2.2 驱动安装 四、代码讲解4.1 配置浏览器4.2 加载更多4.3 寻找内容4.4 完整代码 五、报告文件爬取5.1 提…...

均衡后的SNRSINR

本文主要摘自参考文献中的前两篇&#xff0c;相关文献中经常会出现MIMO检测后的SINR不过一直没有找到相关数学推到过程&#xff0c;其中文献[1]中给出了相关原理在此仅做记录。 1. 系统模型 复信道模型 n t n_t nt​ 根发送天线&#xff0c; n r n_r nr​ 根接收天线的 MIMO 系…...

让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比

在机器学习的回归分析中&#xff0c;损失函数的选择对模型性能具有决定性影响。均方误差&#xff08;MSE&#xff09;作为经典的损失函数&#xff0c;在处理干净数据时表现优异&#xff0c;但在面对包含异常值的噪声数据时&#xff0c;其对大误差的二次惩罚机制往往导致模型参数…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的

修改bug思路&#xff1a; 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑&#xff1a;async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

招商蛇口 | 执笔CID,启幕低密生活新境

作为中国城市生长的力量&#xff0c;招商蛇口以“美好生活承载者”为使命&#xff0c;深耕全球111座城市&#xff0c;以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子&#xff0c;招商蛇口始终与城市发展同频共振&#xff0c;以建筑诠释对土地与生活的…...