(三十三)补充Python经典面试题(吸收高级编程特性)
第一题:
def func(a, b=[]): pass
一、上题讲解:
这个函数定义有一个默认参数b,它的默认值是一个空列表[]。这道面试题涉及到Python中函数参数默认值的一些重要概念和陷阱。
首先,当你调用这个函数时,如果不传递参数b的值,它将使用默认的空列表[]。例如:
func(1) # 这会将a设置为1,b设置为默认的空列表[]
但是,这里有一个陷阱。默认参数b(即空列表[])在函数定义时只会被创建一次,而不是每次函数调用时都会创建一个新的空列表。这就意味着,如果你在一个函数调用中修改了b的值,那么下一次调用该函数时,b将保留上一次的修改。
例如:
func(1) # a=1, b=[]
b.append(2)
func(3) # a=3, b=[2]
在上面的例子中,我们首先调用了func(1),然后在b上执行了append(2)操作,导致b变成了[2]。接下来,我们调用了func(3),此时a被设置为3,但b仍然是[2],而不是一个新的空列表[]。
这种行为可能会导致一些不直观的问题和bug,因为使用者可能期望每次调用函数时都会得到一个独立的空列表。
为了避免这种问题,我们可以使用None作为默认值,并在函数内部检查b是否为None,然后在需要时创建一个新的空列表。例如:
def func(a, b=None):if b is None:b = []# 现在每次函数调用都会得到一个新的空列表# 其他函数逻辑
这样做可以确保每次调用函数时都会得到一个新的空列表,避免了默认参数共享的问题。
二、是什么导致的上述问题:
这是因为在Python中,默认参数在函数定义时只会被创建一次,并且在函数的整个生命周期内都会保留它们的状态。这是为了提高函数的性能和效率。
当你定义一个函数时,Python会在函数的定义阶段创建默认参数的值,然后将这些值存储在函数的代码对象中。这意味着每次调用函数时,不会重新创建默认参数的新实例,而是会重用已经存在的默认参数。
这种行为有一些优点和一些潜在的陷阱:
优点:
- 提高了函数的性能,因为不需要每次函数调用都创建新的默认参数对象。
- 可以实现一些有用的功能,例如在多次函数调用之间共享状态。这可以在某些情况下很有用。
潜在的陷阱:
- 如果默认参数是可变对象(如列表或字典),并且在函数内部进行了修改,那么这些修改会在后续函数调用中保留下来,可能导致不直观的行为。
- 开发者需要谨慎处理默认参数,以避免意外共享状态的问题。
要避免默认参数共享状态的问题,可以使用None作为默认参数的值,并在函数内部检查并创建新的实例,如上解决的方法所示。
总之,Python的默认参数在函数定义时只会被创建一次,这是出于性能和实现的考虑,但在使用可变对象作为默认参数时需要特别小心,以避免不希望的副作用。
第二题:
val = [lambda: i + 1 for i in range(10)]data = val[0]()
print(data)
这道面试题涉及到Python中的lambda函数和列表推导式,并且可能会引发一个常见的陷阱,即闭包与变量作用域的问题。
将上述代码拆开来看:
def a():return i + 1s = []
for i in range(10):s.append(a)print(s[0]())
相信很多小伙伴看到上述拆开的代码都已经能理解本道面试题的精髓所在了。
但也请继续看下原理,是否和你想的一样~
讲解原理:
首先,列表推导式 [lambda: i + 1 for i in range(10)]
创建了一个包含 10 个 lambda 表达式的列表,每个 lambda 表达式在调用时都会返回 i + 1 的值。**需要注意的是这里每个 lambda 表达式都是一个闭包,它们“记住”了变量 i 的值。 然而,关键之处在于 lambda 表达式记住的是变量 i 而非 i 当时的值。**由于列表推导式内的 i 是在单个作用域内循环的,因此当列表推导式结束时,i 的值将停留在最后一次循环的值,即 9。 之后的代码 data = val[0]
选择列表中的第一个 lambda 函数并调用它。因为所有的 lambda 闭包都是对同一个 i 的引用,这时 i 的值是循环结束时的值 9。因此,无论调用列表中的哪一个 lambda 表达式,它都能返回 9 + 1,即 10。
这是因为,**在 Python 的 for 循环中,循环变量 i 会被绑定到列表推导式的外部作用域,而不是每次迭代都创建一个新的作用域。**所以,所有的 lambda 表达式都引用着同一个 i 变量,而在循环结束时,i 的值为 9。 要让每个 lambda 表达式保留它被定义时的 i 值,可以使用默认参数来捕获i的值,以确保每个lambda函数都捕获到不同的值:
val = [lambda i=i: i + 1 for i in range(10)]data = val[0]()
print(data)
上面修改后的代码中,lambda i=i: i + 1
为每个 lambda 函数创建了一个默认参数 i,它的值在定义 lambda 函数时就被确定下来了。这时,val[0]
会输出 1,因为它将使用列表推导式中第一次迭代时 i 的值,即 0,然后加 1。
第三题:
老生常谈,请讲一讲迭代器,生成器,可迭代对象,装饰器,并讲一下它们各自的应用场景。
首先,迭代器(Iterator)、生成器(Generator)、可迭代对象(Iterable)都与遍历数据集合相关,但各有特点,所以放一起讲:
1.1 迭代器(Iterators):
迭代器是遵循迭代器协议的对象,这意味着迭代器对象需要实现两个方法:__iter__()
和 __next__()
。__iter__()
返回迭代器对象本身,而 __next__()
方法返回容器中的下一个元素。当迭代器中没有更多元素时,__next__()
应该抛出一个 StopIteration 异常。迭代器允许一个对象对一组数据进行遍历,但不需要此数据在内存中完全展开。
-
Python的内置容器类型:
如列表、元组、字典等,都提供了迭代器。例如,当你在列表上调用
__iter__()
函数时,会返回一个迭代器,该迭代器可以遍历列表的所有元素。 -
使用场景:
当需要访问集合中的元素而不暴露底层表示时;
当需要一个能够记住遍历位置的对象时,以便在需要时能够从同一位置继续。
1.2 生成器(Generators):
生成器是一种特殊的迭代器,更容易编写。**当需要一次一个地按顺序生成一个序列的值时,使用生成器是非常有用的。**生成器函数使用 yield 语句,每次产生(yield)一个值,函数的状态会被挂起,直到下一个值被请求时再恢复。 生成器表达式是另一种构建生成器的方式,它看起来像列表推导式,但使用圆括号而不是方括号。
-
使用场景:
当需要一个懒序列(lazy sequence),该序列按需计算元素而不是预先计算,并且不希望一次性加载所有元素到内存中;
当处理的是流式数据或大数据集合,只需要一次处理一部分数据;
当需要一个函数来生成无穷序列下的元素。
1.3 可迭代对象(Iterables):
可迭代对象是实现了 __iter__()
方法的任何 Python 对象,__iter__()
需要返回一个迭代器。另外,可迭代对象也可以实现 __getitem__()
方法,以便按照索引访问元素。字符串、列表等 Python 标准类型都是可迭代的。
class Demo(object):def __iter__(self):return iter([1, 2, 3])obj = Demo()
-
使用场景:
在使用 for 循环时,你通常会迭代一个可迭代对象;
当需要一种方式可以一次访问一组元素,而无需将它们全部保存在内存中;
在使用 map()、filter()、sum()、min()、max() 等内置函数时,这些函数接受一个可迭代对象作为参数
1.4 总结一下:
在 Python 中,迭代器、生成器和可迭代对象是集合数据访问的三个基本概念。迭代器提供了一种通用的遍历集合数据的方法,而生成器提供了一种生成迭代数据的简洁方式,可迭代对象则定义了可以生成迭代器的对象。它们的共同目的是为了在保持代码简洁的同时,有效地处理数据集合,尤其是在数据量非常大或者是无限的情况下。 理解并掌握这些概念对于编写高效和可读性高的 Python 代码非常重要。每个概念都在数据处理和控制流的抽象中扮演着关键角色,并广泛应用于数据分析领域、系统操作领域和网络编程等领域。
2.0 装饰器(Decorator):
装饰器是Python中的一种高级编程特性,**它允许你在不修改原始函数代码的情况下,动态地增强或修改函数的行为。**装饰器通常用于代码重用、添加功能、修改函数的输入/输出等方面,它是Python函数式编程的一部分,非常强大和灵活。
-
函数装饰器:
- 装饰器本质上是一个Python函数,它接受一个函数作为参数,并返回一个新的函数。
- 装饰器函数通常在函数定义之前使用
@
符号来装饰目标函数。 - 装饰器的主要作用是在不修改原函数代码的情况下,为函数添加额外的功能或修改其行为。
-
装饰器示例:
下面是一个简单的装饰器示例,它用于测量函数的执行时间:import timedef timing_decorator(func):def wrapper(*args, **kwargs):start_time = time.time()result = func(*args, **kwargs)end_time = time.time()print(f"{func.__name__} took {end_time - start_time} seconds to execute.")return resultreturn wrapper@timing_decorator def my_function():# Some time-consuming tasktime.sleep(2)my_function()
在这个示例中,
timing_decorator
装饰器测量了my_function
函数的执行时间,而不需要修改my_function
的源代码。 -
多个装饰器:
你可以为一个函数应用多个装饰器,它们按照从上到下的顺序执行。这允许你将不同的功能组合在一起,以增强函数的行为。@decorator1 @decorator2 def my_function():# ...# 等效于 my_function = decorator1(decorator2(my_function))
-
内置装饰器:
Python提供了一些内置装饰器,如@staticmethod
和@classmethod
,用于定义静态方法和类方法。这些装饰器可以用于类中的方法,以提供不同类型的方法调用。class MyClass:def __init__(self, value):self.value = value@staticmethoddef static_method():print("This is a static method")@classmethoddef class_method(cls):print("This is a class method")obj = MyClass(42) obj.static_method() obj.class_method()
-
自定义装饰器:
你可以自己编写装饰器函数,以满足特定需求。通常,自定义装饰器需要接受函数作为参数,并返回一个包装函数。装饰器函数可以在包装函数的前后执行自定义逻辑。
装饰器是Python中强大而灵活的工具,它们用于增强函数的功能、提供代码重用和简化代码结构。常见的装饰器包括日志记录、性能分析、权限验证、缓存等。理解和熟练使用装饰器是成为高级Python开发人员的关键一步。
相关文章:
(三十三)补充Python经典面试题(吸收高级编程特性)
第一题: def func(a, b[]): pass一、上题讲解: 这个函数定义有一个默认参数b,它的默认值是一个空列表[]。这道面试题涉及到Python中函数参数默认值的一些重要概念和陷阱。 首先,当你调用这个函数时,如果不传递参数b…...

