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

深入理解闭包:原理、应用与最佳实践

1、 什么是闭包?

如果一个函数内部定义了另一个函数,并且内部函数引用了外部函数的变量,那么内部函数就形成了一个闭包。

def outer_function(x):# 外部函数接受一个参数 x 是自由变量# seed 也是一个自由变量seed = 10def inner_function(y):# 内部函数接受另一个参数 yreturn x + y + seedreturn inner_function# 创建闭包函数,传入参数 10,closure就是一个闭包
closure = outer_function(10)# 使用闭包函数计算 5 + 10 + 10
result = closure(5)
print(result)  # 输出 25

2、自由变量

https://docs.python.org/zh-cn/3.7/reference/executionmodel.html#index-6
局部变量,如果名称绑定在一个代码块中,则为该代码块的局部变量。
全局变量,如果名称绑定在模块层级,则为全局变量。
自由变量,如果变量在一个代码块中被使用但不是在其中定义,则为 自由变量。

3、闭包的特点

1、 闭包可以**捕获(即使外部函数已经执行完毕,这些变量依然可以被内部函数访问和操作)外部变量,**并且保持外部变量的状态,使其在多次调用中保持不变。
2、闭包允许函数返回一个函数,而不仅仅是一个值。
3、闭包与闭包之间的状态是隔离的

def average():data = []  # 使用列表来存储内部状态def add_number(number):data.append(number)  # 将新数字添加到列表中total = sum(data)  # 计算列表中所有数字的总和count = len(data)  # 获取列表中数字的数量return total / count if count > 0 else 0  # 计算平均数return add_number# 创建累计平均数的闭包
avg = average()# 不断添加新的数字并计算平均数
# data变量是average函数的局部变量
# 但是 当调用avg(10)时,average函数已经执行完了,所以它的作用域已经不存在了
print(avg(10))  # 平均数: 10.0
print(avg(20))  # 平均数: 15.0
print(avg(30))  # 平均数: 20.0
print("avg --> ", avg(40))  # 平均数: 25.0# 闭包和闭包之间的状态是隔离的
avg1 = average()
print("avg1 --> ", avg1(11))
print("avg1 --> ", avg1(15))

4、闭包的应用

本地作用域在函数结束后就立即失效,而嵌套作用域在嵌套的函数返回后却仍然有效,类似可以把这些变量类比为 C++中局部静态变量。想要给函数增加或者保持状态、实现装饰器、构建工厂函数、创建函数组合就可以使用闭包来实现。

##################### 函数组合
def add(x):return x + 2def multiply(x):return x * 3def compose(f, g):# 返回一个闭包,将 f(g(x)) 的结果def inner(x):return f(g(x))return inner# 创建函数组合
combined_function = compose(add, multiply)# 使用组合函数
result = combined_function(4)  # 先执行 multiply(4),然后执行 add(12)
print(result)  # 输出 14################### 创建工厂函数
def create_multiplier(factor):# 工厂函数返回一个闭包def multiplier(x):return x * factorreturn multiplier# 创建两个不同的乘法函数工厂
double = create_multiplier(2)
triple = create_multiplier(3)# 使用工厂函数生成乘法函数
double_result = double(5)  # 返回 5 * 2 = 10
triple_result = triple(5)  # 返回 5 * 3 = 15print(double_result)
print(triple_result)################# 装饰器
import timedef timing_decorator(func):def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()execution_time = end_time - start_timeprint(f"{func.__name__} executed in {execution_time:.4f} seconds")return resultreturn wrapper# 使用装饰器
@timing_decorator
def requests_http_data():# 模拟一些耗时操作time.sleep(2)requests_http_data()

5、global和nonlocal

global 声明对全局变量进行引用修改
nonlocal 内嵌函数内部想对嵌套作用域中的值是不可变类型的变量(值为 int、float、str)进行修改

