【Python】笔试面试题之生成器、闭包、字典

embedded/2025/1/24 1:32:18/

文章目录

  • 一、生成器是什么
    • 1. 最简单的生成器
    • 2. 在函数中使用yield关键字
  • 二、闭包是什么?怎么理解?
    • 1. 案例1
    • 2. 案例2:实现项目的日志处理
    • 3. 案例3:装饰器就是一种闭包
    • 4. 总结
  • 三、Python中字典的底层是怎么实现的
    • 1. 相关概念
    • 2. Python中字典的操作
    • 3. 哈希冲突
    • 4. 总结

个人主页:道友老李
欢迎加入社区:道友老李的学习社区

一、生成器是什么

我们来看看为什么python会添加生成器这个功能:

  • 我们知道我们可以用列表储存数据,可是当我们的数据特别大的时候建立一个列表的储存数据就会很占内存的。这时生成器就派上用场了。它可以说是一个不怎么占计算机资源的一种方法。

定义:

  • 跟普通函数不同的是,生成器是一个返回迭代器的函数,只能用于迭代操作,更简单点理解生成器就是一个迭代器。
  • 调用一个生成器函数,返回的是一个迭代器对象。

1. 最简单的生成器

我们可以用列表推导式来创建一个生成器:

python">gen = (x for x in range(5))print(gen) 
#output: <generator object <genexpr> at 0x0000000000AA20F8>from collections import Iterable, Iteratorprint(isinstance(gen, Iterable))#output:Trueprint(isinstance(gen, Iterator))
#output:True

2. 在函数中使用yield关键字

  • 在函数中使用yield关键字,函数就变成了一个generator。
  • 函数里有了yield后,执行到yield就会停住,当需要再往下算时才会再往下算。所以生成器函数即使是有无限循环也没关系,它需要算到多少就会算多少,不需要就不往下算。
  • 其作用和return的功能差不多,就是返回一个值给调用者,只不过有yield的函数返回值后函数依然保持调用yield时的状态,当下次调用的时候,在原先的基础上继续执行代码,直到遇到下一个yield或者满足结束条件结束函数为止。
python">def fib():a,b = 0,1while True:yield aa, b = b, a + b
# 迭代器是无限
def fib_d(times):# 初始化n = 0a, b = 0, 1while n < times:yield (b)a, b = b, a + bn += 1return 'ok'# 迭代器是有限

总结:生成器可以避免不必要的计算,带来性能上的提升;而且会节约空间,可以实现无限循环(无穷大的)的数据结构。

二、闭包是什么?怎么理解?

在一个外函数中定义了一个内嵌函数,内嵌函数里运用了外函数的临时变量,并且外函数的返回值是内函数的引用。这样就构成了一个闭包。

一般情况下,在我们认知当中,如果一个函数结束,函数的内部所有东西都会释放掉,还给内存,局部变量都会消失。但是闭包是一种特殊情况,如果外函数在结束的时候发现有自己的临时变量将来会在内部函数中用到,就把这个临时变量绑定给了内部函数,然后自己再结束。

三个条件,缺一不可:

  1. 必须有一个内嵌函数(函数里定义的函数)——这对应函数之间的嵌套
  2. 内嵌函数必须引用一个定义在闭合范围内(外部函数里)的变量——内部函数引用外部变量
  3. 外部函数必须返回内嵌函数——必须返回那个内部函数

1. 案例1

python">#闭包函数的实例# outer是外部函数 a和b都是外函数的临时变量def outer( a ):b = 10# inner是内函数def inner():#在内函数中 用到了外函数的临时变量print(a+b)b = b+1# 外函数的返回值是内函数的引用return inner
if __name__ == '__main__':# 在这里我们调用外函数传入参数5#此时外函数两个临时变量 a是5 b是10 ,并创建了内函数,然后把内函数的引用返回存给了demo# 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数demo = outer(5)# 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量# demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数demo() # 15demo2 = outer(7)demo2()#17

修改外部函数的变量:

