闭包和装饰器

什么是闭包

闭包(Closure)是 Python 中一个非常重要的概念,它是一种特殊的函数对象,通常用于封装和延迟计算某些值。以下是闭包的详细定义和解释:

1.闭包的定义
闭包是指一个函数对象,它不仅包含函数的代码,还绑定了函数外部的自由变量(free variable)。自由变量是指在函数内部被引用,但不是函数参数的变量。闭包允许函数访问和操作这些自由变量,即使这些变量的作用域已经结束。

2.闭包的构成要素
一个闭包通常由以下三个部分组成:

• 外部函数:定义了自由变量的函数。

• 内部函数:在外部函数内部定义的函数,它引用了外部函数的自由变量。

• 自由变量:在内部函数中被引用,但不是内部函数参数的变量。

3.闭包的创建
闭包是通过返回内部函数来创建的。当内部函数被返回时,它会记住外部函数的自由变量,即使外部函数的作用域已经结束。这种机制使得闭包可以“记住”外部函数的上下文。

4.闭包的作用
闭包的主要作用是封装状态,允许函数在不使用全局变量的情况下,保存和操作一些数据。闭包可以用于实现装饰器、延迟计算、回调函数等功能。

5.闭包的示例
以下是一个简单的闭包示例,用于说明闭包的创建和使用:

def outer_function(x):def inner_function(y):return x + y  # x 是自由变量return inner_function  # 返回内部函数,创建闭包# 创建闭包
closure = outer_function(10)  # x 被绑定为 10# 调用闭包
result = closure(5)  # 调用 inner_function,y 为 5,结果为 15
print(result)  # 输出 15

在这个例子中:

outer_function是外部函数,它定义了一个自由变量x

inner_function是内部函数,它引用了自由变量x

• 当outer_function被调用时,它返回了inner_function,此时inner_function记住了x的值(10),即使outer_function的作用域已经结束。

closure是一个闭包对象,它绑定了自由变量x的值(10),并可以被多次调用。

6.闭包的特性

• 自由变量的绑定:闭包会记住外部函数的自由变量的值,即使外部函数的作用域已经结束。

• 延迟计算:闭包允许延迟计算某些值,直到内部函数被调用。

• 封装性:闭包可以封装状态,避免使用全局变量,使代码更加模块化。

7.闭包的应用场景

• 装饰器:Python 中的装饰器本质上是闭包,用于在不修改原函数的情况下扩展函数的功能。

• 回调函数:闭包可以作为回调函数,保存一些上下文信息。

• 延迟计算:闭包可以用于延迟计算某些值,直到需要时才计算。

• 封装状态:闭包可以封装一些状态信息,避免使用全局变量。

8.注意事项

• 内存占用:闭包会占用一定的内存,因为它们需要保存自由变量的值。

• 变量作用域:自由变量的值是绑定在闭包创建时的值,而不是调用时的值。

• 不可变变量:如果自由变量是不可变类型(如整数、字符串等),它们的值在闭包中是固定的;如果是可变类型(如列表、字典等),它们的值可以在闭包中被修改。

全局变量使用

在 Python 中,nonlocal是一个关键字,用于在嵌套函数中修改外部函数(但不是全局作用域)中的变量。它是 Python 3 中引入的一个特性,用于解决嵌套函数中变量作用域的问题。

1.nonlocal的作用

在嵌套函数中,如果内部函数需要修改外部函数中的变量,而这个变量既不是全局变量,也不是内部函数的局部变量,那么就需要使用nonlocal关键字。nonlocal告诉 Python,变量来自外层作用域(但不是全局作用域),从而允许内部函数修改这个变量。

2.使用场景

假设有一个外部函数和一个内部函数,外部函数中定义了一个变量,内部函数需要修改这个变量。如果没有nonlocal,Python 会认为内部函数中对变量的赋值是创建了一个新的局部变量,而不是修改外部函数中的变量。使用nonlocal可以明确告诉 Python,要修改的是外部函数中的变量。

3.示例

以下是一个使用nonlocal的示例:

def outer_function():x = 10  # 外部函数中的变量def inner_function():nonlocal x  # 使用 nonlocal 声明 xx = 20  # 修改外部函数中的 xinner_function()  # 调用内部函数print(x)  # 输出修改后的 xouter_function()

