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 基本信息 递归函数是指一个函数在其定义中直接或间接地调用了自身 递归在解决许多问题(如树的遍历、图的搜索、数学中的分治算法等)时非常有用 在Python中,递归函数可以通过简单的语法来实现 然而,使用递归…...
Vue+element-ui实现网页右侧快捷导航栏 Vue实现全局右侧快捷菜单功能组件
Vue+element-ui实现网页右侧快捷导航栏 Vue实现全局右侧快捷菜单功能组件 可视区域没超过当前屏幕高度时候只显示三个菜单效果 可视区域超过当前屏幕高度时,显示可回到顶部菜单的,当然这个菜单显示条件可以自定义,根据需求设置 然后将这个整体功能创建为一个全局组件 代…...
如何配置,npm install 是从本地安装依赖
在 Node.js 中,要使npm install从本地安装依赖,可以按照以下步骤进行配置: 一、准备本地依赖包 确保你有本地的依赖包。这个依赖包可以是一个包含package.json文件的文件夹,或者是一个已经打包好的.tgz文件。 二、使用相对路径…...
Python画图3个小案例之“一起看流星雨”、“爱心跳动”、“烟花绚丽”
源码如下: import turtle # 导入turtle库,用于图形绘制 import random # 导入random库,生成随机数 import math # 导入math库,进行数学计算turtle.setup(1.0, 1.0) # 设置窗口大小为屏幕大小 turtle.title("流星雨动画&…...
Knife4j配置 ▎使用 ▎教程 ▎实例
knife4j简介 支持 API 自动生成同步的在线文档:使用 Swagger 后可以直接通过代码生成文档,不再需要自己手动编写接口文档了,对程序员来说非常方便,可以节约写文档的时间去学习新技术。 提供 Web 页面在线测试 API:光有文档还不够,Swagger 生成的文档还支持在线测试.参数和格式都…...
电子电气架构 --- 车载芯片现状
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧…...
Unity 二次元三渲二
三渲二 注意:Unity必须是2022.3LTS及以上和URP项目!!! 下载三渲二插件 【如何将原神的角色导入Unity】全网最细致教程,全程干货。不使用任何收费插件,使用Spring Bone对头发和衣服进行物理模拟。_原神 步…...
echart实现地图数据可视化
文章目录 [TOC](文章目录) 前言一、基本地图展示2.数据可视化 总结 前言 最近工作安排使用echarts来制作图形报表,记录一下我的步骤,需求呈现一个地图,地图显示标签,根据业务指标值给地图不同省市填充不同颜色,鼠标放…...
网关三问:为什么微服务需要网关?什么是微服务网关?网关怎么选型?
文章整体介绍 本文旨在解答关于微服务网关的三个核心问题: 1)为什么需要网关?也即在何种场景下应采用微服务网关以优化系统架构; 2)什么是微服务网关?主要讲构成微服务网关的关键能力,包括但…...
Mybatis-plus解决兼容oracle批量插入
本博客借鉴网上很多大佬的答案,东拼西凑,最终在项目中完成批量插入,仅供参考~~~ 1. 自定义SQL注入器 新建一个名为EasySqlInjector的类,继承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 是一款低功耗单声道音频编解码器,具有全差分输出,支持在全差分配置下可编程模拟输入。可pin to pin兼容ES8311。 录音路径包含一个全差分输入,低噪声可编程增益放大器和自动增益控制(ALC)。在录音过程中,通过内…...
通用AT指令
1、查询SIM卡状态 ATCPIN?2、查询信号强度 ATCSQ //99,99 表示无信号3、查询IMEI ATCGSN4、查询4G/5G模式 ATCOPS? //7表示在4G模式,13表示在5G模式5、设置接入点 ATCGDCONT1,"IP","uninet" //联通 ATCGDCONT1,"IP","…...
二进制狼群算法
本文所涉及所有资源均在 传知代码平台 可获取。 目录 一、背景及意义介绍 背景 意义...
STL——list的介绍和使用
前言 本篇博客我们继续来介绍STL的内容,这次我们要介绍的是list这个容器,可以简单地理解为顺序表,当然和我们之前学过顺序表还是有区别的,具体内容大家可以继续往下阅读,下面进入正文。 1. list简介 1.list是一种可…...
二百七十六、ClickHouse——Hive和ClickHouse非常不同的DWS指标数据SQL语句
一、目的 在完成数据之后对业务指标进行分析,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格式并存在时区差异时,可通过设置字段格式如yyyy-MM-dd HH:mm:ss并指定时区为GMT8来解决。存储Date类型数据时,可以使用JSON库如json-lib, fastjson, Jackson或gson进行…...
mathorcup2024台风 我all in ai
三个问题,力大砖飞。 不建物理模型,直接all in好吧 第一个故意无监督 第二个LSTMCNN注意力,刚好时间空间 第三个在第二个上加了个transfomer ,然后LSTM变双向,增加层数(基线模型选的经验公式,少…...
android 10 后台启动activity
摘要:Android 10(API 级别 29)及更高版本会限制应用何时可以启动 activity 背景。这些限制有助于最大限度地减少对用户的干扰, 让用户能够更好地控制其屏幕上显示的内容。本文以此为出发点,基于展锐平台对系统代码进行…...
文案创作新思路:Python与文心一言API的完美结合
在这个信息爆炸的时代,内容创作似乎成了一项需要魔法才能完成的任务。不过,别担心!今天,我们将向你介绍一种新的“魔法”工具——百度文心一言 API。这款大语言模型不仅能与人对话互动,还能高效便捷地协助你获取创意灵…...
CentOS 7 上安装 MySQL 8.0 教程
🌟 你好 欢迎来到我的技术小宇宙!🌌 这里不仅是我记录技术点滴的后花园,也是我分享学习心得和项目经验的乐园。📚 无论你是技术小白还是资深大牛,这里总有一些内容能触动你的好奇心。🔍 &#x…...
Chromium HTML5 新的 Input 类型url对应c++
一、Input 类型: url url 类型用于应该包含 URL 地址的输入域。 在提交表单时,会自动验证 url 域的值。 <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title>test</title> </head> <body&g…...
java多线程编程(二)一一>线程安全问题, 单例模式, 解决程线程安全问题的措施
引言: 如果多线程环境下代码运行的结果是符合我们预期的,即在单线程环境应该的结果,则说这个程序是线程安全的 线程安全问题的原因: 一.操作系统的随机调度 : 二.多个线程修改同一个变量: 三.修改操作不是…...
Leetcode 213. 打家劫舍 II 动态规划
原题链接:Leetcode 213. 打家劫舍 II class Solution { public:int rob(vector<int>& nums) {int n nums.size();if (n 1)return nums[0];if (n 2)return max(nums[0], nums[1]);// 如果偷了第一家,就不能偷最后一家int dp[n - 1];dp[0] …...
就业市场变革:AI时代,我们将如何评估人才?
内容概要 在这个充满变革的时代,就业市场正被人工智能(AI)技术深刻改变。随着技术的进步,传统的人才评估方式逐渐显示出其局限性。例如,过去依赖于纸质简历和面试评估的方式在快速变化的环境中难以准确识别真实的人才…...
富格林:安全操作方式稳健出金
富格林认为,黄金一直是吸引投资者关注的投资产品之一,投资者不断踏入黄金投资交易市场。很多投资者都以为现货黄金投资是很容易实现出金获得丰厚利润,但是面对复杂的交易市场,不仅不能轻易实现安全获利出金,甚至可能还…...
早点包子店点餐的软件下载和点餐操作教程 佳易王餐饮点餐管理系统操作方法
一、概述 【软件试用版资源文件可以点文章最后卡片了解】 早点包子店点餐的软件下载和点餐操作教程 适合于早点早餐餐饮行业的软件,实现早点点餐,收银会员管理,库存统计,销售统计等一体化操作。 点餐的时候可以用手触摸点&…...
uniapp一键打包
1.先安装python环境, 2.复制这几个文件到uniapp项目里面 3.修改自己证书路径,配置文件路径什么的 4.在文件夹页面双击buildController.py或者cmd直接输入buildController.py 5.python报错,哪个依赖缺少安装哪个依赖 6.执行不动的话&…...
什么是ksqlDB?流处理世界里的新范式
在大数据技术快速迭代的今天,我们见证了数据处理范式的不断演进。从批处理到流处理,从复杂的编程框架到声明式API,技术在不断简化与进化。而ksqlDB的出现,为我们带来了一个全新的视角 - 它不仅仅是一个流处理引擎,更是重新定义了我们与实时数据交互的方式。 让我们重新认识流处…...
Vue.js组件开发
Vue.js 是一个流行的 JavaScript 框架,用于构建用户界面和单页应用程序。开发 Vue.js 组件是 Vue.js 开发的核心部分。下面是一些关于 Vue.js 组件开发的基本概念和示例。 1. 创建一个基本的 Vue 组件 <template><div><h1>{{ title }}</h1>…...
网站设计要求/哪里有网页设计公司
Tomcat Cant load AMD 64-bit .dll on a IA 32 标签: tomcatinstallerjavajdkservice2012-06-01 17:09 38370人阅读 评论(7) 收藏 举报版权声明:版权归博主所有,转载请带上本文链接!联系方式:abel533gmail.com java.la…...
政府网站建设困难/正规seo需要多少钱
shutil.copyfileobj()文件拷贝,只拷贝文件内容: # 文件文件拷贝 f1 open("srcfile",r) f2 open("dstfile",w) shutil.copyfileobj(f1,f2)# 二进制文件拷贝f1 open("srcfile_b.mp4",rb) f2 open("dstfile_b.mp4",wb) sh…...
深圳做网站排名公司/市场调研分析报告范文
如模式名称所表达的,抽象工厂模式就像我们现实生活中的工厂一样,它是用于制造产品的,在此模式中产品就是类型的实例,而且这些实例具有关联性,它们每个像一个家族中的成员。这里提到的是抽象工厂,那么在使用…...
做网站工资高不高/天天广告联盟
相信大家在开发一些程序会有识别图片上文字(即所谓的OCR)的需求,比如识别车牌、识别图片格式的商品价格、识别图片格式的邮箱地址等等,当然需求最多的还是识别验证码。如果要完成这些OCR的工作,需要你掌握图像处理、图…...
用wordpress修改网站/环球贸易网
一,桶排序 如果数据的排序依据在一个有限的范围,可以将这个范围划分为多个有序的区间,然后扫描数据,将数据划分到不同的桶中,由于桶与桶是有序的,只需要对桶内的数据进行排序,桶内的数据有序后…...
快速搭建网站 优帮云/怎么制作seo搜索优化
一、饮品类 水促进新陈代谢,缩短粪便在肠道停留的时间,减少毒素的吸收,溶解水溶性的毒素。最好在每天清晨空腹喝一杯温开水。(每天八杯水,可要保证哦!) 排毒茶有一款藏药的效果特别好,用西藏的红景天…...