n = 100def add():global n # 函数内部要对全局变量进行修改,必须使用global声明n = n +100print(n)add()
print(n)def sub():a = 100def execs():nonlocal a # 内嵌的函数想修改外部函数的变量,必须使用nonlocal进行声明a = a - 1return areturn execss = sub()
print(s())

6、闭包和类

闭包比较像只有一个方法的类,可以保持状态和数据隐藏,为什么不写成类:
1、闭包的功能一般很小很简单
2、闭包执行速度较快,不需要多余的self参数等

# 闭包
def counter():count = 0def increment():nonlocal countcount += 1return countreturn increment# 创建闭包对象
counter1 = counter()
counter2 = counter()print(counter1())  # 输出 1
print(counter1())  # 输出 2
print(counter2())  # 输出 1
print(counter1())  # 输出 3# 类
class Counter:def __init__(self):self.count = 0def increment(self):self.count += 1return self.count# 创建类对象
counter1 = Counter()
counter2 = Counter()print(counter1.increment())  # 输出 1
print(counter1.increment())  # 输出 2
print(counter2.increment())  # 输出 1
print(counter1.increment())  # 输出 3

7、扩展-偏函数

# 偏函数,也可以保持函数内部的变量状态
# 我们可以使用内置的 functools 模块的 partial 函数来创建偏函数。
# 偏函数指通过固定函数的一部分参数后,返回一个新的函数,
# 这个新函数可以接受剩余的参数进行调用
from functools import partialdef add(a, b):return a + bx = partial(add, 1) # 1赋给参数a 并暂停函数
print(x)
res1 = x(2)	# 将2赋给b后进行计算
print(res1) # 3
res2 = x(3)
print(res2) # 4

相关文章:

深入理解闭包:原理、应用与最佳实践

1、 什么是闭包? 如果一个函数内部定义了另一个函数,并且内部函数引用了外部函数的变量,那么内部函数就形成了一个闭包。 def outer_function(x):# 外部函数接受一个参数 x 是自由变量# seed 也是一个自由变量seed 10def inner_function(y…...

[NSSCTF 2nd]Math