输出结果为:

20

在这个例子中:

xouter_function中的局部变量。

inner_function是嵌套在outer_function内部的函数。

• 如果不使用nonlocalinner_function中的x = 20会创建一个新的局部变量x,而不会修改outer_function中的x

• 使用nonlocal x后,inner_function中的x = 20会修改outer_function中的x

4.nonlocal的规则

nonlocal只能用于嵌套函数中,不能用于全局作用域。

nonlocal声明的变量必须在外部作用域中已经存在,不能在内部函数中直接创建一个nonlocal变量。

nonlocal只能用于修改变量的值,不能用于重新绑定变量到一个新的对象。

5.示例:嵌套多层函数

nonlocal可以用于多层嵌套的函数中,但只能作用于直接外层的变量。例如:

def outer_function():x = 10def middle_function():def inner_function():nonlocal x  # 修改 outer_function 中的 xx = 20inner_function()middle_function()print(x)outer_function()

输出结果为:

20

在这个例子中,inner_function中的nonlocal x修改了outer_function中的x,而不是middle_function中的x

7.nonlocalglobal的区别

global用于声明全局变量,可以在函数内部修改全局作用域中的变量。

nonlocal用于声明嵌套函数中的变量,只能修改外层函数(非全局作用域)中的变量。

闭包的主要作用就是使用装饰器

装饰器(Decorator)是Python提供的一种语法糖,它允许你在不修改函数本身代码的情况下,增加函数的新功能。装饰器本质上是一个函数,它接收一个函数作为参数并返回一个新的函数。

装饰器的功能特点:

  1. 不修改已有函数的源代码:装饰器不会改变被装饰函数的代码。

  2. 不修改已有函数的调用方式:调用被装饰的函数时,不需要改变调用方式。

  3. 给已有函数增加额外的功能:装饰器可以在不修改函数代码的情况下,给函数增加新的功能。

装饰器的使用:
由于装饰器本质上就是一个闭包函数,所以在使用自定义装饰器之前,需要先定义一个用来做装饰器的闭包。闭包的外部函数名,就作为装饰器名使用。

在图中,展示了一个简单的装饰器示例:

import timedef count_time(func):def inner():start_time = time.time()func()stop_time = time.time()print(f"Function {func.__name__} took {stop_time - start_time} seconds to execute.")return inner# 使用装饰器
@count_time
def example_function():time.sleep(2)print("Function is running.")

在这个例子中:

count_time是一个装饰器函数,它接收一个函数func作为参数,并返回一个新的函数inner

inner函数记录了func函数的执行时间,并在执行前后打印相关信息。

@count_time是装饰器的使用方式,它将example_function函数作为参数传递给count_time装饰器。

通过这种方式,example_function在执行时会自动记录并打印其执行时间,而不需要修改example_function的代码。这就是装饰器的强大之处,它能够在不改变函数代码的情况下,给函数增加新的功能。

可变参数

在Python中,如果你需要定义一个函数来处理可变数量的参数,你可以使用*args**kwargs来实现。这两种方法允许你的函数接收任意数量的位置参数和关键字参数。

使用*args处理可变数量的位置参数

*args允许你将任意数量的位置参数传递给函数,这些参数在函数内部作为一个元组处理。

def fun(*args):for arg in args:print(arg)fun(1, 2, 3, 4, 5)  # 输出: 1 2 3 4 5

在这个例子中,fun函数可以接收任意数量的位置参数,并将它们打印出来。

使用**kwargs处理可变数量的关键字参数

**kwargs允许你将任意数量的关键字参数传递给函数,这些参数在函数内部作为一个字典处理。

def fun(**kwargs):for key, value in kwargs.items():print(f"{key}: {value}")fun(name="Alice", age=25, city="New York")  # 输出: name: Alice age: 25 city: New York

在这个例子中,fun函数可以接收任意数量的关键字参数,并将它们打印出来。

结合使用*args**kwargs

你可以在同一个函数中同时使用*args**kwargs,以处理任意数量的位置参数和关键字参数。

def fun(*args, **kwargs):for arg in args:print(arg)for key, value in kwargs.items():print(f"{key}: {value}")fun(1, 2, 3, name="Alice", age=25)  # 输出: 1 2 3 name: Alice age: 25

