Python常见100个经典面试问题总结(从入门到进阶)
说明:本文整理了 Python 面试中常见的 100 个经典问题,覆盖基础语法、数据结构、函数、装饰器、异常、文件、迭代器、生成器、面向对象、工程化、并发、标准库、性能优化等内容。每个问题都尽量配有示例代码和真实输出,方便读者边看边练。
前言
Python 面试并不是单纯考“会不会写语法”,而是考你是否真正理解对象、数据结构、函数、异常、面向对象、装饰器、生成器、并发、性能、工程化和常见坑点。
很多候选人能写出代码,但一问:
- 为什么列表不能作为字典 key?
- 装饰器什么时候执行?
is和==有什么区别?- 线程、进程、协程怎么选?
- GIL 到底影响什么?
- 浅拷贝和深拷贝有什么区别?
就容易卡住。
本文整理 100 个 Python 高频面试问题,每个问题都配一个小例子,方便你边看边练。建议阅读方式是:先看问题,自己想 30 秒,再看答案和代码。
一、Python 基础语法与对象模型
1. Python 是解释型语言吗?
是。Python 通常由解释器执行源码或字节码,不需要像 C/C++ 那样提前编译成机器码。
但这不代表 Python 没有编译过程。.py 文件通常会先被编译成字节码,再由 Python 虚拟机执行。
print("hello python")
输出:
hello python
2. Python 中“一切皆对象”是什么意思?
变量、函数、类、模块、数字、字符串都是对象。对象通常有三个重要特征:
- 身份:可以用
id()查看 - 类型:可以用
type()查看 - 值:对象保存的数据
x = 100 print(type(x)) print(id(x))
输出示例:
<class 'int'> 140735568356104
3.is和==有什么区别?
== 比较的是两个对象的值是否相等。
is 比较的是两个变量是否引用同一个对象。
a = [1, 2] b = [1, 2] print(a == b) print(a is b)
输出:
True False
解释:
虽然 a 和 b 的值一样,但它们是两个不同的列表对象。
4. Python 中可变对象和不可变对象有什么区别?
可变对象的值可以原地修改,例如:
listdictset
不可变对象创建后不能直接修改,例如:
intfloatstrtuple
a = [1, 2] a.append(3) print(a) s = "ab" s += "c" print(s)
输出:
[1, 2, 3] abc
注意:字符串看起来被修改了,其实是创建了一个新的字符串对象。
5. 为什么列表不能作为字典 key?
因为列表是可变对象,哈希值不稳定,不能作为字典 key。
字典 key 必须是可哈希对象。常见可哈希对象包括:
- 字符串
- 数字
- 元组
- 布尔值
d = {}
# d[[1, 2]] = "value" # TypeError: unhashable type: 'list'
d[(1, 2)] = "value"
print(d)
输出:
{(1, 2): 'value'}
6.None应该如何判断?
推荐使用 is None,不要使用 == None。
value = None
if value is None:
print("value is None")
输出:
value is None
原因是 None 是一个单例对象,使用 is 更准确。
7. Python 的布尔值判断规则是什么?
以下值通常会被判断为假:
NoneFalse0""[]{}set()tuple()
values = ["", [], {}, 0, None, "python"]
for v in values:
print(bool(v))
输出:
False False False False False True
8.and和or返回的一定是布尔值吗?
不一定。它们返回的是参与运算的对象本身。
print(0 or "default")
print("python" and "ok")
输出:
default ok
这个特性经常用于默认值处理。
9. Python 中变量需要声明类型吗?
不需要。Python 是动态类型语言,变量名只是对象的引用。
x = 1 x = "hello" print(x)
输出:
hello
10. Python 的类型注解会强制校验类型吗?
不会。类型注解主要用于:
- 提高代码可读性
- 辅助 IDE 提示
- 配合 mypy、pyright 等工具做静态检查
Python 运行时默认不会强制校验类型。
def add(a: int, b: int) -> int:
return a + b
print(add("1", "2"))
输出:
12
虽然参数标注为 int,但运行时传入字符串也能执行。
二、字符串、列表、元组、字典、集合
11. 字符串如何反转?
s = "python" print(s[::-1])
输出:
nohtyp
12. 字符串拼接为什么推荐join?
循环中频繁使用 + 拼接字符串,会产生多个中间字符串对象。
大量字符串拼接时,推荐使用 join()。
words = ["Python", "is", "good"]
print(" ".join(words))
输出:
Python is good
13.split()和strip()有什么区别?
split() 用于分割字符串。
strip() 用于去除字符串首尾空白或指定字符。
s = " a,b,c "
print(s.strip())
print(s.strip().split(","))
输出:
a,b,c ['a', 'b', 'c']
14. 列表推导式是什么?
列表推导式可以用简洁语法生成列表。
nums = [x * x for x in range(5)] print(nums)
输出:
[0, 1, 4, 9, 16]
15. 列表推导式中如何加条件?
nums = [x for x in range(10) if x % 2 == 0] print(nums)
输出:
[0, 2, 4, 6, 8]
16.append()和extend()有什么区别?
append() 添加一个元素。
extend() 展开可迭代对象后逐个添加。
a = [1, 2] a.append([3, 4]) print(a) b = [1, 2] b.extend([3, 4]) print(b)
输出:
[1, 2, [3, 4]] [1, 2, 3, 4]
17.list.sort()和sorted()有什么区别?
list.sort() 是原地排序,返回 None。
sorted() 会返回一个新的列表。
a = [3, 1, 2] b = sorted(a) print(a) print(b) a.sort() print(a)
输出:
[3, 1, 2] [1, 2, 3] [1, 2, 3]
18. 元组一定不可变吗?
元组本身不可变,但如果元组中包含可变对象,可变对象内部仍然可以修改。
t = ([1, 2], "a") t[0].append(3) print(t)
输出:
([1, 2, 3], 'a')
19. 字典如何安全获取不存在的 key?
使用 get()。
user = {"name": "vito"}
print(user.get("age"))
print(user.get("age", 18))
输出:
None 18
20. 字典如何遍历 key 和 value?
user = {"name": "vito", "age": 18}
for k, v in user.items():
print(k, v)
输出:
name vito age 18
21. 字典推导式是什么?
d = {x: x * x for x in range(3)}
print(d)
输出:
{0: 0, 1: 1, 2: 4}
22. 集合有什么特点?
集合的特点:
- 元素唯一
- 无序
- 适合去重
- 适合成员判断
nums = [1, 2, 2, 3] print(set(nums))
输出:
{1, 2, 3}
23. 集合常见运算有哪些?
a = {1, 2, 3}
b = {3, 4}
print(a | b)
print(a & b)
print(a - b)
输出:
{1, 2, 3, 4}
{3}
{1, 2}
24. 如何统计列表中元素出现次数?
from collections import Counter items = ["a", "b", "a", "c", "b", "a"] print(Counter(items))
输出:
Counter({'a': 3, 'b': 2, 'c': 1})
25. 如何取列表中出现最多的元素?
from collections import Counter items = ["a", "b", "a", "c", "b", "a"] print(Counter(items).most_common(1))
输出:
[('a', 3)]
三、函数与参数
26. Python 函数参数有哪些类型?
常见参数类型包括:
- 位置参数
- 默认参数
- 关键字参数
- 可变位置参数
*args - 可变关键字参数
**kwargs
def demo(a, b=2, *args, **kwargs):
print(a, b, args, kwargs)
demo(1, 3, 4, 5, name="vito")
输出:
1 3 (4, 5) {'name': 'vito'}
27. 默认参数有什么坑?
默认参数只在函数定义时创建一次。
如果默认参数是列表、字典等可变对象,可能导致数据被多次调用共享。
def add_item(item, box=[]):
box.append(item)
return box
print(add_item("a"))
print(add_item("b"))
输出:
['a'] ['a', 'b']
推荐写法:
def add_item(item, box=None):
if box is None:
box = []
box.append(item)
return box
print(add_item("a"))
print(add_item("b"))
输出:
['a'] ['b']
28.*args是什么?
*args 用于接收多余的位置参数,类型是元组。
def total(*args):
return sum(args)
print(total(1, 2, 3))
输出:
6
29.**kwargs是什么?
**kwargs 用于接收多余的关键字参数,类型是字典。
def show(**kwargs):
print(kwargs)
show(name="vito", age=18)
输出:
{'name': 'vito', 'age': 18}
30. Python 函数是对象吗?
是。函数可以赋值给变量,也可以作为参数传递。
def hello():
return "hello"
f = hello
print(f())
输出:
hello
31. 什么是高阶函数?
接收函数作为参数,或者返回函数的函数,称为高阶函数。
def apply(func, value):
return func(value)
print(apply(abs, -10))
输出:
10
32.lambda表达式是什么?
lambda 是匿名函数,适合简单逻辑。
add = lambda a, b: a + b print(add(1, 2))
输出:
3
实际项目中,不建议写过于复杂的 lambda。
33.map()怎么用?
map() 会对可迭代对象中的每个元素应用函数。
nums = [1, 2, 3] print(list(map(lambda x: x * 2, nums)))
输出:
[2, 4, 6]
34.filter()怎么用?
filter() 用于过滤元素。
nums = [1, 2, 3, 4] print(list(filter(lambda x: x % 2 == 0, nums)))
输出:
[2, 4]
35.zip()怎么用?
zip() 会把多个可迭代对象按位置打包。
names = ["a", "b"] scores = [90, 80] print(list(zip(names, scores)))
输出:
[('a', 90), ('b', 80)]
四、作用域、闭包、装饰器
36. Python 作用域查找规则是什么?
Python 变量查找遵循 LEGB 规则:
- Local:局部作用域
- Enclosing:外层函数作用域
- Global:全局作用域
- Built-in:内置作用域
x = "global"
def outer():
x = "outer"
def inner():
x = "inner"
print(x)
inner()
outer()
输出:
inner
37.global有什么作用?
global 用于在函数内部声明并修改全局变量。
count = 0
def inc():
global count
count += 1
inc()
print(count)
输出:
1
38.nonlocal有什么作用?
nonlocal 用于修改外层函数作用域中的变量。
def outer():
count = 0
def inner():
nonlocal count
count += 1
return count
return inner
f = outer()
print(f())
print(f())
输出:
1 2
39. 什么是闭包?
函数内部定义函数,并且内部函数引用了外部函数的变量,这种结构就是闭包。
def make_multiplier(n):
def mul(x):
return x * n
return mul
double = make_multiplier(2)
print(double(5))
输出:
10
40. 什么是装饰器?
装饰器本质上是一个函数,用于在不修改原函数代码的情况下增强功能。
def log(func):
def wrapper():
print("before")
func()
print("after")
return wrapper
@log
def hello():
print("hello")
hello()
输出:
before hello after
41. 装饰器如何保留原函数信息?
使用 functools.wraps。
from functools import wraps
def log(func):
@wraps(func)
def wrapper(*args, **kwargs):
return func(*args, **kwargs)
return wrapper
@log
def hello():
"""say hello"""
print("hello")
print(hello.__name__)
print(hello.__doc__)
输出:
hello say hello
42. 带参数的装饰器怎么写?
from functools import wraps
def repeat(n):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
for _ in range(n):
func(*args, **kwargs)
return wrapper
return decorator
@repeat(2)
def say():
print("hi")
say()
输出:
hi hi
五、异常处理
43. Python 如何捕获异常?
try:
x = 1 / 0
except ZeroDivisionError as e:
print("error:", e)
输出:
error: division by zero
44.try...except...else...finally执行顺序是什么?
else 在没有异常时执行。
finally 无论是否异常都会执行。
try:
x = 10 / 2
except ZeroDivisionError:
print("except")
else:
print("else:", x)
finally:
print("finally")
输出:
else: 5.0 finally
45. 如何主动抛出异常?
使用 raise。
def check_age(age):
if age < 0:
raise ValueError("age cannot be negative")
return age
try:
check_age(-1)
except ValueError as e:
print(e)
输出:
age cannot be negative
46. 如何自定义异常?
class BusinessError(Exception):
pass
raise BusinessError("业务异常")
输出示例:
BusinessError: 业务异常
47. 为什么不要直接except Exception: pass?
因为这样会吞掉错误,导致问题隐藏,排查困难。
try:
int("abc")
except Exception:
print("发生异常,但这里至少要记录日志")
输出:
发生异常,但这里至少要记录日志
六、文件、上下文管理器、迭代器、生成器
48. 为什么推荐使用with open()?
with 会自动关闭文件,避免资源泄漏。
with open("demo.txt", "w", encoding="utf-8") as f:
f.write("hello")
49. 什么是上下文管理器?
实现 __enter__ 和 __exit__ 方法的对象,就是上下文管理器。
class Demo:
def __enter__(self):
print("enter")
return self
def __exit__(self, exc_type, exc, tb):
print("exit")
with Demo():
print("running")
输出:
enter running exit
50. 什么是迭代器?
实现 __iter__() 和 __next__() 的对象就是迭代器。
nums = iter([1, 2, 3]) print(next(nums)) print(next(nums))
输出:
1 2
51. 什么是可迭代对象?
能被 for 循环遍历的对象,就是可迭代对象。
常见可迭代对象包括:
- 列表
- 元组
- 字典
- 字符串
- 集合
- 生成器
for ch in "abc":
print(ch)
输出:
a b c
52. 什么是生成器?
包含 yield 的函数会返回生成器。生成器会按需产生数据。
def gen():
yield 1
yield 2
g = gen()
print(next(g))
print(next(g))
输出:
1 2
53. 生成器有什么优点?
生成器节省内存,适合处理大数据流。
def numbers(n):
for i in range(n):
yield i
for x in numbers(3):
print(x)
输出:
0 1 2
54.yield from有什么作用?
yield from 可以把子生成器的值交给外层生成器。
def gen():
yield from [1, 2, 3]
print(list(gen()))
输出:
[1, 2, 3]
55. 生成器表达式和列表推导式有什么区别?
生成器表达式按需计算。
列表推导式会一次性生成完整列表。
g = (x * x for x in range(3)) print(g) print(list(g))
输出示例:
<generator object <genexpr> at 0x...> [0, 1, 4]
七、面向对象
56. 类和对象有什么区别?
类是模板,对象是类的实例。
class User:
pass
u = User()
print(type(u))
输出:
<class '__main__.User'>
57.__init__是构造函数吗?
严格来说,__init__ 是初始化方法,对象创建后会调用它。
真正创建对象的是 __new__。
class User:
def __init__(self, name):
self.name = name
u = User("vito")
print(u.name)
输出:
vito
58. 实例属性和类属性有什么区别?
实例属性属于对象。
类属性属于类。
class User:
role = "tester"
u1 = User()
u2 = User()
u1.name = "vito"
print(u1.role)
print(u2.role)
print(u1.name)
输出:
tester tester vito
59. 类方法、静态方法、实例方法有什么区别?
实例方法默认接收 self。
类方法默认接收 cls。
静态方法不自动接收对象或类。
class Demo:
def ins(self):
print("instance")
@classmethod
def cls_method(cls):
print("class")
@staticmethod
def static_method():
print("static")
d = Demo()
d.ins()
Demo.cls_method()
Demo.static_method()
输出:
instance class static
60. 什么是继承?
子类可以复用父类的属性和方法。
class Animal:
def speak(self):
print("animal speak")
class Dog(Animal):
pass
Dog().speak()
输出:
animal speak
61. 什么是方法重写?
子类重新定义父类方法,就是方法重写。
class Animal:
def speak(self):
print("animal")
class Dog(Animal):
def speak(self):
print("wang")
Dog().speak()
输出:
wang
62.super()有什么作用?
super() 用于调用父类方法。
class Base:
def hello(self):
print("base hello")
class Child(Base):
def hello(self):
super().hello()
print("child hello")
Child().hello()
输出:
base hello child hello
63. Python 支持多继承吗?
支持。方法解析顺序由 MRO 决定。
class A:
def hello(self):
print("A")
class B(A):
pass
class C(A):
def hello(self):
print("C")
class D(B, C):
pass
D().hello()
print(D.mro())
输出示例:
C [<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]
64. 什么是魔术方法?
以双下划线开头和结尾的方法,例如:
__str____repr____len____call____enter____exit__
class User:
def __str__(self):
return "User object"
print(User())
输出:
User object
65.__repr__和__str__有什么区别?
__str__ 面向用户,输出更友好。
__repr__ 面向开发者和调试。
class User:
def __repr__(self):
return "User(name='vito')"
u = User()
print(repr(u))
输出:
User(name='vito')
66.@property有什么作用?
@property 可以把方法当属性访问,同时封装计算逻辑。
class Circle:
def __init__(self, r):
self.r = r
@property
def area(self):
return 3.14 * self.r * self.r
c = Circle(2)
print(c.area)
输出:
12.56
67. 什么是dataclass?
dataclass 可以自动生成 __init__、__repr__ 等方法,适合定义数据类。
from dataclasses import dataclass
@dataclass
class User:
name: str
age: int
u = User("vito", 18)
print(u)
输出:
User(name='vito', age=18)
68.__slots__有什么作用?
__slots__ 可以限制实例动态添加属性,也可以减少内存开销。
class User:
__slots__ = ("name",)
u = User()
u.name = "vito"
print(u.name)
# u.age = 18 # AttributeError
输出:
vito
八、模块、包、虚拟环境、工程化
69. 模块和包有什么区别?
一个 .py 文件可以是模块。
包含多个模块的目录可以作为包。
# demo.py
def hello():
return "hello"
使用:
# import demo # print(demo.hello())
70.if __name__ == "__main__"有什么作用?
判断当前文件是被直接运行,还是被其他模块导入。
def main():
print("running main")
if __name__ == "__main__":
main()
直接运行输出:
running main
71. Python 如何管理第三方依赖?
常用 pip 安装依赖,并推荐使用虚拟环境。
python -m venv .venv source .venv/bin/activate pip install requests
Windows PowerShell:
python -m venv .venv .\.venv\Scripts\Activate.ps1 pip install requests
72.requirements.txt有什么用?
requirements.txt 用于记录项目依赖,方便环境复现。
requests==2.32.3 pytest==8.3.2
安装依赖:
pip install -r requirements.txt
73.pyproject.toml是什么?
pyproject.toml 是现代 Python 项目常见配置文件,可配置:
- 项目信息
- 构建系统
- pytest 配置
- black 配置
- mypy 配置
- ruff 配置
[project] name = "demo" version = "0.1.0" [tool.pytest.ini_options] testpaths = ["tests"]
74. Python 如何读取环境变量?
import os
os.environ["APP_ENV"] = "dev"
print(os.getenv("APP_ENV"))
输出:
dev
75.__all__有什么作用?
__all__ 用于控制 from module import * 导入的内容。
__all__ = ["hello"]
def hello():
print("hello")
def hidden():
print("hidden")
九、并发、线程、进程、协程
76. 线程适合什么场景?
线程适合 IO 密集型任务,例如:
- 网络请求
- 文件读写
- 数据库访问
- 接口调用
import threading
import time
def task(name):
time.sleep(1)
print(name, "done")
t1 = threading.Thread(target=task, args=("A",))
t2 = threading.Thread(target=task, args=("B",))
t1.start()
t2.start()
t1.join()
t2.join()
输出:
A done B done
77. 什么是 GIL?
GIL 是 CPython 中的全局解释器锁。
它会限制多个线程同时执行 Python 字节码,所以 CPU 密集型任务通常无法通过多线程获得明显性能提升。
def cpu_task():
return sum(i * i for i in range(100000))
print(cpu_task())
输出:
333328333350000
78. 进程适合什么场景?
进程适合 CPU 密集型任务。
多进程可以利用多核 CPU。
from multiprocessing import Pool
def square(x):
return x * x
if __name__ == "__main__":
with Pool(2) as pool:
print(pool.map(square, [1, 2, 3]))
输出:
[1, 4, 9]
79. 为什么 Windows 下多进程要写if __name__ == "__main__"?
因为 Windows 创建子进程时会重新导入主模块。
如果不加保护,可能导致子进程重复创建子进程。
from multiprocessing import Process
def hello():
print("hello")
if __name__ == "__main__":
p = Process(target=hello)
p.start()
p.join()
输出:
hello
80. 协程适合什么场景?
协程适合高并发 IO 场景,例如:
- 网络请求
- WebSocket
- 异步数据库
- 异步爬虫
- 高并发接口调用
import asyncio
async def main():
print("start")
await asyncio.sleep(1)
print("end")
asyncio.run(main())
输出:
start end
81.async和await是什么?
async 用于定义协程函数。
await 用于等待异步操作完成。
import asyncio
async def fetch():
await asyncio.sleep(1)
return "data"
async def main():
result = await fetch()
print(result)
asyncio.run(main())
输出:
data
82. 如何并发运行多个协程?
使用 asyncio.gather()。
import asyncio
async def task(name):
await asyncio.sleep(1)
return f"{name} done"
async def main():
result = await asyncio.gather(task("A"), task("B"))
print(result)
asyncio.run(main())
输出:
['A done', 'B done']
83.time.sleep()和asyncio.sleep()有什么区别?
time.sleep() 会阻塞当前线程。
asyncio.sleep() 会让出事件循环,不阻塞其他协程。
import asyncio
async def task():
await asyncio.sleep(1)
print("done")
asyncio.run(task())
输出:
done
84. 如何避免多个线程同时修改共享数据?
可以使用锁。
import threading
count = 0
lock = threading.Lock()
def inc():
global count
for _ in range(10000):
with lock:
count += 1
threads = [threading.Thread(target=inc) for _ in range(2)]
for t in threads:
t.start()
for t in threads:
t.join()
print(count)
输出:
20000
十、常用标准库与实战能力
85.collections.defaultdict有什么用?
defaultdict 可以给不存在的 key 自动创建默认值。
from collections import defaultdict
d = defaultdict(list)
d["python"].append("good")
print(d)
输出:
defaultdict(<class 'list'>, {'python': ['good']})
86.deque适合什么场景?
deque 是双端队列,适合从两端快速添加和删除元素。
from collections import deque q = deque([1, 2]) q.appendleft(0) q.append(3) print(q)
输出:
deque([0, 1, 2, 3])
87.heapq有什么用?
heapq 可以实现堆,常用于:
- Top K
- 优先队列
- 小顶堆
import heapq nums = [5, 1, 3] heapq.heapify(nums) print(heapq.heappop(nums))
输出:
1
88.json.dumps()和json.loads()有什么区别?
json.dumps() 把 Python 对象转成 JSON 字符串。
json.loads() 把 JSON 字符串转成 Python 对象。
import json
s = json.dumps({"name": "vito"}, ensure_ascii=False)
print(s)
obj = json.loads(s)
print(obj["name"])
输出:
{"name": "vito"}
vito
89. 如何处理Decimal不能直接 JSON 序列化的问题?
可以转换为字符串或浮点数。
如果是金额、精度敏感场景,建议转换为字符串。
import json
from decimal import Decimal
data = {"price": str(Decimal("10.50"))}
print(json.dumps(data))
输出:
{"price": "10.50"}
90.pathlib相比os.path有什么好处?
pathlib 是面向对象的路径处理方式,路径拼接更直观。
from pathlib import Path
p = Path("logs") / "app.log"
print(p)
输出:
logs/app.log
91. 如何读取 CSV 文件?
import csv
rows = [["name", "score"], ["vito", "90"]]
with open("score.csv", "w", newline="", encoding="utf-8") as f:
writer = csv.writer(f)
writer.writerows(rows)
with open("score.csv", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
print(row)
输出:
{'name': 'vito', 'score': '90'}
92. 如何记录日志?
import logging
logging.basicConfig(level=logging.INFO)
logging.info("service started")
输出示例:
INFO:root:service started
93. 如何写单元测试?
def add(a, b):
return a + b
def test_add():
assert add(1, 2) == 3
使用 pytest 运行:
pytest test_demo.py
输出示例:
1 passed in 0.01s
94.pytest.raises怎么用?
import pytest
def div(a, b):
return a / b
def test_div_zero():
with pytest.raises(ZeroDivisionError):
div(1, 0)
输出示例:
1 passed in 0.01s
十一、性能、内存、编码规范
95. 如何查看对象占用内存?
import sys a = [1, 2, 3] print(sys.getsizeof(a))
输出示例:
88
具体数值和 Python 版本、操作系统有关。
96. 如何优化大列表处理?
能用生成器就不要一次性创建大列表。
total = sum(x * x for x in range(1000000)) print(total)
输出:
333332833333500000
97. 浅拷贝和深拷贝有什么区别?
浅拷贝只复制外层对象。
深拷贝会递归复制内部对象。
import copy a = [[1, 2], [3, 4]] b = copy.copy(a) c = copy.deepcopy(a) a[0].append(99) print(b) print(c)
输出:
[[1, 2, 99], [3, 4]] [[1, 2], [3, 4]]
98.with为什么比手动close()更安全?
因为即使中间发生异常,with 也会执行资源释放逻辑。
try:
with open("demo.txt", "r", encoding="utf-8") as f:
print(f.read())
except FileNotFoundError:
print("file not found")
输出示例:
hello
或者:
file not found
99. Python 代码规范主要看什么?
常见关注点包括:
- 命名清晰
- 函数不要太长
- 异常不要乱吞
- 不要写重复代码
- 复杂逻辑拆函数
- 遵循 PEP 8 风格
- 加必要的类型注解
- 加必要的单元测试
def calculate_total_price(price: float, count: int) -> float:
return price * count
print(calculate_total_price(9.9, 3))
输出:
29.700000000000003
如果涉及金额,建议使用 Decimal。
100. 面试中如何回答“你怎么提升 Python 代码质量”?
可以从以下几个方面回答:
- 使用类型注解提升可读性
- 使用 pytest 编写单元测试
- 使用 logging 记录关键日志
- 使用异常处理保证程序稳定
- 使用虚拟环境隔离依赖
- 使用 requirements.txt 或 pyproject.toml 管理依赖
- 使用 black、ruff、mypy 等工具做代码检查
- 使用 CI 流水线自动执行测试和代码扫描
- 复杂逻辑模块化
- 性能敏感代码做 profiling 分析
from typing import Sequence
def average(nums: Sequence[float]) -> float:
if not nums:
raise ValueError("nums cannot be empty")
return sum(nums) / len(nums)
print(average([80, 90, 100]))
输出:
90.0
十二、总结:Python 面试不是背答案,而是建立知识网络
这 100 个问题可以分成 8 条主线:
- 基础语法:变量、对象、类型、真假判断
- 数据结构:字符串、列表、元组、字典、集合
- 函数能力:参数、闭包、装饰器、高阶函数
- 面向对象:类、继承、魔术方法、属性管理
- 异常与资源:异常捕获、上下文管理器、文件处理
- 并发模型:线程、进程、协程、GIL、锁
- 标准库:json、csv、pathlib、logging、collections
- 工程质量:虚拟环境、依赖管理、测试、类型注解、代码规范
真正的面试重点不是“你是否见过这个问题”,而是你能否用清晰的语言说明原理,并写出可靠的小例子。
最好的准备方式是:
- 每个问题都自己敲一遍代码
- 观察真实输出
- 尝试修改参数和边界条件
- 主动制造异常场景
- 把问题串成知识体系
当你能把一个知识点讲清楚、写明白、举出例子,并能说出常见坑点时,面试基本就稳了一半。
附:面试复习建议
如果你准备 Python 面试,可以按下面顺序复习:
第一阶段:基础语法
重点掌握:
- 变量
- 类型
- 判断
- 循环
- 字符串
- 列表
- 字典
- 集合
第二阶段:函数和对象
重点掌握:
- 参数传递
- 默认参数坑点
- 闭包
- 装饰器
- 类
- 继承
- 魔术方法
第三阶段:工程能力
重点掌握:
- 虚拟环境
- pip
- requirements.txt
- pyproject.toml
- 日志
- 异常
- 单元测试
第四阶段:进阶能力
重点掌握:
- 迭代器
- 生成器
- 上下文管理器
- 多线程
- 多进程
- 协程
- GIL
- 性能优化
第五阶段:项目表达
面试时不要只说“我会 Python”,而要结合项目讲:
- 我用 Python 做过什么
- 解决了什么问题
- 遇到过什么坑
- 如何排查问题
- 如何提升效率
- 如何保证代码质量
例如:
我在自动化测试平台中使用 Python 编写接口测试脚本,通过 pytest 管理测试用例,结合 logging 输出关键日志,并使用 requests 封装接口调用。对于复杂业务场景,我会把公共逻辑抽成工具函数或类,同时通过 fixture 管理测试数据,提升了用例复用性和维护性。
这样的回答,比单纯背语法更有说服力。
参考方向
本文内容主要围绕 Python 常见面试点整理,建议进一步阅读:
- Python 官方文档
- Python Tutorial
- Python Data Model
- Python Standard Library
- pytest 官方文档
- Python Packaging 官方文档
- asyncio 官方文档
- threading 官方文档
- multiprocessing 官方文档
到此这篇关于Python常见100个经典面试问题总结的文章就介绍到这了,更多相关Python经典面试问题内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
相关文章
查找python项目依赖并生成requirements.txt的方法
今天小编就为大家分享一篇查找python项目依赖并生成requirements.txt的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧2018-07-07
pycharm没有找到manage repositories按钮的解决办法
这篇文章主要给大家介绍了关于pycharm没有找到manage repositories按钮的解决办法,pycharm是用来写python的可视化代码软件,文中通过图文介绍的非常详细,需要的朋友可以参考下2023-07-07
Python使用requests模块发送http请求的方法介绍
Python Requests是一个 HTTP 库,它允许我们向 Web 服务器发送 HTTP 请求,并获取响应结果,本文将会详细介绍Python requests模块如何发送http请求,文中有相关的代码示例,需要的朋友可以参考下2023-06-06


最新评论