Python 面试系列:常见 100 个经典面试问题,从入门到进阶

Python 面试系列:常见 100 个经典面试问题,从入门到进阶

说明:本文整理了 Python 面试中常见的 100 个经典问题,覆盖基础语法、数据结构、函数、装饰器、异常、文件、迭代器、生成器、面向对象、工程化、并发、标准库、性能优化等内容。每个问题都尽量配有示例代码和真实输出,方便读者边看边练。


前言

Python 面试并不是单纯考"会不会写语法",而是考你是否真正理解对象、数据结构、函数、异常、面向对象、装饰器、生成器、并发、性能、工程化和常见坑点。

很多候选人能写出代码,但一问:

  • 为什么列表不能作为字典 key?
  • 装饰器什么时候执行?
  • is== 有什么区别?
  • 线程、进程、协程怎么选?
  • GIL 到底影响什么?
  • 浅拷贝和深拷贝有什么区别?

就容易卡住。

本文整理 100 个 Python 高频面试问题,每个问题都配一个小例子,方便你边看边练。建议阅读方式是:先看问题,自己想 30 秒,再看答案和代码。


一、Python 基础语法与对象模型

1. Python 是解释型语言吗?

是。Python 通常由解释器执行源码或字节码,不需要像 C/C++ 那样提前编译成机器码。

但这不代表 Python 没有编译过程。.py 文件通常会先被编译成字节码,再由 Python 虚拟机执行。

python 复制代码
print("hello python")

输出:

text 复制代码
hello python

2. Python 中"一切皆对象"是什么意思?

变量、函数、类、模块、数字、字符串都是对象。对象通常有三个重要特征:

  1. 身份:可以用 id() 查看
  2. 类型:可以用 type() 查看
  3. 值:对象保存的数据
python 复制代码
x = 100

print(type(x))
print(id(x))

输出示例:

text 复制代码
<class 'int'>
140735568356104

3. is== 有什么区别?

== 比较的是两个对象的值是否相等。

is 比较的是两个变量是否引用同一个对象。

python 复制代码
a = [1, 2]
b = [1, 2]

print(a == b)
print(a is b)

输出:

text 复制代码
True
False

解释:

虽然 ab 的值一样,但它们是两个不同的列表对象。


4. Python 中可变对象和不可变对象有什么区别?

可变对象的值可以原地修改,例如:

  • list
  • dict
  • set

不可变对象创建后不能直接修改,例如:

  • int
  • float
  • str
  • tuple
python 复制代码
a = [1, 2]
a.append(3)
print(a)

s = "ab"
s += "c"
print(s)

输出:

text 复制代码
[1, 2, 3]
abc

注意:字符串看起来被修改了,其实是创建了一个新的字符串对象。


5. 为什么列表不能作为字典 key?

因为列表是可变对象,哈希值不稳定,不能作为字典 key。

字典 key 必须是可哈希对象。常见可哈希对象包括:

  • 字符串
  • 数字
  • 元组
  • 布尔值
python 复制代码
d = {}

# d[[1, 2]] = "value"  # TypeError: unhashable type: 'list'

d[(1, 2)] = "value"

print(d)

输出:

text 复制代码
{(1, 2): 'value'}

6. None 应该如何判断?

推荐使用 is None,不要使用 == None

python 复制代码
value = None

if value is None:
    print("value is None")

输出:

text 复制代码
value is None

原因是 None 是一个单例对象,使用 is 更准确。


7. Python 的布尔值判断规则是什么?

以下值通常会被判断为假:

  • None
  • False
  • 0
  • ""
  • []
  • {}
  • set()
  • tuple()
python 复制代码
values = ["", [], {}, 0, None, "python"]

for v in values:
    print(bool(v))

输出:

text 复制代码
False
False
False
False
False
True

8. andor 返回的一定是布尔值吗?

不一定。它们返回的是参与运算的对象本身。

python 复制代码
print(0 or "default")
print("python" and "ok")

输出:

text 复制代码
default
ok