python">def outer( a ):b = 10# inner是内函数def inner():# 表示这个变量不是局部变量空间的变量,需要向上一层变量空间找这个变量。nonlocal bprint(b)#在内函数中 用到了外函数的临时变量b = b+1print(a+b)# 外函数的返回值是内函数的引用return inner
if __name__ == '__main__':# 在这里我们调用外函数传入参数5#此时外函数两个临时变量 a是5 b是11 ,并创建了内函数,然后把内函数的引用返回存给了demo# 外函数结束的时候发现内部函数将会用到自己的临时变量,这两个临时变量就不会释放,会绑定给这个内部函数demo = outer(5)# 我们调用内部函数,看一看内部函数是不是能使用外部函数的临时变量# demo存了外函数的返回值,也就是inner函数的引用,这里相当于执行inner函数demo() # 15# demo2 = outer(7)demo()#17

2. 案例2:实现项目的日志处理

python">import loggingdef log_header(logger_name):logging.basicConfig(level=logging.DEBUG, format='%(asctime)s [%(name)s] %(levelname)s  %(message)s',datefmt='%Y-%m-%d %H:%M:%S')logger = logging.getLogger(logger_name)def _logging(something, level='debug'):if level == 'debug':logger.debug(something)elif level == 'warning':logger.warning(something)elif level == 'error':logger.error(something)else:raise Exception("I dont know what you want to do?")return _loggingproject_1_logging = log_header('project_1')project_2_logging = log_header('project_2')def project_1():# do somethingproject_1_logging('this is a debug info', 'debug')# do somethingproject_1_logging('this is a warning info', 'warning')# do somethingproject_1_logging('this is a error info', 'error')def project_2():# do somethingproject_2_logging('this is a debug info', 'debug')# do somethingproject_2_logging('this is a warning info', 'warning')# do somethingproject_2_logging('this is a critical info', 'error')project_1()
project_2()

3. 案例3:装饰器就是一种闭包

python">def makebold(fn):def wrapped():return "<b>" + fn() + "</b>"return wrappeddef makeitalic(fn):def wrapped():return "<i>" + fn() + "</i>"return wrapped@makebold@makeitalicdef hello():return "hello world"
print(hello())

4. 总结

  • 优点和作用:

    • 闭包似优化了变量,原来需要类对象完成的⼯作,闭包也可以完成; 大家回想一下类对象的情况,对象有好多类似的属性和方法,所以我们创建类,用类创建出来的对象都具有相同的属性方法。 闭包也是实现面向对象的方法之一。
    • 装饰器就是一种闭包,装饰器有的功能,闭包也有;
    • 闭包可以实现单例模式和工厂模式;
    • 当闭包执行完后,仍然能够保持住当前的运行环境。以便于下次调用;
  • 缺点:

    • 每次调用函数时,都得在全局作用域申明变量。别人调用函数时还得查看函数内部代码。
    • 当函数在多个地方被调用并且同时记录着很多状态时,会造成非常地混乱。
    • 由于闭包引⽤了外部函数的局部变量,则外部函数的局部变量没有及时释放,消耗内存

三、Python中字典的底层是怎么实现的

1. 相关概念

Python 字典的底层实现是哈希表。调用python内置的哈希函数,将键(Key)作为参数进行转换(哈希运算+取余运算),得到一个唯一的地址(地址的索引),然后将值(Value)存放到对应地址中(给相同的键赋值会直接覆盖原值,因为相同的键转换后的地址是一样的)。

哈希表(Hash Table,又称为散列表)是一种线性表的存储结构。由一个直接寻址表 T (假设大小为m) 和一个哈希函数 h(k) 组成。对于任意可哈希对象,通过哈希函数(一般先进行哈希计算,然后对结果进行取余运算),将该对象映射为寻址表的索引 [0,1,2,…m-1],然后在该索引所对应的空间 T[0,1,2,…,m-1] 进行变量的存储/读取等操作。如下图所示。
([1,2],[3,4,5])

在这里插入图片描述
在这里插入图片描述

注:键(Key)必须是可哈希的,即,通过哈希函数可为此键计算出唯一地址。

对于 Python 来说,变量,列表、字典、集合这些都是可变的,所以都不能做为键(Key)来使用。因为元祖里边可以存放列表这类可变因素,所以如果实在想拿元祖当字典的键(Key),那必须对元祖做限制:元组中只包括像数字和字符串这样的不可变元素时,才可以作为字典中有效的键(Key)。另外还需要注意的一点是,Python 的哈希算法对相同的值计算得到的结果是一样的,也就是说 12315 和 12315.0 的值相同,他们被认为是相同的键(Key)。