SQL进阶理论篇(四):索引的结构原理(B树与B+树)
文章目录 简介如何评价索引的数据结构设计好坏二叉树的局限性什么是B树什么是B树总结参考文献 简介 我们在上一节中说过,索引其实是一种数据结构,那它到底是一种什么样的数据结构呢?本节将简单介绍一下几个问题: 什么样的数据结…...

springMVC-模型数据的处理
一、数据放入到request域当中 1、把获取的数据放入request域中, 方便在跳转页面去显示 <a>添加主人信息</a> <form action"vote/vote04" method"post" >主人id:<input type"text" name"id&q…...

计算机组成原理-微指令的设计与微程序控制单元的设计
文章目录 微指令的设计微指令的格式微指令的编码方式水平型微指令的操作控制部分的编码方式直接编码字段直接编码例题字段间接编码方式 微指令的地址形成方式例题小结 微程序控制单元的设计微程序设计分类硬布线与微程序的比较 微指令的设计 微指令的格式 水平型微指令的操作…...

PyTorch机器学习与深度学习
近年来,随着AlphaGo、无人驾驶汽车、医学影像智慧辅助诊疗、ImageNet竞赛等热点事件的发生,人工智能迎来了新一轮的发展浪潮。尤其是深度学习技术,在许多行业都取得了颠覆性的成果。另外,近年来,Pytorch深度学习框架受…...

