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)是一种用于修改或扩展函数或方法行为的高级功能。它们本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。装饰器使用@语法糖来应用 

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

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

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 带有参数的装饰器

装饰器本身也可以接受参数。为了实现这一点,可以使用嵌套函数:

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 保留函数元数据 

在装饰器内部定义的 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 的名称和文档字符串等元数据

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/460294.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

从0到1构建 UniApp + Vue3 + TypeScript 移动端跨平台开源脚手架

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f343; vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode&#x1f4ab; Gitee &#x1f…

Docker部署教程:打造流畅的斗地主网页小游戏

Docker部署教程:打造流畅的斗地主网页小游戏 一、项目介绍项目简介项目预览二、系统要求环境要求环境检查Docker版本检查检查操作系统版本三、部署斗地主网页小游戏下载镜像创建容器检查容器状态查看容器日志安全设置四、访问斗地主网页小游戏五、总结一、项目介绍 项目简介 …

计算机视觉常用数据集Cityscapes的介绍、下载、转为YOLO格式进行训练

我在寻找Cityscapes数据集的时候花了一番功夫&#xff0c;因为官网下载需要用公司或学校邮箱邮箱注册账号&#xff0c;等待审核通过后才能进行下载数据集。并且一开始我也并不了解Cityscapes的格式和内容是什么样的&#xff0c;现在我弄明白后写下这篇文章&#xff0c;用于记录…

【机器学习】Lesson3 - 逻辑回归(LR)二分类

目录 背景 一、适用数据集 1. 数据集选择 1.1 领域 1.2 数据集维度 1.3 记录行&#xff08;样本数量&#xff09; 2. 本文数据集介绍 3. 数据集下载 注意 二、逻辑回归的基本原理 1. 目的 2. Sigmoid 函数 3. 类别划分 4. 召回率 三、代码 1. 导入所需包&数…

kubernetes——part2-3 使用RKE构建企业生产级Kubernetes集群

使用RKE构建企业生产级Kubernetes集群 一、RKE工具介绍 RKE是一款经过CNCF认证的开源Kubernetes发行版&#xff0c;可以在Docker容器内运行。 它通过删除大部分主机依赖项&#xff0c;并为部署、升级和回滚提供一个稳定的路径&#xff0c;从而解决了Kubernetes最常见的安装复杂…

重学SpringBoot3-Spring WebFlux之HttpHandler和HttpServer

更多SpringBoot3内容请关注我的专栏&#xff1a;《SpringBoot3》 期待您的点赞&#x1f44d;收藏⭐评论✍ 重学SpringBoot3-Spring WebFlux之HttpHandler和HttpServer 1. 什么是响应式编程&#xff1f;2. Project Reactor 概述3. HttpHandler概述3.1 HttpHandler是什么3.2 Http…

3D Gaussian Splatting代码详解(三):模型构建,实现3D 高斯椭球体的克隆和分裂

3 模型构建 3.4 根据梯度对3D gaussian 进行增加或删减 &#xff08;1&#xff09; 对3D高斯分布进行密集化和修剪的操作 def densify_and_prune(self, max_grad, min_opacity, extent, max_screen_size):"""对3D高斯分布进行密集化和修剪的操作:param max_g…

无人机协同控制技术详解!

一、算法概述 无人机协同控制技术算法是指通过综合运用通信、控制、优化等多学科知识&#xff0c;实现对多个无人机的协同控制和任务规划。这些算法通常基于各种数学模型和控制理论&#xff0c;如线性代数、微分方程、最优控制等&#xff0c;旨在确保无人机能够相互协作&#…

【热门主题】000013 C++游戏开发全攻略

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享一篇文章&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 目录 【热…

QT中的item views与Item widgets控件的用法总结

0、前言 在一般进行数据表格展示的时候&#xff0c;大多时候要用到表格、列表或者树形结构。 Qt中常见的控件显示有两大类&#xff1a; Item View (list View、Tree View、Table View、Column View和Undo View&#xff09;Item widget&#xff08;List Widget、Tree Widget和…