2. Python中字典的操作

  • 插入: 对键进行哈希和取余运算,得到一个哈希表的索引,如果该索引所对应的表地址空间为空,将键值对存入该地址空间;
  • 查询/更新: 对健进行哈希和取余运算,得到一个哈希表的索引,如果该索引所对应的地址空间中健与要查询/更新的健一致,那么就将该键值对取出来 / 更新该键所对应的值;
  • 扩容: 字典初始化的时候,会对应初始化一个有k个空间的表,等空间不够用的时候,系统就会自动扩容,这时候会对已经存在的键值对 重新进行哈希取余运算(重新进行插入操作)保存到其它位置;

3. 哈希冲突

由于哈希表的大小是有限的,而要存储的值的总数量是无限的,因此对于任何哈希函数,都会出现两个不同元素映射到同一个位置上的情况,这种情况叫做哈希冲突。字典使用了开放寻址法来解决冲突。

开放寻址法:如果哈希函数返回的位置已经有值,则可以探查新的空位置来存储这个值。
在这里插入图片描述
在这里插入图片描述

4. 总结

在这里插入图片描述


http://www.ppmy.cn/embedded/156447.html

相关文章

Python从0到100(八十五):神经网络-使用迁移学习完成猫狗分类

前言&#xff1a; 零基础学Python&#xff1a;Python从0到100最新最全教程。 想做这件事情很久了&#xff0c;这次我更新了自己所写过的所有博客&#xff0c;汇集成了Python从0到100&#xff0c;共一百节课&#xff0c;帮助大家一个月时间里从零基础到学习Python基础语法、Pyth…

1. 基于图像的三维重建

1. 基于图像的三维重建 核心概念三维重建中深度图、点云的区别&#xff1f;深度图点云总结 深度图到点云还需要什么步骤&#xff1f;1. **获取相机内参**2. **生成相应的像素坐标**3. **计算三维坐标**4. **构建点云**5. **处理颜色信息&#xff08;可选&#xff09;**6. **去除…

centos哪个版本建站好?centos最稳定好用的版本

在信息化飞速发展的今天&#xff0c;服务器操作系统作为构建网络架构的基石&#xff0c;其稳定性和易用性成为企业和个人用户关注的重点。CentOS作为一款广受欢迎的开源服务器操作系统&#xff0c;凭借其强大的性能、出色的稳定性和丰富的软件包资源&#xff0c;成为众多用户建…

Windows7搭建Hadoop-2.7.3源码阅读环境问题解决列表

个人博客地址:Window7搭建Hadoop-2.7.3源码阅读环境问题解决列表 | 一张假钞的真实世界 环境说明 Windows 7java version “1.7.0_80”Apache Maven 3.2.3ProtocolBuffer 2.5.0cmake version 3.7.2 win64 x64Windows SDK 7.1构建过程参照源代码目录下BUILDING.txt说明文件中的…

YOLOv8改进,YOLOv8检测头融合DSConv(动态蛇形卷积),并添加小目标检测层(四头检测),适合目标检测、分割等

精确分割拓扑管状结构例如血管和道路,对各个领域至关重要,可确保下游任务的准确性和效率。然而,许多因素使任务变得复杂,包括细小脆弱的局部结构和复杂多变的全局形态。在这项工作中,注意到管状结构的特殊特征,并利用这一知识来引导 DSCNet 在三个阶段同时增强感知:特征…

Vue3+Element Plus 实现 el-table 表格组件滚动是否触底监听判断

问题描述 Element Plus 中的 el-table 组件暴露出了 scroll 事件&#xff0c;表格被用户滚动后会触发&#xff0c;暴露出横向和竖向的滚动距离&#xff0c;未暴露出表格的DOM对象。 ({ scrollLeft: number, scrollTop: number }) > void此时&#xff0c;可以通过表格的引用…

摄影交流平台项目Uniapp+Springboot已完成

后端项目结构 前端项目结构 前端效果

深度学习python基础(第三节) 函数、列表

本节主要介绍函数、列表的基本语法格式。 函数 与c语言的函数差不多&#xff0c;就是语法基本格式不同。 name "loveyou" length len(name) print("字符串的长度为&#xff1a;%d" % length) # 自定义函数 def countstr(data):count 0for i in da…