这个特性经常用于默认值处理。


9. Python 中变量需要声明类型吗?

不需要。Python 是动态类型语言,变量名只是对象的引用。

python 复制代码
x = 1
x = "hello"

print(x)

输出:

text 复制代码
hello

10. Python 的类型注解会强制校验类型吗?

不会。类型注解主要用于:

  • 提高代码可读性
  • 辅助 IDE 提示
  • 配合 mypy、pyright 等工具做静态检查

Python 运行时默认不会强制校验类型。

python 复制代码
def add(a: int, b: int) -> int:
    return a + b

print(add("1", "2"))

输出:

text 复制代码
12

虽然参数标注为 int,但运行时传入字符串也能执行。


二、字符串、列表、元组、字典、集合

11. 字符串如何反转?

python 复制代码
s = "python"

print(s[::-1])

输出:

text 复制代码
nohtyp

12. 字符串拼接为什么推荐 join

循环中频繁使用 + 拼接字符串,会产生多个中间字符串对象。

大量字符串拼接时,推荐使用 join()

python 复制代码
words = ["Python", "is", "good"]

print(" ".join(words))

输出:

text 复制代码
Python is good

13. split()strip() 有什么区别?

split() 用于分割字符串。

strip() 用于去除字符串首尾空白或指定字符。

python 复制代码
s = "  a,b,c  "

print(s.strip())
print(s.strip().split(","))

输出:

text 复制代码
a,b,c
['a', 'b', 'c']

14. 列表推导式是什么?

列表推导式可以用简洁语法生成列表。

python 复制代码
nums = [x * x for x in range(5)]

print(nums)

输出:

text 复制代码
[0, 1, 4, 9, 16]

15. 列表推导式中如何加条件?

python 复制代码
nums = [x for x in range(10) if x % 2 == 0]

print(nums)

输出:

text 复制代码
[0, 2, 4, 6, 8]

16. append()extend() 有什么区别?

append() 添加一个元素。

extend() 展开可迭代对象后逐个添加。

python 复制代码
a = [1, 2]
a.append([3, 4])
print(a)

b = [1, 2]
b.extend([3, 4])
print(b)

输出:

text 复制代码
[1, 2, [3, 4]]
[1, 2, 3, 4]

17. list.sort()sorted() 有什么区别?

list.sort() 是原地排序,返回 None

sorted() 会返回一个新的列表。

python 复制代码
a = [3, 1, 2]

b = sorted(a)

print(a)
print(b)

a.sort()
print(a)

输出:

text 复制代码
[3, 1, 2]
[1, 2, 3]
[1, 2, 3]

18. 元组一定不可变吗?

元组本身不可变,但如果元组中包含可变对象,可变对象内部仍然可以修改。

python 复制代码
t = ([1, 2], "a")

t[0].append(3)

print(t)

输出:

text 复制代码
([1, 2, 3], 'a')

19. 字典如何安全获取不存在的 key?

使用 get()

python 复制代码
user = {"name": "vito"}

print(user.get("age"))
print(user.get("age", 18))

输出:

text 复制代码
None
18

20. 字典如何遍历 key 和 value?

python 复制代码
user = {"name": "vito", "age": 18}

for k, v in user.items():
    print(k, v)

输出:

text 复制代码
name vito
age 18

21. 字典推导式是什么?

python 复制代码
d = {x: x * x for x in range(3)}

print(d)

输出:

text 复制代码
{0: 0, 1: 1, 2: 4}

22. 集合有什么特点?

集合的特点:

  1. 元素唯一
  2. 无序
  3. 适合去重
  4. 适合成员判断
python 复制代码
nums = [1, 2, 2, 3]

print(set(nums))

输出:

text 复制代码
{1, 2, 3}

23. 集合常见运算有哪些?

python 复制代码
a = {1, 2, 3}
b = {3, 4}

print(a | b)
print(a & b)
print(a - b)

输出:

text 复制代码
{1, 2, 3, 4}
{3}
{1, 2}