在这个例子中,fun函数可以同时接收任意数量的位置参数和关键字参数。

装饰器中使用*args**kwargs

当你在装饰器中处理被装饰函数时,如果被装饰函数可能接收可变数量的参数,你需要在装饰器的包装函数中传递这些参数。

import timedef count_time(func):def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()print(f"Function {func.__name__} took {end_time - start_time} seconds to execute.")return resultreturn wrapper@count_time
def greet(name, *args, **kwargs):print(f"Hello, {name}!")for arg in args:print(arg)for key, value in kwargs.items():print(f"{key}: {value}")greet("Alice", 25, city="New York")  # 输出: Hello, Alice! 25 city: New York

在这个例子中,greet函数可以接收一个位置参数name,任意数量的位置参数*args,以及任意数量的关键字参数**kwargs。装饰器count_time通过在包装函数wrapper中使用*args**kwargs,确保了这些参数能够正确地传递给greet函数。

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

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

相关文章

notepad++8.6.4安装及细节

notepad8.6.4下载安装(附安装包) 一、安装包下载1.1方法一:官网下载(点击跳转)1.2方法二:网盘链接分享8.6.4版本 二、安装过程细节2.1这里的组件建议全部勾选。点击“下一步”。2.2 勾选①:可以…

COZE通关指南:工作流与插件开发

前言 本文隶属于专栏《AI Agent 通关指南》,该专栏为笔者原创,引用请注明来源,不足和错误之处请在评论区帮忙指出,谢谢! 本专栏目录结构和参考文献请见《AI Agent 通关指南》 正文 1. 平台基础介绍 🌟 1.1 COZE平台概述 COZE平台(coze.cn)是一个强大的AI应用开发平台…

【Block总结】ENLTransformerBlock,高效非局部变换器块|即插即用

1. 论文信息 标题: Perspective+ Unet: Enhancing Segmentation with Bi-Path Fusion and Efficient Non-Local Attention for Superior Receptive Fields论文地址: arXiv:2406.14052 2. 创新点 双路径编码策略: 在编码器阶段引入双路径策略,结合传统卷积和空洞卷积的结果,平…

【爬虫】网易云音乐评论数据爬取

文章目录 🍖 前言🎶一、抓取要求✨二、代码展示🏀三、运行结果🏆四、知识点提示 🍖 前言 【爬虫】网易云音乐歌词/评论数据爬取 🎶一、抓取要求 描述: 输入歌曲的id,获取对应歌曲的用户评论信…

C++使用Qt Charts创建数据可视化图表

Qt Charts 是一个强大的工具,用于创建直观的数据可视化图表。本文将通过一个具体的示例,展示如何使用 Qt Charts 创建一个包含多条数据序列、自定义坐标轴和随机数据生成的图表。 示例代码解析 以下是一个完整的示例代码,展示如何使用 Qt Ch…

TCP/IP五层协议

