Python常见面试题
·
1. Python有哪些内置数据类型?
- 常见的有:
int,float,bool,str,list,tuple,dict,set。
2. Python中列表和元组的区别?
- 列表(list)可变,可增删改;元组(tuple)不可变,定义后不能修改。
3. Python的深拷贝和浅拷贝有什么区别?
- 浅拷贝复制对象的引用,改变子对象会影响原对象。
- 深拷贝复制对象及其所有子对象,完全独立。
浅拷贝(shallow copy)
import copy
original = [1, 2, [3, 4]]
shallow_copied = copy.copy(original)
print("原始列表:", original)
print("浅拷贝列表:", shallow_copied)
# 修改浅拷贝内嵌列表
shallow_copied[2].append(5)
print("\n修改浅拷贝后的原始列表:", original)
print("修改浅拷贝后的浅拷贝列表:", shallow_copied)
输出:
原始列表: [1, 2, [3, 4]]
浅拷贝列表: [1, 2, [3, 4]]
修改浅拷贝后的原始列表: [1, 2, [3, 4, 5]]
修改浅拷贝后的浅拷贝列表: [1, 2, [3, 4, 5]]
可以看到,修改了浅拷贝的内嵌列表,原始列表也会改变,因为它们共享内嵌列表对象。
深拷贝(deep copy)
import copy
original = [1, 2, [3, 4]]
deep_copied = copy.deepcopy(original)
print("原始列表:", original)
print("深拷贝列表:", deep_copied)
# 修改深拷贝内嵌列表
deep_copied[2].append(5)
print("\n修改深拷贝后的原始列表:", original)
print("修改深拷贝后的深拷贝列表:", deep_copied)
输出:
原始列表: [1, 2, [3, 4]]
深拷贝列表: [1, 2, [3, 4]]
修改深拷贝后的原始列表: [1, 2, [3, 4]]
修改深拷贝后的深拷贝列表: [1, 2, [3, 4, 5]]
这里修改深拷贝对象里的内嵌列表,原始列表保持不变。
探究浅拷贝和对象赋值
我们常见的代码赋值写法
b = [1, 2, 3]
a = b
这是让变量a和b指向同一个列表对象,a和b引用的是内存中同一个列表,通过a修改列表内容,b也会看到变化,反之亦然。这种效果类似于浅拷贝,但实际意义不同。a=b是指向同一个对象,也就是指向的内存地址是完全一样的, 但浅拷贝a、b就分别指向不同的列表对象
那这就有个疑问了:浅拷贝会改变原始列表的值有啥用处啊,为啥不干脆直接修改原始列表?
这是个很好的问题!浅拷贝看起来修改了拷贝里的可变子对象会影响原始对象,似乎没啥用——但它其实有几个实际场景和意义:
1.避免改变顶层对象,但允许共享子对象
浅拷贝创建了新的顶层容器(比如新的列表对象),这样你在拷贝的容器上添加、删除、替换元素不会影响原始容器;但子对象仍共享,节省了内存。
import copy
original = [[1, 2], [3, 4]]
shallow = copy.copy(original)
# 改变顶层结构
shallow.append([5, 6])
print(original) # 原始列表不变
# 改变子对象内容
shallow[0].append(99)
print(original) # 子对象被修改,原始列表看到变化
这样做的用处在于:
- 比如你想临时拓展原始列表而不影响它结构,但又想共享子数据避免内存消耗。
- 或者顶层改变独立,子对象共享,方便节省资源。
2. 性能和内存考虑
- 深拷贝会递归复制所有子对象,时间和空间开销大。
- 浅拷贝只复制最外层对象,速度快,适合不需要递归复制的情况。
3. 某些场景必须共享子对象
有时候子对象本身就是“不可分割的状态”,希望在多个结构中共享更新,比如共享缓存、配置、连接池等。
4. 区别“修改结构”和“修改内容”
- 修改结构(如添加、删除元素)在浅拷贝副本是独立的,不影响原始列表。
- 修改内容(如修改子列表里的元素)共享,会影响原始。
这提供了更灵活的设计空间,可以根据需求控制修改的影响范围。
4. 什么是Python的GIL(全局解释器锁)?
- GIL使得同一时刻只有一个线程在执行Python字节码,限制多线程并发,影响CPU密集型任务。
5. Python装饰器是什么?怎么使用?
- 装饰器是用于修改函数或类行为的高阶函数,通常使用
@decorator语法调用。
6. 列表推导式写法示例?
squares = [x**2 for x in range(10)]
它的含义是:对 range(10) 里的每个 x,计算 x 的平方,生成一个列表。
range(10) 生成 [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],把每个元素平方
所以,squares 的结果是:
[0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
7. Python如何实现多线程和多进程?
- 多线程用
threading模块;多进程用multiprocessing模块。
8. Python中如何管理内存?
- Python采用引用计数和垃圾回收(GC)机制管理内存。
9. 什么是迭代器和生成器?
- 迭代器是实现了
__iter__和__next__方法的对象;生成器用yield生成迭代器,支持惰性求值。
迭代器示例:
class MyIterator:
def __init__(self, data):
self.data = data
self.index = 0
def __iter__(self):
return self # 迭代器返回自己
def __next__(self):
if self.index < len(self.data):
val = self.data[self.index]
self.index += 1
return val
else:
raise StopIteration # 到尾部时抛出异常
# 使用迭代器
iter_obj = MyIterator([10, 20, 30])
for num in iter_obj:
print(num)
生成器示例(用 yield)
def my_generator():
yield 10
yield 20
yield 30
# 使用生成器
for num in my_generator():
print(num)
| 特点 | 迭代器 | 生成器 |
|---|---|---|
| 定义 | 通过类实现,定义 __iter__ 和 __next__ | 通过函数和 yield 语句 |
| 使用复杂度 | 相对复杂,需要手写类和方法 | 简洁,写函数即可 |
| 内存效率 | 少量数据时无需特殊考虑 | 生成时才计算,更省内存 |
| 适用场景 | 自定义复杂数据结构的遍历 | 惰性生成数据,简化迭代实现 |
10. 类和实例之间的区别?
- 类是对象模板,定义属性和方法;实例是类的具体对象,有独立状态。
11. Python中*args和**kwargs的作用?
*args传递可变数量的位置参数,**kwargs传递可变数量的关键字参数。
示例
def func(*args):
print("args =", args)
for i, val in enumerate(args):
print(f"arg {i}: {val}")
func(1, 2, 3)
def func(**kwargs):
print("kwargs =", kwargs)
for key, val in kwargs.items():
print(f"{key} = {val}")
func(a=1, b=2, c=3)
12. Python中如何捕获异常?
python
复制
try:
x = int(input("请输入一个整数: "))
result = 10 / x
except ValueError:
print("捕获 ValueError,输入的不是有效整数")
except ZeroDivisionError:
print("捕获 ZeroDivisionError,除数不能为零")
except Exception as e:
print("捕获其他异常:", e)
else:
print("计算结果是:", result)
except ValueError:处理转换整数失败的异常except ZeroDivisionError:处理除以零异常except Exception as e:处理其他未捕获的异常(可选)else:当没有异常发生时执行finally:如果需要,无论有没有异常都会执行的代码可以写在这里
13. Python字典的底层实现?
- 字典采用哈希表实现,键必须是可哈希(不可变)类型。
14. 怎么判断一个对象是否是某个类的实例?
isinstance(obj, ClassName)
15. Python的with语句作用?
- 用于简化资源管理,实现上下文管理器协议,自动释放资源。
class MyContext:
def __enter__(self):
print("进入上下文")
return "资源"
def __exit__(self, exc_type, exc_value, traceback):
print("离开上下文")
with MyContext() as resource:
print(f"使用{resource}")
输出:
进入上下文
使用资源
离开上下文
16. Python中的多继承是什么?有什么问题?
- 一个类继承多个父类,可能引起方法解析顺序(MRO)混乱,需注意调用顺序。
什么是 MRO 混乱?
- 当多个父类存在重叠继承关系,或者继承结构复杂时,Python 需要根据一定规则合并各个类的方法查找顺序。
- 如果继承关系设计不当,Python 可能无法推导出一个满足所有父类继承约束的线性顺序,会报错
TypeError: Cannot create a consistent method resolution order (MRO)。 - 这就是所谓的 MRO 混乱。
代码示例展示 MRO 混乱导致的错误
class A:
pass
class B(A):
pass
class C(A):
pass
# 下面这个类继承顺序冲突,会报错
class D(B, C):
pass
class E(C, B):
pass
class F(D, E): # 这里继承冲突,MRO 无法解析,会报错
pass
一个正常的多继承 MRO 示例
class X:
def greet(self):
print("Hello from X")
class Y(X):
def greet(self):
print("Hello from Y")
class Z(X):
def greet(self):
print("Hello from Z")
class M(Y, Z):
pass
obj = M()
obj.greet()
print(M.mro())
输出:
Hello from Y
[<class '__main__.M'>, <class '__main__.Y'>, <class '__main__.Z'>, <class '__main__.X'>, <class 'object'>]
- 多继承时,Python 用 C3 算法计算 MRO。
- 如果继承链设计巧妙、顺序合理,MRO 是清晰且唯一的。
- 如果父类继承顺序冲突,就会报 MRO 混乱错误。
- 设计多继承时尽量避免复杂的菱形继承和顺序不一致。
17. Python中lambda表达式如何使用?
- 匿名函数,语法:
lambda 参数: 表达式,适合小函数。
square = lambda x: x ** 2
print(square(5)) # 输出 25
nums = [1, 2, 3, 4, 5, 6]
evens = list(filter(lambda x: x % 2 == 0, nums))
print(evens) # 输出 [2, 4, 6]
18. Python中如何读取和写入文件?
# 读取整个文件内容
with open('example.txt', 'r', encoding='utf-8') as f:
content = f.read()
print(content)
with open('example.txt', 'r', encoding='utf-8') as f:
for line in f:
print(line.strip()) # strip去掉行尾换行符
with open('output.txt', 'w', encoding='utf-8') as f:
f.write("这是写入文件的内容。\n")
f.write("支持中文字符。\n")
with open('output.txt', 'a', encoding='utf-8') as f:
f.write("追加一行内容。\n")
19. Python支持哪些内置数据结构?
- 列表(list)、元组(tuple)、字典(dict)、集合(set)。
20. Python中常见的标准库有哪些?
os,sys,re,json,datetime,collections,itertools,threading等。
更多推荐



所有评论(0)