24. 如何统计列表中元素出现次数?

python 复制代码
from collections import Counter

items = ["a", "b", "a", "c", "b", "a"]

print(Counter(items))

输出:

text 复制代码
Counter({'a': 3, 'b': 2, 'c': 1})

25. 如何取列表中出现最多的元素?

python 复制代码
from collections import Counter

items = ["a", "b", "a", "c", "b", "a"]

print(Counter(items).most_common(1))

输出:

text 复制代码
[('a', 3)]

三、函数与参数

26. Python 函数参数有哪些类型?

常见参数类型包括:

  1. 位置参数
  2. 默认参数
  3. 关键字参数
  4. 可变位置参数 *args
  5. 可变关键字参数 **kwargs
python 复制代码
def demo(a, b=2, *args, **kwargs):
    print(a, b, args, kwargs)

demo(1, 3, 4, 5, name="vito")

输出:

text 复制代码
1 3 (4, 5) {'name': 'vito'}

27. 默认参数有什么坑?

默认参数只在函数定义时创建一次。

如果默认参数是列表、字典等可变对象,可能导致数据被多次调用共享。

python 复制代码
def add_item(item, box=[]):
    box.append(item)
    return box

print(add_item("a"))
print(add_item("b"))

输出:

text 复制代码
['a']
['a', 'b']

推荐写法:

python 复制代码
def add_item(item, box=None):
    if box is None:
        box = []
    box.append(item)
    return box

print(add_item("a"))
print(add_item("b"))

输出:

text 复制代码
['a']
['b']

28. *args 是什么?

*args 用于接收多余的位置参数,类型是元组。

python 复制代码
def total(*args):
    return sum(args)

print(total(1, 2, 3))

输出:

text 复制代码
6

29. **kwargs 是什么?

**kwargs 用于接收多余的关键字参数,类型是字典。

python 复制代码
def show(**kwargs):
    print(kwargs)

show(name="vito", age=18)

输出:

text 复制代码
{'name': 'vito', 'age': 18}

30. Python 函数是对象吗?

是。函数可以赋值给变量,也可以作为参数传递。

python 复制代码
def hello():
    return "hello"

f = hello

print(f())

输出:

text 复制代码
hello

31. 什么是高阶函数?

接收函数作为参数,或者返回函数的函数,称为高阶函数。

python 复制代码
def apply(func, value):
    return func(value)

print(apply(abs, -10))

输出:

text 复制代码
10

32. lambda 表达式是什么?

lambda 是匿名函数,适合简单逻辑。

python 复制代码
add = lambda a, b: a + b

print(add(1, 2))

输出:

text 复制代码
3

实际项目中,不建议写过于复杂的 lambda


33. map() 怎么用?

map() 会对可迭代对象中的每个元素应用函数。

python 复制代码
nums = [1, 2, 3]

print(list(map(lambda x: x * 2, nums)))

输出:

text 复制代码
[2, 4, 6]

34. filter() 怎么用?

filter() 用于过滤元素。

python 复制代码
nums = [1, 2, 3, 4]

print(list(filter(lambda x: x % 2 == 0, nums)))

输出:

text 复制代码
[2, 4]

35. zip() 怎么用?

zip() 会把多个可迭代对象按位置打包。

python 复制代码
names = ["a", "b"]
scores = [90, 80]

print(list(zip(names, scores)))

输出:

text 复制代码
[('a', 90), ('b', 80)]

四、作用域、闭包、装饰器

36. Python 作用域查找规则是什么?

Python 变量查找遵循 LEGB 规则:

  1. Local:局部作用域
  2. Enclosing:外层函数作用域
  3. Global:全局作用域
  4. Built-in:内置作用域
python 复制代码
x = "global"

def outer():
    x = "outer"

    def inner():
        x = "inner"
        print(x)

    inner()

outer()

输出:

text 复制代码
inner

37. global 有什么作用?

global 用于在函数内部声明并修改全局变量。