目录 1. 五层模型结构 2. 各层核心功能与协议 (1) 应用层(Application Layer) (2) 传输层(Transport Layer) (3) 网络层(Network Layer) (4) 数据链路层(Data Link Layer) (5…

【最新版】金媒婚恋系统v10.5最新稳定开源+原生前端小程序 PC端+安装教程

一.系统简介 1. 红娘服务 红娘服务模块是该系统的一大特色。专业红娘会通过分析用户的个人资料和偏好, 为用户提供精准的配对建议和个性化服务。用户可以预约红娘服务,通过红娘的介入,提升配对成功率。 2. 相亲活动 相亲活动模块用于组织和管…

吴恩达深度学习复盘(5)神经网络的前向传播TesorFlow与NumPy实现比对

数据结构差别 NumPy 和 TensorFlow 在数据表示上的差异展开,结合神经网络实践中的常见问题进行说明。以下是详细解析: 一、简介 数据表示的历史背景 NumPy 是 Python 科学计算的基础库,早期设计为处理多维数组TensorFlow 由 Google Brain 团…

多元高斯分布函数

1、 n n n元向量 假设 n n n元随机变量 X X X X [ X 1 , X 2 , ⋯ , X i , ⋯ , X n ] T μ [ μ 1 , μ 2 , ⋯ , μ i , ⋯ , μ n ] T σ [ σ 1 , σ 2 , ⋯ , σ i , ⋯ , σ n ] T X i ∼ N ( μ i , σ i 2 ) \begin{split} X&[X_1,X_2,\cdots,X_i,\cdots ,X_n…

洞察 Linux 进程管理

一、进程和线程的概念 1.进程 (1)概念 进程是程序在操作系统中的一次执行过程,是系统进行资源分配和调度的基本单位。进程是程序的执行实例,拥有独立的资源(如内存、文件描述符等)。每个进程在创建时会被…

PyTorch 实现图像版多头注意力(Multi-Head Attention)和自注意力(Self-Attention)

本文提供一个适用于图像输入的多头注意力机制(Multi-Head Attention)PyTorch 实现,适用于 ViT、MAE 等视觉 Transformer 中的注意力计算。 模块说明 输入支持图像格式 (B, C, H, W)内部转换为序列 (B, N, C),其中 N H * W多头注…

每日一题(小白)字符串娱乐篇16

分析题意可以了解到本题要求在一串字符串中找到所有组合起来排序递增的字符串。我们可以默认所有字符在字符串中的上升序列是1,从第一个字符开始找,如果后面的字符大于前面的字符就说明这是一个上序列那么后面字符所在的数组加一,如果连接不上…

Ubuntu 22 Linux上部署DeepSeek R1保姆式操作详解(Xinference方式)

一、安装步骤 1.基础环境安装 安装显卡驱动、cuda,根据自己硬件情况查找相应编号,本篇不介绍这部分内容,只给出参考指令,详情请读者自行查阅互联网其它参考资料。 sudo apt install nvidia-utils-565-server sudo apt install…

Immutable.js 完全指南:不可变数据的艺术与实践

引言 在现代前端开发中,状态管理是一个核心挑战。随着应用复杂度增加,如何高效、安全地管理应用状态变得至关重要。Immutable.js 是 Facebook 推出的一个 JavaScript 库,它提供了持久化不可变数据结构,可以帮助开发者更好地管理应…

字符串数据类型的基本运算

任务描述 本关任务:从后台输入任意三个字符串,求最大的字符串。 相关知识 字符串本身是存放在一块连续的内存空间中,并以’\0’作为字符串的结束标记。 字符指针变量本身是一个变量,用于存放字符串的第 1 个字符的地址。 字符数…

Ubuntu 22.04 一键部署openManus

openManus 前言 OpenManus-RL,这是一个专注于基于强化学习(RL,例如 GRPO)的方法来优化大语言模型(LLM)智能体的开源项目,由来自UIUC 和 OpenManus 的研究人员合作开发。 前提要求 安装deepseek docker方式安装 ,windows 方式安装,Linux安装方式

PDF 转图片,一行代码搞定!批量支持已上线!

大家好,我是程序员晚枫。今天我要给大家带来一个超实用的功能——popdf 现在支持 PDF 转图片了,而且还能批量操作!是不是很激动?别急,我来手把手教你玩转这个功能。 1. 一行代码搞定单文件转换 popdf 的核心就是简单暴…

《比特城的机密邮件:加密、签名与防篡改的守护之战》

点击下面图片带您领略全新的嵌入式学习路线 🔥爆款热榜 88万阅读 1.6万收藏 第一章:风暴前的密令 比特城的议会大厅内,首席长老艾德文握着一卷足有半人高的羊皮纸,眉头紧锁。纸上是即将颁布的《新纪元法典》——这份文件不仅内…

8.用户管理专栏主页面开发

用户管理专栏主页面开发 写在前面用户权限控制用户列表接口设计主页面开发前端account/Index.vuelangs/zh.jsstore.js 后端Paginator概述基本用法代码示例属性与方法 urls.pyviews.py 运行效果 总结 欢迎加入Gerapy二次开发教程专栏! 本专栏专为新手开发者精心策划了…

http://noi.openjudge.cn/_2.5基本算法之搜索_1804:小游戏

文章目录 题目深搜代码宽搜代码深搜数据演示图总结 题目 1804:小游戏 总时间限制: 1000ms 内存限制: 65536kB 描述 一天早上,你起床的时候想:“我编程序这么牛,为什么不能靠这个赚点小钱呢?”因此你决定编写一个小游戏。 游戏在一…