ssm+vue645基于web的电影购票系统设计与实现

博主介绍&#xff1a;专注于Java&#xff08;springboot ssm 等开发框架&#xff09; vue .net php phython node.js uniapp 微信小程序 等诸多技术领域和毕业项目实战、企业信息化系统建设&#xff0c;从业十五余年开发设计教学工作 ☆☆☆ 精彩专栏推荐订阅☆☆☆☆☆不…

Spark RDD

概念 RDD是一种抽象&#xff0c;是Spark对于分布式数据集的抽象&#xff0c;它用于囊括所有内存中和磁盘中的分布式数据实体 RDD 与 数组对比 对比项数组RDD概念类型数据结构实体数据模型抽象数据跨度单机进程内跨进程、跨计算节点数据构成数组元素数据分片(Partitions)数据…

java-数据结构

一.链表 单向链表 /单向链表 public class SinglyLinkedList implements Iterable<Integer> {//头节点private Node head null;//头指针//节点类private static class Node{int value;//值Node next;//下一个节点的指针public Node(int value, Node next) {this.val…

pycharm与anaconda下的pyside6的安装记录

一、打开anaconda虚拟环境的命令行窗口&#xff0c;pip install&#xff0c;加入清华源&#xff1a; pip install PySide6 -i https://pypi.tuna.tsinghua.edu.cn/simple 二、打开pycharm&#xff0c;在文件--设置--工具--外部工具中配置一下三项&#xff1a; 1、 QtDesigner…

成本累计曲线:项目预算的秘密武器

在项目管理的过程中&#xff0c;成本控制是影响项目成败的关键因素之一&#xff0c;而其中“成本累计曲线”就像是一位财务导航员&#xff0c;为项目的成本控制和进度监控提供了极大的帮助。那么&#xff0c;什么是成本累计曲线&#xff1f;它包含哪些步骤&#xff1f;如何应用…

[0152].第3节:IDEA中工程与模块

我的后端学习大纲 IDEA大纲 1、Project和Module的概念&#xff1a; 2、Module操作&#xff1a; 2.1.创建Module: 2.2.删除Module&#xff1a; 2.3.导入Module&#xff1a; 1.导入外来模块的代码&#xff1a; 查看Project Structure&#xff0c;选择import module&#xff1a…

【Linux网络】UdpSocket

目录 套接字 socket编程 源IP地址和目的IP地址 端口号 网络字节序 socket常用API socket结构 UDP UDP协议&#xff08;用户数据报协议&#xff09; 创建套接字 绑定 通信 udp_echo_server:简单的回显服务器和客户端代码 dict_server:简单的英译汉的网络字典 chat_…

双11猫咪好物盛典开启,线上抢购不停 购物清单新鲜出炉

双十一购物狂欢节终于到了&#xff01;铲屎官们想好要给猫咪添置什么好东西了吗&#xff1f;还不知道怎么选的看过来啦~这里整理了一份双十一购物清单&#xff0c;快看看有没有你需要的吧&#xff01; 双十一养猫必购1&#xff1a;CEWEY自动猫砂盆 CEWEY自动猫砂盆真的是我最爱…

magic-api简单使用二:自定义返回结果

背景 在上一章 中我们学习了搭建项目和导入文件&#xff0c; 这二天稍微有点时间&#xff0c;研究下这个magic-api的写法。 后续如果需要维护或者更改&#xff0c;也能在项目中尽快上手。 今天我们主要学习自定义返回结果&#xff0c;当然也可以使用官方的。不需要任何更改。…

二百七十、Kettle——ClickHouse中增量导入清洗数据错误表

一、目的 比如原始数据100条&#xff0c;清洗后&#xff0c;90条正确数据在DWD层清洗表&#xff0c;10条错误数据在DWD层清洗数据错误表&#xff0c;所以清洗数据错误表任务一定要放在清洗表任务之后。 更关键的是&#xff0c;Hive中原本的SQL语句&#xff0c;放在ClickHouse…