python 复制代码
count = 0

def inc():
    global count
    count += 1

inc()

print(count)

输出:

text 复制代码
1

38. nonlocal 有什么作用?

nonlocal 用于修改外层函数作用域中的变量。

python 复制代码
def outer():
    count = 0

    def inner():
        nonlocal count
        count += 1
        return count

    return inner

f = outer()

print(f())
print(f())

输出:

text 复制代码
1
2

39. 什么是闭包?

函数内部定义函数,并且内部函数引用了外部函数的变量,这种结构就是闭包。

python 复制代码
def make_multiplier(n):
    def mul(x):
        return x * n

    return mul

double = make_multiplier(2)

print(double(5))

输出:

text 复制代码
10

40. 什么是装饰器?

装饰器本质上是一个函数,用于在不修改原函数代码的情况下增强功能。

python 复制代码
def log(func):
    def wrapper():
        print("before")
        func()
        print("after")
    return wrapper

@log
def hello():
    print("hello")

hello()

输出:

text 复制代码
before
hello
after

41. 装饰器如何保留原函数信息?

使用 functools.wraps

python 复制代码
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__)

输出:

text 复制代码
hello
say hello

42. 带参数的装饰器怎么写?

python 复制代码
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()

输出:

text 复制代码
hi
hi

五、异常处理

43. Python 如何捕获异常?

python 复制代码
try:
    x = 1 / 0
except ZeroDivisionError as e:
    print("error:", e)

输出:

text 复制代码
error: division by zero

44. try...except...else...finally 执行顺序是什么?

else 在没有异常时执行。

finally 无论是否异常都会执行。

python 复制代码
try:
    x = 10 / 2
except ZeroDivisionError:
    print("except")
else:
    print("else:", x)
finally:
    print("finally")

输出:

text 复制代码
else: 5.0
finally

45. 如何主动抛出异常?

使用 raise

python 复制代码
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)

输出:

text 复制代码
age cannot be negative

46. 如何自定义异常?

python 复制代码
class BusinessError(Exception):
    pass

raise BusinessError("业务异常")

输出示例:

text 复制代码
BusinessError: 业务异常

47. 为什么不要直接 except Exception: pass

因为这样会吞掉错误,导致问题隐藏,排查困难。

python 复制代码
try:
    int("abc")
except Exception:
    print("发生异常,但这里至少要记录日志")

输出:

text 复制代码
发生异常,但这里至少要记录日志

六、文件、上下文管理器、迭代器、生成器

48. 为什么推荐使用 with open()

with 会自动关闭文件,避免资源泄漏。

python 复制代码
with open("demo.txt", "w", encoding="utf-8") as f:
    f.write("hello")

49. 什么是上下文管理器?

实现 __enter____exit__ 方法的对象,就是上下文管理器。

python 复制代码
class Demo:
    def __enter__(self):
        print("enter")
        return self

    def __exit__(self, exc_type, exc, tb):
        print("exit")

with Demo():
    print("running")

输出:

text 复制代码
enter
running
exit

50. 什么是迭代器?

实现 __iter__()__next__() 的对象就是迭代器。

python 复制代码
nums = iter([1, 2, 3])

print(next(nums))
print(next(nums))

输出:

text 复制代码
1
2

51. 什么是可迭代对象?

能被 for 循环遍历的对象,就是可迭代对象。

常见可迭代对象包括:

  • 列表
  • 元组
  • 字典
  • 字符串
  • 集合
  • 生成器
python 复制代码
for ch in "abc":
    print(ch)

输出:

text 复制代码
a
b
c

52. 什么是生成器?

包含 yield 的函数会返回生成器。生成器会按需产生数据。

python 复制代码
def gen():
    yield 1
    yield 2

g = gen()

print(next(g))
print(next(g))

输出:

text 复制代码
1
2

53. 生成器有什么优点?

生成器节省内存,适合处理大数据流。

python 复制代码
def numbers(n):
    for i in range(n):
        yield i

for x in numbers(3):
    print(x)