羊奶vs牛奶,羊大师告诉你谁是更营养的选择?
羊奶vs牛奶,羊大师告诉你谁是更营养的选择? 羊奶和牛奶是两种常见的乳制品,它们不仅在口味上有所差异,而且在营养成分方面也存在一些差异。本文将对羊奶和牛奶的营养成分进行全面对比,旨在帮助读者更好地了解这两种乳…...

机器学习之线性回归(Linear Regression)
概念 线性回归(Linear Regression)是机器学习中的一种基本的监督学习算法,用于建立输入变量(特征)与输出变量(目标)之间的线性关系。它假设输入变量与输出变量之间存在线性关系,并试图找到最佳拟合线来描述这种关系。 在简单线性回归中,只涉及两个变量:一个是自变量…...

ChatGPT与ArcGIS PRO 如何结合,打造一个全新的工作流程
在地学领域,ArcGIS几乎成为了每位科研工作者作图、数据分析的必备工具,而ArcGIS Pro3除了良好地继承了ArcMap强大的数据管理、制图、空间分析等能力,还具有二三维融合、大数据、矢量切片制作及发布、任务工作流、时空立方体等特色功能&#x…...

【深度学习】对比学习的损失函数
前言 对比学习损失(Contrastive Learning Loss)是一种用于自监督学习的损失函数。它侧重于学习一个特征空间,其中相似的样本被拉近,而不相似的样本被推远。在二分类任务中,对比学习损失可以用来学习区分正负样本的特征…...