原题py: from secret import flag from Crypto.Util.number import * import gmpy2length len(flag) flag1 flag[:length//2] flag2 flag[length//2:] e 65537m1 bytes_to_long(flag1) p getPrime(512) q getPrime(512) n p*q phi (p-1)*(q-1) d gmpy2.i…...

uml知识点学习

https://zhuanlan.zhihu.com/p/659911315https://zhuanlan.zhihu.com/p/659911315软件工程分析设计图库目录 - 知乎一、结构化绘图1. 结构化——数据流图Chilan Yuk:1. 结构化——数据流图2. 结构化——数据字典Chilan Yuk:2. 结构化——数据字典3. 结构…...

JAVA学习日记1——JAVA简介及第一个java程序

简单记忆 JAVA SE :标准版,核心基础 JAVA EE:企业版,进阶 JDK:Java Development Kit,Java开发工具包,包含JRE JRE:Java Runtime Environment,Java运行时环境&#xff…...

Linux命令(102)之less

linux命令之less 1.less介绍 linux命令less是一个文本文件查看工具,它以一种交互的方式,逐页地显示文本文件的内容,并且可以在文件中进行搜索等定位 2.less用法 less [参数] filename less参数 参数说明-N显示每行的行号-i忽略搜索时的大…...

vue多条件查询

<template><div><input type"text" v-model"keyword" placeholder"关键字"><select v-model"category"><option value"">所有分类</option><option v-for"cat in categories&q…...

c 语言基础:L1-038 新世界

这道超级简单的题目没有任何输入。 你只需要在第一行中输出程序员钦定名言“Hello World”&#xff0c;并且在第二行中输出更新版的“Hello New World”就可以了。 输入样例&#xff1a; 无输出样例&#xff1a; Hello World Hello New World 程序源码&#xff1a; #incl…...

计算机算法分析与设计(13)---贪心算法(多机调度问题)

文章目录 一、问题概述1.1 思路分析1.2 实例分析 二、代码编写 一、问题概述 1.1 思路分析 1. 设有 n n n 个独立的作业 1 , 2 , … , n {1, 2, …, n} 1,2,…,n&#xff0c;由 m m m 台相同的机器 M 1 , M 2 , … , M m {M_1, M_2, …, M_m} M1​,M2​,…,Mm​ 进行加工处…...

小程序canvas层级过高真机遮挡组件的解决办法

文章目录 问题发现真机调试问题分析问题解决改造代码效果展示 问题发现 在小程序开发中需要上传图片进行裁剪&#xff0c;在实际真机调试中发现canvas层遮挡住了生成图片的按钮。 问题代码 <import src"../we-cropper/we-cropper.wxml"></import> <…...

番外8.1 配置+管理文件系统

Task01: Linux 文件系统结构&#xff1b; 可以进行Linux操作系统的文件权限管理与方式切换&#xff0c;可以应用磁盘与文件权限管理工具&#xff1b; 01&#xff1a;常见文件系统类型&#xff08;Ext4[rhel6默认文件管理系统], 存储容量1 EB1073741824 GB; XFS[rhel 7/8默认的文…...

互联网Java工程师面试题·Java 总结篇·第八弹

目录 72、用 Java 的套接字编程实现一个多线程的回显&#xff08;echo&#xff09;服务器。 73、XML 文档定义有几种形式&#xff1f;它们之间有何本质区别&#xff1f;解析XML 文档有哪几种方式&#xff1f; 74、你在项目中哪些地方用到了 XML&#xff1f; 72、用 Java 的套…...

VSCode修改扩展和用户文件夹目录位置(Windows)

VSCode修改扩展和用户文件夹目录位置&#xff08;Windows&#xff09; 前言&#xff1a;方法前期准备&#xff1a;方法1&#xff08;强推荐&#xff09;方法2&#xff08;不太推荐&#xff09;方法3&#xff08;好麻烦&#xff0c;不太推荐&#xff09; 前言&#xff1a; VSCod…...

Spring 事务

文章目录 实现CURD&#xff08;没加入事务前&#xff09;1.加入依赖2.创建jdbc.properties3.配置Spring的配置文件4.数据库与测试表 基于注解的声明式事务准备工作测试模拟场景 加入事务①添加事务配置 Transactional注解标识的位置只读事务属性&#xff1a;超时事务属性&#…...

无法访问 github ,解决办法

一、使用代理&#xff08;首选&#xff09; 这种办法只需要更改github.com为代理的域名即可&#xff0c;使用方式与GitHub除了域名不同其他都一样&#xff0c;速度挺快&#xff0c;可登陆&#xff0c;可提交。 1、查看当前的代理&#xff1a; git config --global --get htt…...

SD卡与emmc的异同

eMMC与SD卡的异同&#xff1a; 物理尺寸和接口&#xff1a; eMMC&#xff1a;eMMC是一种嵌入式存储解决方案&#xff0c;通常采用BGA&#xff08;Ball Grid Array&#xff09;封装&#xff0c;焊接在电路板上。它没有标准的物理尺寸&#xff0c;而是以芯片的形式存在。SD卡&…...

机器学习笔记 - 3D 对象跟踪极简概述

一、简述 大多数对象跟踪应用程序都是 2D 的。但现实世界是 3D 的,无论您是跟踪汽车、人、直升机、导弹,还是进行增强现实,您都需要使用 3D。在 CVPR 2022(计算机视觉和模式识别)会议上,已经出现了大量3D目标检测论文。 二、什么是 3D 对象跟踪? 对象跟踪是指随着时间的…...

《机器学习----简单的分类器》第二章、朴素贝叶斯,项目:使用特征值给语句打标签

贝叶斯分类器 1,朴素贝叶斯算法1. 朴素贝叶斯算法、2. 算法思路3. 贝叶斯定理4.特征的选用的要求和处理 2&#xff0c;算法应用1 文本分类2 垃圾邮件过滤3 情感分析 3. 朴素贝叶斯的优缺点1. 优点2. 缺点 项目实践1&#xff0c;算法流程2&#xff0c;具体实现 1,朴素贝叶斯算法…...

01. 汇编LED驱动实验

01. 汇编LED驱动实验 汇编原理分析为什么要学习Cortex—A汇编STM32IO初始化流程IMX6UL初始化流程 汇编基础处理器内部数据传输指令存储器访问指令 编写驱动编译程序烧写bin文件 汇编原理分析 为什么要学习Cortex—A汇编 需要用汇编初始化一些SOC外设使用汇编初始化DDR&#x…...

Hadoop3教程(二十):MapReduce的工作机制总结

文章目录 &#xff08;109&#xff09;MapTask工作机制&#xff08;110&#xff09;ReduceTask工作机制&并行度ReduceTask工作机制MapTask和ReduceTask的并行度决定机制 &#xff08;122&#xff09;MapReduce开发总结参考文献 &#xff08;109&#xff09;MapTask工作机制…...

浅谈AI大模型技术:概念、发展和应用

AI大模型技术是指使用超大规模的深度学习模型来解决各种复杂的人工智能问题&#xff0c;如自然语言处理、计算机视觉、多模态交互等。AI大模型技术具有强大的学习能力和泛化能力&#xff0c;可以在多种任务上取得优异的性能&#xff0c;但也面临着计算、存储、通信等方面的挑战…...

Vim 调用外部命令学习笔记

Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...

内存分配函数malloc kmalloc vmalloc

内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

SkyWalking 10.2.0 SWCK 配置过程

SkyWalking 10.2.0 & SWCK 配置过程 skywalking oap-server & ui 使用Docker安装在K8S集群以外&#xff0c;K8S集群中的微服务使用initContainer按命名空间将skywalking-java-agent注入到业务容器中。 SWCK有整套的解决方案&#xff0c;全安装在K8S群集中。 具体可参…...

《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》

在注意力分散、内容高度同质化的时代&#xff0c;情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现&#xff0c;消费者对内容的“有感”程度&#xff0c;正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中&#xff0…...

高等数学(下)题型笔记(八)空间解析几何与向量代数

目录 0 前言 1 向量的点乘 1.1 基本公式 1.2 例题 2 向量的叉乘 2.1 基础知识 2.2 例题 3 空间平面方程 3.1 基础知识 3.2 例题 4 空间直线方程 4.1 基础知识 4.2 例题 5 旋转曲面及其方程 5.1 基础知识 5.2 例题 6 空间曲面的法线与切平面 6.1 基础知识 6.2…...

【HTML-16】深入理解HTML中的块元素与行内元素

HTML元素根据其显示特性可以分为两大类&#xff1a;块元素(Block-level Elements)和行内元素(Inline Elements)。理解这两者的区别对于构建良好的网页布局至关重要。本文将全面解析这两种元素的特性、区别以及实际应用场景。 1. 块元素(Block-level Elements) 1.1 基本特性 …...

JDK 17 新特性

#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持&#xff0c;不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的&#xff…...

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* …...

[Java恶补day16] 238.除自身以外数组的乘积

给你一个整数数组 nums&#xff0c;返回 数组 answer &#xff0c;其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。 题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在 32 位 整数范围内。 请 不要使用除法&#xff0c;且在 O(n) 时间复杂度…...

Element Plus 表单(el-form)中关于正整数输入的校验规则

目录 1 单个正整数输入1.1 模板1.2 校验规则 2 两个正整数输入&#xff08;联动&#xff09;2.1 模板2.2 校验规则2.3 CSS 1 单个正整数输入 1.1 模板 <el-formref"formRef":model"formData":rules"formRules"label-width"150px"…...