输出:

text 复制代码
0
1
2

54. yield from 有什么作用?

yield from 可以把子生成器的值交给外层生成器。

python 复制代码
def gen():
    yield from [1, 2, 3]

print(list(gen()))

输出:

text 复制代码
[1, 2, 3]

55. 生成器表达式和列表推导式有什么区别?

生成器表达式按需计算。

列表推导式会一次性生成完整列表。

python 复制代码
g = (x * x for x in range(3))

print(g)
print(list(g))

输出示例:

text 复制代码
<generator object <genexpr> at 0x...>
[0, 1, 4]

七、面向对象

56. 类和对象有什么区别?

类是模板,对象是类的实例。

python 复制代码
class User:
    pass

u = User()

print(type(u))

输出:

text 复制代码
<class '__main__.User'>

57. __init__ 是构造函数吗?

严格来说,__init__ 是初始化方法,对象创建后会调用它。

真正创建对象的是 __new__

python 复制代码
class User:
    def __init__(self, name):
        self.name = name

u = User("vito")

print(u.name)

输出:

text 复制代码
vito

58. 实例属性和类属性有什么区别?

实例属性属于对象。

类属性属于类。

python 复制代码
class User:
    role = "tester"

u1 = User()
u2 = User()

u1.name = "vito"

print(u1.role)
print(u2.role)
print(u1.name)

输出:

text 复制代码
tester
tester
vito

59. 类方法、静态方法、实例方法有什么区别?

实例方法默认接收 self

类方法默认接收 cls

静态方法不自动接收对象或类。

python 复制代码
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()

输出:

text 复制代码
instance
class
static

60. 什么是继承?

子类可以复用父类的属性和方法。

python 复制代码
class Animal:
    def speak(self):
        print("animal speak")

class Dog(Animal):
    pass

Dog().speak()

输出:

text 复制代码
animal speak

61. 什么是方法重写?

子类重新定义父类方法,就是方法重写。

python 复制代码
class Animal:
    def speak(self):
        print("animal")

class Dog(Animal):
    def speak(self):
        print("wang")

Dog().speak()

输出:

text 复制代码
wang

62. super() 有什么作用?

super() 用于调用父类方法。

python 复制代码
class Base:
    def hello(self):
        print("base hello")

class Child(Base):
    def hello(self):
        super().hello()
        print("child hello")

Child().hello()

输出:

text 复制代码
base hello
child hello

63. Python 支持多继承吗?

支持。方法解析顺序由 MRO 决定。

python 复制代码
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())

输出示例:

text 复制代码
C
[<class '__main__.D'>, <class '__main__.B'>, <class '__main__.C'>, <class '__main__.A'>, <class 'object'>]

64. 什么是魔术方法?

以双下划线开头和结尾的方法,例如:

  • __str__
  • __repr__
  • __len__
  • __call__
  • __enter__
  • __exit__
python 复制代码
class User:
    def __str__(self):
        return "User object"

print(User())

输出:

text 复制代码
User object

65. __repr____str__ 有什么区别?

__str__ 面向用户,输出更友好。

__repr__ 面向开发者和调试。

python 复制代码
class User:
    def __repr__(self):
        return "User(name='vito')"

u = User()

print(repr(u))

输出:

text 复制代码
User(name='vito')

66. @property 有什么作用?

@property 可以把方法当属性访问,同时封装计算逻辑。

python 复制代码
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)

输出:

text 复制代码
12.56

67. 什么是 dataclass

dataclass 可以自动生成 __init____repr__ 等方法,适合定义数据类。

python 复制代码
from dataclasses import dataclass

@dataclass
class User:
    name: str
    age: int

u = User("vito", 18)

print(u)

输出:

text 复制代码
User(name='vito', age=18)

68. __slots__ 有什么作用?

__slots__ 可以限制实例动态添加属性,也可以减少内存开销。

python 复制代码
class User:
    __slots__ = ("name",)

u = User()
u.name = "vito"