哈夫曼解码
【问题描述】 给定一组字符的Huffman编码表(从标准输入读取),给定一个用该编码表进行编码的Huffman编码文件(存在当前目录下的in.txt中),编写程序对Huffman编码文件进行解码。 例如给定的一组字符的Huffm…...

Excel小技能:excel如何将数字20231211转化成指定日期格式2023/12/11
给了一串数字20231211,想要转成指定格式的日期格式,发现设置单元格格式为指定日期格式不生效,反而变成很长很长的一串#这个,如图所示: 其实,正确的做法如下: 1)打开数据功能界面&am…...

Selenium自动化测试框架(超详细总结分享)
设计思路 本文整理归纳以往的工作中用到的东西,现汇总成基础测试框架提供分享。 框架采用python3 selenium3 PO yaml ddt unittest等技术编写成基础测试框架,能适应日常测试工作需要。 1、使用Page Object模式将页面定位和业务操作分开ÿ…...

STM32 DAC+串口
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 前言一、DAC是什么?二、STM32 DAC1.什么型号有DAC2. 简介3. 主要特点4. DAC框图5. DAC 电压范围和引脚 三、程序步骤1. 开启DAC时钟2. 配置引脚 PA4 PA5…...

SolidWorks二次开发 C#-读取基于Excel的BOM表信息
SolidWorks二次开发 C#-读取基于Excel的BOM表信息 问题点来源解决方案及思路相关引用链接 问题点来源 这是一位粉丝问的一个问题,他说到: 老师,请问Solidworks二次开发工程图中"基于Excel的材料明细表"怎么读取里面的数据? Ps:这…...

maui中实现加载更多 RefreshView跟ListView(2)
一个类似商品例表的下拉效果: 代码 新增个类为商品商体类 public class ProductItem{public string ImageSource { get; set; }public string ProductName { get; set; }public string Price { get; set; }}界面代码: <?xml version"1.0&quo…...

win10环境下git安装和基础操作
简述 关于git的作用就不多赘述了,配合GitHub,达到方便人们日常项目维护和管理,每一次项目增删改查都可以看的清清楚楚,方便团队协作和个人项目日常维护。 下载git 首先我们自然是要到官网下载git,下载地址为https:/…...

