Python面试中的常见陷阱
在Python面试中,面试官经常会设置一些看似简单实则暗藏玄机的问题。这些问题不仅考察你的基础知识,更考验你对Python特性的深入理解。今天我们就来揭秘几个常见的Python面试陷阱,帮助你轻松应对面试挑战。
可变对象作为默认参数
def add_item(item, lst=[]):
lst.append(item)
return lst
print(add_item(1)) # 输出: [1]
print(add_item(2)) # 输出: [1, 2]
这个例子中,很多人会惊讶地发现第二次调用add_item时,默认参数lst保留了第一次调用时的值。这是因为Python中默认参数在函数定义时就被创建,并在所有函数调用之间共享。
正确的做法是:
def add_item(item, lst=None):
if lst is None:
lst = []
lst.append(item)
return lst
闭包中的变量绑定
def create_functions():
functions = []
for i in range(3):
functions.append(lambda x: x + i)
return functions
for f in create_functions():
print(f(0)) # 输出: 2, 2, 2
这里所有函数都引用了循环变量i,而i在循环结束时值为2,所以所有函数都使用了这个最终值。
正确的做法是使用默认参数来捕获当前值:
def create_functions():
functions = []
for i in range(3):
functions.append(lambda x, i=i: x + i)
return functions
列表推导式与生成器表达式
# 列表推导式
squares = [x2 for x in range(1000000)]
生成器表达式
squares_gen = (x2 for x in range(1000000))
列表推导式会立即创建整个列表并占用内存,而生成器表达式则是惰性求值,只在需要时才计算下一个值。在处理大量数据时,生成器表达式可以显著减少内存使用。
浅拷贝与深拷贝
import copy
list1 = [1, [2, 3], 4]
list2 = list1.copy() # 浅拷贝
list3 = copy.deepcopy(list1) # 深拷贝
list1[1][0] = a
print(list2) # 输出: [1, [a, 3], 4]
print(list3) # 输出: [1, [2, 3], 4]
浅拷贝只复制对象的第一层,而深拷贝会递归复制所有嵌套对象。在处理包含嵌套结构的对象时,理解这两种拷贝的区别至关重要。
GIL与多线程
import threading
import time
def cpu_bound_task():
for i in range(10000000):
pass
单线程
start = time.time()
cpu_bound_task()
print(f单线程耗时: {time.time()
多线程
start = time.time()
threads = [threading.Thread(target=cpu_bound_task) for _ in range(4)]
for t in threads:
t.start()
for t in threads:
t.join()
print(f多线程耗时: {time.time()
由于Python的全局解释器锁(GIL),多线程在CPU密集型任务上可能不会带来性能提升,甚至可能因为线程切换开销而变慢。对于CPU密集型任务,应该考虑使用多进程。
装饰器的执行顺序
def decorator1(func):
print(装饰器1被调用)
def wrapper():
print(装饰器1的wrapper被调用)
return func()
return wrapper
def decorator2(func):
print(装饰器2被调用)
def wrapper():
print(装饰器2的wrapper被调用)
return func()
return wrapper
@decorator1
@decorator2
def hello():
print(Hello, World!)
hello()
装饰器的执行顺序是从下到上,而调用顺序是从上到下。理解这一点对于调试复杂的装饰器链非常重要。
元类与类创建过程
class Meta(type):
def __new__(cls, name, bases, attrs):
print(f创建类: {name})
return super().__new__(cls, name, bases, attrs)
class MyClass(metaclass=Meta):
pass
元类是类的类,它控制类的创建过程。理解元类可以帮助你掌握Python的类创建机制,这在框架开发中非常有用。
上下文管理器与with语句
class ResourceManager:
def __enter__(self):
print(获取资源)
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print(释放资源)
return False # 返回False会重新抛出异常
with ResourceManager() as res:
print(使用资源)
# 如果这里发生异常,__exit__仍然会被调用
上下文管理器是Python中优雅处理资源获取和释放的方式,理解__enter__和__exit__方法的工作机制对于编写健壮的代码至关重要。
属性查找顺序(MRO)
class A:
def method(self):
print(A.method)
class B(A):
def method(self):
print(B.method)
class C(A):
def method(self):
print(C.method)
class D(B, C):
pass
d = D()
d.method() # 输出: B.method
print(D.__mro__) # 输出: (, , , , )
Python使用C3线性化算法来确定方法解析顺序(MRO)。理解MRO对于解决复杂的继承问题非常重要。
迭代器与生成器
# 迭代器
class Counter:
def __init__(self, limit):
self.limit = limit
self.counter = 0
def __iter__(self):
return self
def __next__(self):
if self.counter < self.limit:
self.counter += 1
return self.counter
raise StopIteration
生成器
def counter(limit):
count = 0
while count < limit:
count += 1
yield count
使用迭代器
for num in Counter(5):
print(num)
使用生成器
for num in counter(5):
print(num)
迭代器和生成器是Python中处理序列的强大工具。理解它们的区别和工作原理可以帮助你编写更高效的代码。
暂无评论内容