print(u.name)

# u.age = 18  # AttributeError

输出:

text 复制代码
vito

八、模块、包、虚拟环境、工程化

69. 模块和包有什么区别?

一个 .py 文件可以是模块。

包含多个模块的目录可以作为包。

python 复制代码
# demo.py
def hello():
    return "hello"

使用:

python 复制代码
# import demo
# print(demo.hello())

70. if __name__ == "__main__" 有什么作用?

判断当前文件是被直接运行,还是被其他模块导入。

python 复制代码
def main():
    print("running main")

if __name__ == "__main__":
    main()

直接运行输出:

text 复制代码
running main

71. Python 如何管理第三方依赖?

常用 pip 安装依赖,并推荐使用虚拟环境。

bash 复制代码
python -m venv .venv
source .venv/bin/activate
pip install requests

Windows PowerShell:

powershell 复制代码
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install requests

72. requirements.txt 有什么用?

requirements.txt 用于记录项目依赖,方便环境复现。

text 复制代码
requests==2.32.3
pytest==8.3.2

安装依赖:

bash 复制代码
pip install -r requirements.txt

73. pyproject.toml 是什么?

pyproject.toml 是现代 Python 项目常见配置文件,可配置:

  • 项目信息
  • 构建系统
  • pytest 配置
  • black 配置
  • mypy 配置
  • ruff 配置
toml 复制代码
[project]
name = "demo"
version = "0.1.0"

[tool.pytest.ini_options]
testpaths = ["tests"]

74. Python 如何读取环境变量?

python 复制代码
import os

os.environ["APP_ENV"] = "dev"

print(os.getenv("APP_ENV"))

输出:

text 复制代码
dev

75. __all__ 有什么作用?

__all__ 用于控制 from module import * 导入的内容。

python 复制代码
__all__ = ["hello"]

def hello():
    print("hello")

def hidden():
    print("hidden")

九、并发、线程、进程、协程

76. 线程适合什么场景?

线程适合 IO 密集型任务,例如:

  • 网络请求
  • 文件读写
  • 数据库访问
  • 接口调用
python 复制代码
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()

输出:

text 复制代码
A done
B done

77. 什么是 GIL?

GIL 是 CPython 中的全局解释器锁。

它会限制多个线程同时执行 Python 字节码,所以 CPU 密集型任务通常无法通过多线程获得明显性能提升。

python 复制代码
def cpu_task():
    return sum(i * i for i in range(100000))

print(cpu_task())

输出:

text 复制代码
333328333350000

78. 进程适合什么场景?

进程适合 CPU 密集型任务。

多进程可以利用多核 CPU。

python 复制代码
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]))

输出:

text 复制代码
[1, 4, 9]

79. 为什么 Windows 下多进程要写 if __name__ == "__main__"

因为 Windows 创建子进程时会重新导入主模块。

如果不加保护,可能导致子进程重复创建子进程。

python 复制代码
from multiprocessing import Process

def hello():
    print("hello")

if __name__ == "__main__":
    p = Process(target=hello)
    p.start()
    p.join()

输出:

text 复制代码
hello

80. 协程适合什么场景?

协程适合高并发 IO 场景,例如:

  • 网络请求
  • WebSocket
  • 异步数据库
  • 异步爬虫
  • 高并发接口调用
python 复制代码
import asyncio

async def main():
    print("start")
    await asyncio.sleep(1)
    print("end")

asyncio.run(main())

输出:

text 复制代码
start
end

81. asyncawait 是什么?

async 用于定义协程函数。

await 用于等待异步操作完成。

python 复制代码
import asyncio

async def fetch():
    await asyncio.sleep(1)
    return "data"

async def main():
    result = await fetch()
    print(result)

asyncio.run(main())

输出:

text 复制代码
data

82. 如何并发运行多个协程?

使用 asyncio.gather()

python 复制代码
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())

输出:

text 复制代码
['A done', 'B done']

83. time.sleep()asyncio.sleep() 有什么区别?