将yolo格式转化为voc格式:txt转xml(亲测有效)
1.文件目录如下所示: 对以上目录的解释: 1.dataset下面的image文件夹:里面装的是数据集的原图片 2.dataset下面的label文件夹:里面装的是图片对应得yolo格式标签 3.dataset下面的Annotations文件夹:这是一个空文件夹&…...
字符串 - 541.反转字符串II(C#和C实现)
字符串 - 541.反转字符串II(C#和C实现) 题目描述 给定一个字符串 s 和一个整数 k,你需要对从字符串开头算起的每隔 2k 个字符的前 k 个字符进行反转。 如果剩余字符少于 k 个,则将剩余字符全部反转。如果剩余字符小于 2k 但大于或等于 k 个࿰…...

机器视觉技术与应用实战(开运算、闭运算、细化)
开运算和闭运算的基础是膨胀和腐蚀,可以在看本文章前先阅读这篇文章机器视觉技术与应用实战(Chapter Two-04)-CSDN博客 开运算:先腐蚀后膨胀。开运算可以使图像的轮廓变得光滑,具有断开狭窄的间断和消除细小突出物的作…...
云原生之深入解析云原生架构的日志监控
一、什么是云原生架构的日志监控? 云原生架构的日志监控要求现代 Web 应用程序采用与传统应用程序略有不同的方法。部分原因是应用程序环境要复杂得多,包括从微服务中获取数据、使用 Kubernetes 和其他容器技术,以及在许多情况下集成开源组件…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
JDK 17 新特性
#JDK 17 新特性 /**************** 文本块 *****************/ python/scala中早就支持,不稀奇 String json “”" { “name”: “Java”, “version”: 17 } “”"; /**************** Switch 语句 -> 表达式 *****************/ 挺好的ÿ…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...

C# 表达式和运算符(求值顺序)
求值顺序 表达式可以由许多嵌套的子表达式构成。子表达式的求值顺序可以使表达式的最终值发生 变化。 例如,已知表达式3*52,依照子表达式的求值顺序,有两种可能的结果,如图9-3所示。 如果乘法先执行,结果是17。如果5…...

PHP 8.5 即将发布:管道操作符、强力调试
前不久,PHP宣布了即将在 2025 年 11 月 20 日 正式发布的 PHP 8.5!作为 PHP 语言的又一次重要迭代,PHP 8.5 承诺带来一系列旨在提升代码可读性、健壮性以及开发者效率的改进。而更令人兴奋的是,借助强大的本地开发环境 ServBay&am…...

手机平板能效生态设计指令EU 2023/1670标准解读
手机平板能效生态设计指令EU 2023/1670标准解读 以下是针对欧盟《手机和平板电脑生态设计法规》(EU) 2023/1670 的核心解读,综合法规核心要求、最新修正及企业合规要点: 一、法规背景与目标 生效与强制时间 发布于2023年8月31日(OJ公报&…...

Elastic 获得 AWS 教育 ISV 合作伙伴资质,进一步增强教育解决方案产品组合
作者:来自 Elastic Udayasimha Theepireddy (Uday), Brian Bergholm, Marianna Jonsdottir 通过搜索 AI 和云创新推动教育领域的数字化转型。 我们非常高兴地宣布,Elastic 已获得 AWS 教育 ISV 合作伙伴资质。这一重要认证表明,Elastic 作为 …...

数据结构:递归的种类(Types of Recursion)
目录 尾递归(Tail Recursion) 什么是 Loop(循环)? 复杂度分析 头递归(Head Recursion) 树形递归(Tree Recursion) 线性递归(Linear Recursion)…...

使用SSE解决获取状态不一致问题
使用SSE解决获取状态不一致问题 1. 问题描述2. SSE介绍2.1 SSE 的工作原理2.2 SSE 的事件格式规范2.3 SSE与其他技术对比2.4 SSE 的优缺点 3. 实战代码 1. 问题描述 目前做的一个功能是上传多个文件,这个上传文件是整体功能的一部分,文件在上传的过程中…...