Python常见面试题001-005,涉及深浅拷贝、MRO、函数可变参数、作用域、is和==的区别等
1|0Python常见面试题001-005
参考资料
https://github.com/taizilongxu/interview_python
https://github.com/hantmac/Python-Interview-Customs-Collection
https://github.com/kenwoodjw/python_interview_question
有些来自上面(但我也做了自己的补充),有些来自网络或书籍
本文不准备写编程题,偏重于理论一些。你要的话去刷leetcode就是了。
倒序描述,限于篇幅,可能要连载
2|0005. 说说你对浅拷贝、深拷贝的理解
- 浅拷贝 shallow copy
- 深拷贝 deep copy
2|1浅拷贝
-
第一次见浅拷贝是在
-
list列表的copy方法,那浅拷贝到底是怎样的行为表现呢?
-
示例代码
-
来看这段
-
在第一个例子中
- 来看看其他的浅拷贝方式
切片
-
可变序列的切片创建了一个浅拷贝,不可变序列的切片创建了一个引用
- 浅拷贝,是指重新分配一块内存,创建一个新的对象,里 面的元素是原对象中子对象的引用。因此,如果原对象中的元素不可变,那倒无所谓;但如果元 素可变,浅拷贝通常会带来一些副作用
构造器
-
常见的浅拷贝的方法,是使用数据类型本身的构造器
copy.copy()
-
copy.copy则可以用于任意的数据类型的浅拷贝
-
示例代码
特殊情况
-
来看下面的这些例子
-
按照前面的理解,list构造器会产生浅拷贝
-
按理说l1的变化不会影响到l2
-
但事实是影响了
-
仔细看会发现,line3没有改变,line4改变了
-
再看一个操作
-
完整的解释
-
你可以这样验证
-
至此你应该发现了浅拷贝的一些副作用
2|2深拷贝
-
深拷贝来自copy模块的deepcopy方法
-
同样看上面的例子
-
好像deepcopy很完美?
-
复制的时候的确不希望互相影响
-
但deepcopy有它的弊端:如果被拷贝对象中存在指向自身的引 用,那么程序很容易陷入无限循环
2|3官方解释
-
Python 的赋值语句不复制对象,而是创建目标和对象的绑定关系
-
对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象。本模块提供了通用的浅层复制和深层复制操作
- copy.copy(x) 浅层复制
- copy.deepcopy(x) 深层复制
-
浅层与深层复制的区别仅与复合对象(即包含列表或类的实例等其他对象的对象)相关:
- 浅层复制 构造一个新的复合对象,然后(在尽可能的范围内)将原始对象中找到的对象的 引用 插入其中。
- 深层复制 构造一个新的复合对象,然后,递归地将在原始对象里找到的对象的 副本 插入其中。
-
深度复制操作通常存在两个问题, 而浅层复制操作并不存在这些问题:
- 递归对象 (直接或间接包含对自身引用的复合对象) 可能会导致递归循环。
- 由于深层复制会复制所有内容,因此可能会过多复制(例如本应该在副本之间共享的数据)
-
deepcopy() 函数用以下方式避免了这些问题:
- 保留在当前复制过程中已复制的对象的 "备忘录" (
memo
) 字典;以及 - 允许用户定义的类重载复制操作或复制的组件集合
- 保留在当前复制过程中已复制的对象的 "备忘录" (
-
下面这个案例说明了一点什么
- 按理说y会无限循环,堆栈溢出,但实际上并没有,还是deepcopy做了一些事情规避的
3|0004. 请说出下面代码的返回结果是什么?
参考了 https://www.liujiangblog.com/course/python/44
如有侵权,联系删除
-
示例代码1
-
结果
-
你可以整理出这样的一个继承关系
-
从执行结果看先走 是A(B,E)中左侧的B这个分支:可见,在A的定义中,继承参数的书写有先后顺序,写在前面的被优先继承。
-
你可以查看A的__mro__属性
-
如果你改成这样
-
顺序自然成了这样
-
继承关系下的搜索顺序
-
所以,把代码改为这样,输出你应该毫无疑问了
-
那么这样呢?
-
继承关系是这样的
-
答案是
-
看MRO
-
所以继承树的搜索顺序是这样的
-
而所有的继承其实都是这2种图形的变化
-
比如这样的代码
-
你先分析下应该输出啥,继承树是怎样的,MRO是如何的?
-
输出
-
继承树
-
MRO
-
关于类的继承
- 子类在调用某个方法或变量的时候,首先在自己内部查找,如果没有找到,则开始根据继承机制在父类里查找。
- 根据父类定义中的顺序,以深度优先的方式逐一查找父类!
- 子类永远在父类前面,如果有多个父类,会根据它们在列表中的顺序被检查,如果对下一个类存在两个合法的选择,选择第一个父类
-
MRO:即Method Resolution Order(方法解析顺序)
-
从Python 2.3开始计算MRO一直是用的C3算法
-
C3算法的简单解释可以参考码农高天的这个视频:https://www.bilibili.com/video/BV1V5411S7dY
4|0003. 请说出下面的代码返回结果是什么?为何?如何改进?
知识点: 函数参数的类型
-
示例代码
-
据说是国内某上市互联网公司Python面试真题(略作改动),而实际在python的官网也有
-
烂大街了
-
典型的错误答案
-
实际的答案
-
因为Python函数体在被读入内存的时候,默认参数a指向的空列表对象就会被创建,并放在内存里了。因为默认参数a本身也是一个变量,保存了指向对象[]的地址。每次调用该函数,往a指向的列表里添加一个A。a没有变,始终保存的是指向列表的地址,变的是列表内的数据!
-
修改
-
官网的重要警告: 默认值只计算一次。默认值为列表、字典或类实例等可变对象时,会产生与该规则不同的结果
-
这样的代码
-
上面的函数会累积后续调用时传递的参数
-
不想在后续调用之间共享默认值时,建议用None这样的不可变对象来存储
5|0002. 请分别说出下面的代码返回结果是什么?为何?
知识点: 作用域
-
示例代码1
-
示例代码2
-
示例代码3
-
示例代码1的执行结果
-
示例代码2的执行结果
-
示例代码3的执行结果
解释3
- Python 编译函数的定义体时,它判断 b 是局部变量,依据是y=2,你对它进行了赋值。Python 会尝试从本地环境获取 b。
- 后面调用 func(1)时,func的定义体会获取并打印局部变量x 的值,但是尝试获取局部变量 y 的值时,发现 y 没有 绑定值就报错了。
- 这不是缺陷,这是设计如此(做测试是不是经常听到这句话)
- Python 不要求声明变量,但是假定在函数定义体中赋值的变 量,那就认为它是局部变量
对于代码3的处理
-
示例代码3(更改)
-
这样解释器就会把 y 当成全局变量,从而找到第一行的y=1并print出来了
从函数的字节码也能看出来这个过程
-
代码1
-
字节码
-
示例代码2
-
字节码
-
示例代码3
-
字节码
-
示例代码3(更改)
-
字节码
看不懂字节码不要紧的,当然非要,你可以去参考https://docs.python.org/zh-cn/3/library/dis.html
作用域LEGB相关知识单独考虑弄个博文
6|0001. is和==有什么区别
-
==是对象的值的比较,也就是对象保存的数据。
-
is比较的是对象的标识。
-
示例代码1
-
is的背后是id,is比较为True,说明2个id的返回是一样的
-
在 CPython 中,id() 返回对象的内存地址, 但是在其他 Python 解释器中可能是别的值。关键是,ID 一定是唯一的数值标注,而且在 对象的生命周期中绝不会变。
上面的话引自 <流畅的python> 8.2 标识、相等性、别名
这些知识涉及对象的引用,相关的面试题如浅拷贝/深拷贝、重载运算符(==)等
浅拷贝也考虑单独剥离弄个博文或主题
-
示例代码2
-
这是因为出于对性能优化的考虑,Python内部会对-5到256的整型维持一个数组,起到一个缓存 的作用。这样,每次你试图创建一个-5到256范围内的整型数字时,Python都会从这个数组中返回相对应的引用,而不是重新开辟一块新的内存空间。
-
但是,如果整型数字超过了这个范围,比如上述例子中的257,Python则会为两个257开辟两块 内存区域,因此a和b的ID不一样,a is b就会返回False了。
-
比较操作符'is'的速度效率,通常要优于'=='。因为'is'操作符不能被重载,这 样,Python就不需要去寻找,程序中是否有其他地方重载了比较操作符,并去调用。执行比较操作符'is',就仅仅是比较两个变量的ID而已。
-
但是'=='操作符却不同,执行a == b相当于是去执行a.__eq__(b),而Python大部分的数据类型都 会去重载__eq_这个函数,其内部的处理通常会复杂一些。比如,对于列表,__eq_函数会去 遍历列表中的元素,比较它们的顺序和值是否相等。
__EOF__

本文链接:https://www.cnblogs.com/wuxianfeng023/p/17115981.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)