time.sleep() 会阻塞当前线程。

asyncio.sleep() 会让出事件循环,不阻塞其他协程。

python 复制代码
import asyncio

async def task():
    await asyncio.sleep(1)
    print("done")

asyncio.run(task())

输出:

text 复制代码
done

84. 如何避免多个线程同时修改共享数据?

可以使用锁。

python 复制代码
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)

输出:

text 复制代码
20000

十、常用标准库与实战能力

85. collections.defaultdict 有什么用?

defaultdict 可以给不存在的 key 自动创建默认值。

python 复制代码
from collections import defaultdict

d = defaultdict(list)

d["python"].append("good")

print(d)

输出:

text 复制代码
defaultdict(<class 'list'>, {'python': ['good']})

86. deque 适合什么场景?

deque 是双端队列,适合从两端快速添加和删除元素。

python 复制代码
from collections import deque

q = deque([1, 2])

q.appendleft(0)
q.append(3)

print(q)

输出:

text 复制代码
deque([0, 1, 2, 3])

87. heapq 有什么用?

heapq 可以实现堆,常用于:

  • Top K
  • 优先队列
  • 小顶堆
python 复制代码
import heapq

nums = [5, 1, 3]

heapq.heapify(nums)

print(heapq.heappop(nums))

输出:

text 复制代码
1

88. json.dumps()json.loads() 有什么区别?

json.dumps() 把 Python 对象转成 JSON 字符串。

json.loads() 把 JSON 字符串转成 Python 对象。

python 复制代码
import json

s = json.dumps({"name": "vito"}, ensure_ascii=False)
print(s)

obj = json.loads(s)
print(obj["name"])

输出:

text 复制代码
{"name": "vito"}
vito

89. 如何处理 Decimal 不能直接 JSON 序列化的问题?

可以转换为字符串或浮点数。

如果是金额、精度敏感场景,建议转换为字符串。

python 复制代码
import json
from decimal import Decimal

data = {"price": str(Decimal("10.50"))}

print(json.dumps(data))

输出:

text 复制代码
{"price": "10.50"}

90. pathlib 相比 os.path 有什么好处?

pathlib 是面向对象的路径处理方式,路径拼接更直观。

python 复制代码
from pathlib import Path

p = Path("logs") / "app.log"

print(p)

输出:

text 复制代码
logs/app.log

91. 如何读取 CSV 文件?

python 复制代码
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)

输出:

text 复制代码
{'name': 'vito', 'score': '90'}

92. 如何记录日志?

python 复制代码
import logging

logging.basicConfig(level=logging.INFO)

logging.info("service started")

输出示例:

text 复制代码
INFO:root:service started

93. 如何写单元测试?

python 复制代码
def add(a, b):
    return a + b

def test_add():
    assert add(1, 2) == 3

使用 pytest 运行:

bash 复制代码
pytest test_demo.py

输出示例:

text 复制代码
1 passed in 0.01s

94. pytest.raises 怎么用?

python 复制代码
import pytest

def div(a, b):
    return a / b

def test_div_zero():
    with pytest.raises(ZeroDivisionError):
        div(1, 0)

输出示例:

text 复制代码
1 passed in 0.01s

十一、性能、内存、编码规范

95. 如何查看对象占用内存?

python 复制代码
import sys

a = [1, 2, 3]

print(sys.getsizeof(a))

输出示例:

text 复制代码
88

具体数值和 Python 版本、操作系统有关。


96. 如何优化大列表处理?

能用生成器就不要一次性创建大列表。

python 复制代码
total = sum(x * x for x in range(1000000))

print(total)

输出:

text 复制代码
333332833333500000

97. 浅拷贝和深拷贝有什么区别?

浅拷贝只复制外层对象。

深拷贝会递归复制内部对象。

python 复制代码
import copy

a = [[1, 2], [3, 4]]

b = copy.copy(a)
c = copy.deepcopy(a)

a[0].append(99)

print(b)
print(c)

输出:

text 复制代码
[[1, 2, 99], [3, 4]]
[[1, 2], [3, 4]]

98. with 为什么比手动 close() 更安全?

因为即使中间发生异常,with 也会执行资源释放逻辑。

python 复制代码
try:
    with open("demo.txt", "r", encoding="utf-8") as f:
        print(f.read())
except FileNotFoundError:
    print("file not found")

输出示例:

text 复制代码
hello

或者:

text 复制代码
file not found

99. Python 代码规范主要看什么?

常见关注点包括:

  1. 命名清晰
  2. 函数不要太长
  3. 异常不要乱吞
  4. 不要写重复代码
  5. 复杂逻辑拆函数
  6. 遵循 PEP 8 风格
  7. 加必要的类型注解
  8. 加必要的单元测试
python 复制代码
def calculate_total_price(price: float, count: int) -> float:
    return price * count

print(calculate_total_price(9.9, 3))

输出:

text 复制代码
29.700000000000003

如果涉及金额,建议使用 Decimal


100. 面试中如何回答"你怎么提升 Python 代码质量"?

可以从以下几个方面回答:

  1. 使用类型注解提升可读性
  2. 使用 pytest 编写单元测试
  3. 使用 logging 记录关键日志
  4. 使用异常处理保证程序稳定
  5. 使用虚拟环境隔离依赖
  6. 使用 requirements.txt 或 pyproject.toml 管理依赖
  7. 使用 black、ruff、mypy 等工具做代码检查
  8. 使用 CI 流水线自动执行测试和代码扫描
  9. 复杂逻辑模块化
  10. 性能敏感代码做 profiling 分析
python 复制代码
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]))

输出:

text 复制代码
90.0

十二、总结:Python 面试不是背答案,而是建立知识网络

这 100 个问题可以分成 8 条主线:

  1. 基础语法:变量、对象、类型、真假判断
  2. 数据结构:字符串、列表、元组、字典、集合
  3. 函数能力:参数、闭包、装饰器、高阶函数
  4. 面向对象:类、继承、魔术方法、属性管理
  5. 异常与资源:异常捕获、上下文管理器、文件处理
  6. 并发模型:线程、进程、协程、GIL、锁
  7. 标准库:json、csv、pathlib、logging、collections
  8. 工程质量:虚拟环境、依赖管理、测试、类型注解、代码规范

真正的面试重点不是"你是否见过这个问题",而是你能否用清晰的语言说明原理,并写出可靠的小例子。

最好的准备方式是:

  1. 每个问题都自己敲一遍代码
  2. 观察真实输出
  3. 尝试修改参数和边界条件
  4. 主动制造异常场景
  5. 把问题串成知识体系

当你能把一个知识点讲清楚、写明白、举出例子,并能说出常见坑点时,面试基本就稳了一半。


附:面试复习建议

如果你准备 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 官方文档
相关推荐
阿正呀1 小时前
如何显著提升 Google Sheets 数据库批量更新脚本的执行效率
jvm·数据库·python
Rkgua1 小时前
路径传参和查询传参和请求体传参区以及Vue和React的用法区分
前端·面试
想取一个与众不同的名字好难1 小时前
QT webSocket接收客户端发送的双目摄像头数据并显示
开发语言·qt·websocket
dFObBIMmai1 小时前
MySQL迁移过程如何避免数据不一致_利用强一致性备份方案
jvm·数据库·python
驼同学.1 小时前
【求职季】LeetCode Hot 100 渐进式扫盲手册(Python版)
python·算法·leetcode
li星野1 小时前
二分查找六题通关:从标准模板到旋转数组(Python + C++)
java·c++·python
Kiyra1 小时前
LLM 的 JSON 不靠谱:结构化输出的重试与修复实战
开发语言·python·json
u0110225121 小时前
SQL如何利用聚合函数进行库存预测_历史数据分组汇总
jvm·数据库·python
Trouville011 小时前
学习tips:一些可以持续学习的网络体系教程
python·深度学习