跳转至

Python 面试题

40 道 Python 面试高频题 + 详细解答,覆盖基础概念、高级特性、并发编程、实战问题等核心知识点。


一、基础概念( 10 题)

1. Python 是解释型语言还是编译型语言

Python 既有编译过程,也有解释过程。 严格来说是"先编译后解释"的混合型。

执行过程:

Text Only
.py源代码 → 编译器 → .pyc字节码(bytecode) → Python虚拟机(PVM)解释执行
  • 编译阶段: Python 源码被编译为字节码(.pyc 文件),这是一种中间代码,不是机器码
  • 解释阶段: Python 虚拟机( PVM/解释器)逐条解释执行字节码

与真正的编译型语言的区别: - C/C++:源码 → 编译 → 机器码 → 直接运行(速度快) - Java :源码 → 编译 → 字节码 → JVM 执行( JIT 可编译为机器码) - Python :源码 → 编译 → 字节码 → PVM 解释执行(不同解释器实现差异较大; CPython 近年开始引入实验性 JIT 路线,但默认行为和成熟度会随版本变化)

查看字节码:

Python
import dis

def add(a, b):
    return a + b

dis.dis(add)
# 输出:
#   LOAD_FAST    0 (a)
#   LOAD_FAST    1 (b)
#   BINARY_ADD
#   RETURN_VALUE
# 注意:Python 3.11+ 使用 BINARY_OP 替代了 BINARY_ADD/BINARY_SUBTRACT 等独立指令。

Python 的实现版本: - CPython:官方实现, C 语言编写的解释器(最常用) - PyPy:带 JIT 编译的实现,速度更快 - Jython:运行在 JVM 上 - IronPython:运行在.NET 上

2. Python 中可变类型和不可变类型有哪些

不可变类型( Immutable ): - intfloatboolstrtuplefrozensetbytes

可变类型( Mutable ): - listdictsetbytearray

不可变类型的特点:

Python
a = "hello"
print(id(a))       # 140234567890
a = a + " world"   # 创建了新对象
print(id(a))       # 140234567999 (id变了!)

# 字符串是不可变的,"修改"实际上是创建新对象

可变类型的特点:

Python
lst = [1, 2, 3]
print(id(lst))     # 140234567890
lst.append(4)      # 在原对象上修改
print(id(lst))     # 140234567890 (id不变!)

函数传参的影响:

Python
def modify(x, lst):
    x = x + 1       # 不可变类型: 创建新对象, 不影响外部
    lst.append(4)    # 可变类型: 修改原对象, 影响外部

a = 10
b = [1, 2, 3]
modify(a, b)
print(a)  # 10  (没变)
print(b)  # [1, 2, 3, 4]  (被修改了)

面试关键点: Python 中的参数传递是"传对象引用"( Pass by Object Reference ),不可变对象的修改会创建新对象,可变对象的修改是就地修改。

3. 深拷贝和浅拷贝有什么区别

赋值(=): 不拷贝,只是引用同一个对象

Python
a = [1, [2, 3]]
b = a           # b和a指向同一个对象
b[0] = 99
print(a)        # [99, [2, 3]]  (a也变了)

浅拷贝( Shallow Copy ): 创建新的外层对象,但内层对象仍是引用

Python
import copy

a = [1, [2, 3]]
b = copy.copy(a)    # 浅拷贝 (也可以: b = a[:] 或 b = list(a))
# a: [1, [2, 3]]     id(a) = 100
#     ↑    ↑
#     1    [2,3]      id([2,3]) = 200
#     ↑    ↑
# b: [1, [2, 3]]     id(b) = 300  (新外层对象)

b[0] = 99           # 修改不可变元素 → 不影响a
print(a)             # [1, [2, 3]]  ✅

b[1].append(4)       # 修改可变元素(内层引用) → 影响a
print(a)             # [1, [2, 3, 4]]  ❌ a也变了!

深拷贝( Deep Copy ): 递归地创建所有层级的新对象

Python
a = [1, [2, 3]]
b = copy.deepcopy(a)  # 深拷贝

b[1].append(4)
print(a)              # [1, [2, 3]]  ✅ a没变
print(b)              # [1, [2, 3, 4]]

图解对比:

Text Only
赋值:         a ──→ [1, [2,3]]
              b ──↗

浅拷贝:       a ──→ [1, ──→ [2,3]]
              b ──→ [1, ──↗     ]  (外层不同, 内层共享)

深拷贝:       a ──→ [1, ──→ [2,3]]
              b ──→ [1, ──→ [2,3]]  (完全独立)

浅拷贝的方式:

Python
# 列表
b = a[:]  # 切片操作:[start:end:step]提取子序列
b = list(a)
b = a.copy()
b = copy.copy(a)

# 字典
b = dict(a)
b = a.copy()
b = {**a}

4. is 和 == 有什么区别

Python
# == 比较值是否相等
# is 比较是否是同一个对象(内存地址/id是否相同)

a = [1, 2, 3]
b = [1, 2, 3]
print(a == b)   # True  (值相等)
print(a is b)   # False (不同对象)

c = a
print(a is c)   # True  (同一对象)

Python 的小整数缓存池:

Python
# Python缓存了-5到256的整数
a = 256
b = 256
print(a is b)   # True (缓存池中同一个对象)

a = 257
b = 257
print(a is b)   # False (超出缓存范围, 不同对象)
# 注意: 在交互式环境和脚本中行为可能不同

字符串驻留( intern ):

Python
a = "hello"
b = "hello"
print(a is b)    # True (短字符串驻留)

a = "hello world!"
b = "hello world!"
print(a is b)    # 不一定 (含特殊字符可能不驻留)

面试关键点: - == 调用 __eq__ 方法 - is 比较 id() - None 的比较推荐用 isif x is None

5. args 和 *kwargs 是什么

Python
# *args: 接收任意数量的位置参数, 打包成元组(tuple)
# **kwargs: 接收任意数量的关键字参数, 打包成字典(dict)

def func(*args, **kwargs):
    print(f"args: {args}")         # 元组
    print(f"kwargs: {kwargs}")     # 字典

func(1, 2, 3, name="张三", age=25)
# args: (1, 2, 3)
# kwargs: {'name': '张三', 'age': 25}

参数顺序:

Python
def func(a, b, *args, key1="default", **kwargs):
    pass
# 顺序: 普通参数 → *args → 关键字参数 → **kwargs

解包操作:

Python
# * 解包可迭代对象
lst = [1, 2, 3]
print(*lst)          # 1 2 3

# ** 解包字典
d = {"name": "张三", "age": 25}
def greet(name, age):
    print(f"{name}, {age}")
greet(**d)           # 张三, 25

# 合并字典
d1 = {"a": 1}
d2 = {"b": 2}
merged = {**d1, **d2}  # {"a": 1, "b": 2}

# 合并列表
l1 = [1, 2]
l2 = [3, 4]
merged = [*l1, *l2]  # [1, 2, 3, 4]

6. Python 的内存管理机制是什么

Python 内存管理由三个机制组成:

1. 引用计数( Reference Counting )— 主要机制

Python
import sys

a = [1, 2, 3]      # 引用计数 = 1
b = a               # 引用计数 = 2
print(sys.getrefcount(a))  # 3 (传参时临时+1)

del b               # 引用计数 = 1
del a               # 引用计数 = 0 → 立即释放内存

引用计数增加的情况: - 对象创建:a = "hello" - 引用赋值:b = a - 作为参数传递:func(a) - 加入容器:lst.append(a)

引用计数减少的情况: - del a - 变量被重新赋值 - 离开作用域 - 从容器中移除

引用计数的问题 — 循环引用:

Python
a = []
b = []
a.append(b)  # a引用b
b.append(a)  # b引用a

del a
del b
# 虽然删除了变量,但a和b的引用计数各为1(互相引用)
# 引用计数无法回收 → 需要垃圾回收器处理

2. 标记清除( Mark and Sweep ) - 解决循环引用问题 - 从 GC Roots (全局变量、栈上变量等)开始遍历 - 可达的对象标记为存活,不可达的回收

3. 分代回收( Generational Collection )

Text Only
第0代(Generation 0): 新创建的对象, 检查最频繁
    ↓ 存活
第1代(Generation 1): 经历过一次GC仍存活, 检查较少
    ↓ 存活
第2代(Generation 2): 长期存活的对象, 检查最少
  • 新对象放入第 0 代
  • 每次 GC 后存活的对象晋升到下一代
  • 高代的检查频率低(长期存活的对象大概率会继续存活)
Python
import gc

gc.get_threshold()        # (700, 10, 10) 默认阈值
# 第0代: 分配-释放 > 700次 触发GC
# 第1代: 第0代GC 10次后触发
# 第2代: 第1代GC 10次后触发

gc.collect()              # 手动触发完整GC
gc.get_count()            # 查看各代计数

7. Python 的垃圾回收机制如何手动控制

Python
import gc

# 查看GC状态
gc.isenabled()           # 是否启用
gc.get_threshold()       # GC触发阈值

# 手动控制
gc.disable()             # 禁用自动GC(高性能场景)
gc.enable()              # 启用自动GC
gc.collect()             # 手动触发GC,返回不可达对象数量

# 调整阈值
gc.set_threshold(700, 10, 10)

# 查找循环引用
gc.set_debug(gc.DEBUG_LEAK)  # 打印泄漏信息

weakref — 弱引用:

Python
import weakref

class MyClass:
    pass

obj = MyClass()
weak_ref = weakref.ref(obj)   # 弱引用不增加引用计数

print(weak_ref())   # <MyClass object>
del obj
print(weak_ref())   # None (对象已被回收)

弱引用常用于缓存、观察者模式等场景,避免循环引用导致内存泄漏。

8. Python 中的命名空间和作用域是什么

四种作用域( LEGB 规则):

Text Only
L - Local:       函数内部局部作用域
E - Enclosing:   闭包外层函数的作用域
G - Global:      模块级别的全局作用域
B - Built-in:    Python内置作用域
Python
x = "global"              # Global

def outer():
    x = "enclosing"       # Enclosing

    def inner():
        x = "local"       # Local
        print(x)          # 查找顺序: L → E → G → B

    inner()

outer()  # 输出: local

global 和 nonlocal 关键字:

Python
x = 10

def func():
    global x       # 声明使用全局变量x
    x = 20

func()
print(x)           # 20

def outer():
    x = 10
    def inner():
        nonlocal x  # 声明使用外层函数的x
        x = 20
    inner()
    print(x)        # 20

outer()

9. Python 中的闭包是什么

闭包( Closure ): 函数嵌套中,内层函数引用了外层函数的变量,并且外层函数返回内层函数。

Python
def make_counter():
    count = 0           # 外层变量
    def counter():
        nonlocal count
        count += 1      # 引用外层变量
        return count
    return counter       # 返回内层函数

c = make_counter()
print(c())  # 1
print(c())  # 2
print(c())  # 3

# count变量在make_counter返回后仍然存活(被闭包引用)

闭包的常见陷阱 — 延迟绑定:

Python
# 经典问题
functions = []
for i in range(5):
    def func():
        return i
    functions.append(func)

print([f() for f in functions])
# [4, 4, 4, 4, 4]  不是 [0, 1, 2, 3, 4]!
# 因为闭包引用的是变量i,循环结束后i=4

# 解决方案1:使用默认参数
functions = []
for i in range(5):
    def func(x=i):    # 默认参数在定义时求值
        return x
    functions.append(func)
print([f() for f in functions])  # [0, 1, 2, 3, 4]

# 解决方案2:使用functools.partial
from functools import partial
functions = [partial(lambda x: x, i) for i in range(5)]

10. Python 的魔术方法 __new____init__ 有什么区别

Python
class MyClass:
    def __new__(cls, *args, **kwargs):
        print("__new__ called")
        instance = super().__new__(cls)  # 创建实例
        return instance                   # 必须返回实例

    def __init__(self, name):
        print("__init__ called")
        self.name = name                  # 初始化实例

obj = MyClass("张三")
# 输出:
# __new__ called
# __init__ called
对比 __new__ __init__
作用 创建实例(构造器) 初始化实例(初始化器)
参数 cls (类本身) self (实例本身)
返回值 必须返回实例 不返回( None )
调用时机 先调用 后调用(__new__返回实例后)
类型 静态方法 实例方法
用途 单例模式、不可变类型子类化 属性赋值

__new__ 的典型应用 — 单例模式:

Python
class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

a = Singleton()
b = Singleton()
print(a is b)  # True (同一个实例)

二、高级特性( 10 题)

11. Python 装饰器的原理是什么?如何实现参数装饰器和类装饰器

装饰器的本质: 接收一个函数,返回一个新函数(或修改过的函数)。

基础装饰器:

Python
def timer(func):
    import time
    def wrapper(*args, **kwargs):
        start = time.time()
        result = func(*args, **kwargs)
        end = time.time()
        print(f"{func.__name__} 耗时: {end - start:.4f}s")
        return result
    return wrapper

@timer  # 等价于: my_func = timer(my_func)
def my_func():
    time.sleep(1)

my_func()  # my_func 耗时: 1.0012s

functools.wraps 的作用:

Python
from functools import wraps

def timer(func):
    @wraps(func)  # 保留原函数的元信息(__name__, __doc__等)
    def wrapper(*args, **kwargs):
        return func(*args, **kwargs)
    return wrapper

# 不用@wraps: my_func.__name__ = 'wrapper'  ❌
# 使用@wraps: my_func.__name__ = 'my_func'  ✅

带参数的装饰器(三层嵌套):

Python
def retry(max_retries=3, delay=1):
    def decorator(func):
        @wraps(func)
        def wrapper(*args, **kwargs):
            for i in range(max_retries):
                try:
                    return func(*args, **kwargs)
                except Exception as e:
                    if i == max_retries - 1:
                        raise
                    print(f"重试 {i+1}/{max_retries}: {e}")
                    time.sleep(delay)
        return wrapper
    return decorator

@retry(max_retries=5, delay=2)  # 等价于: func = retry(5, 2)(func)
def fetch_data():
    pass

类装饰器:

Python
class CacheDecorator:
    def __init__(self, func):
        self.func = func
        self.cache = {}

    def __call__(self, *args):
        if args in self.cache:
            return self.cache[args]
        result = self.func(*args)
        self.cache[args] = result
        return result

@CacheDecorator
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

print(fibonacci(10))  # 55 (有缓存加速)

用装饰器装饰类(类作为被装饰对象):

Python
def singleton(cls):
    instances = {}
    @wraps(cls)
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class Database:
    pass

多个装饰器的执行顺序:

Python
@decorator_a
@decorator_b
def func():
    pass
# 等价于: func = decorator_a(decorator_b(func))
# 装饰顺序: 从下到上
# 执行顺序: 从上到下

12. 生成器和迭代器有什么区别? yield 的原理是什么

迭代器( Iterator ): - 实现了 __iter__()__next__() 方法的对象 - 可以用 next() 逐个获取元素

Python
class CountDown:
    def __init__(self, n):
        self.n = n

    def __iter__(self):
        return self

    def __next__(self):
        if self.n <= 0:
            raise StopIteration
        self.n -= 1
        return self.n + 1

for num in CountDown(5):
    print(num)  # 5, 4, 3, 2, 1

生成器( Generator ): - 使用 yield 的函数,调用后返回生成器对象 - 是迭代器的简洁写法 - 惰性计算:不一次性生成所有数据,而是按需生成

Python
def countdown(n):
    while n > 0:
        yield n     # 暂停并返回值
        n -= 1      # 下次从这里继续

gen = countdown(5)
print(next(gen))  # 5
print(next(gen))  # 4

yield 的原理: - yield 暂停函数执行,保存函数的状态(局部变量、指令位置) - next() 恢复函数执行,从上次 yield 的位置继续 - 函数体执行完毕后抛出 StopIteration

send() 方法:

Python
def accumulator():
    total = 0
    while True:
        value = yield total  # yield返回total, 同时接收send的值
        total += value

gen = accumulator()
next(gen)           # 0  (初始化,必须先next一次)
print(gen.send(10)) # 10
print(gen.send(20)) # 30
print(gen.send(30)) # 60

yield from — 委托生成器:

Python
def sub_gen():
    yield 1
    yield 2

def main_gen():
    yield from sub_gen()  # 等价于: for x in sub_gen(): yield x
    yield 3

list(main_gen())  # [1, 2, 3]

生成器表达式:

Python
# 列表推导 → 立即生成所有元素
lst = [x**2 for x in range(1000000)]   # 占用大量内存

# 生成器表达式 → 惰性计算
gen = (x**2 for x in range(1000000))   # 几乎不占内存

13. 上下文管理器是什么?如何实现

上下文管理器:with 语句管理资源的获取和释放。

方式 1 :实现 __enter____exit__ 方法

Python
class FileManager:
    def __init__(self, filename, mode):
        self.filename = filename
        self.mode = mode
        self.file = None

    def __enter__(self):
        self.file = open(self.filename, self.mode)
        return self.file       # with ... as f 中f的值

    def __exit__(self, exc_type, exc_val, exc_tb):
        # exc_type: 异常类型, exc_val: 异常值, exc_tb: traceback
        if self.file:
            self.file.close()
        return False            # True表示异常已处理, 不再抛出

with FileManager("test.txt", "w") as f:
    f.write("hello")
# 离开with块时自动调用__exit__, 关闭文件

方式 2 :使用 contextmanager 装饰器

Python
from contextlib import contextmanager

@contextmanager
def file_manager(filename, mode):
    f = open(filename, mode)
    try:
        yield f            # yield之前是__enter__, yield的值是as后的变量
    finally:
        f.close()          # yield之后是__exit__

with file_manager("test.txt", "w") as f:
    f.write("hello")

实际应用场景:

Python
# 数据库连接
@contextmanager
def db_connection():
    conn = create_connection()
    try:
        yield conn
        conn.commit()      # 没异常则提交
    except Exception:
        conn.rollback()    # 有异常则回滚
        raise
    finally:
        conn.close()       # 总是关闭连接

# 计时器
@contextmanager
def timer(label):
    start = time.time()
    yield
    print(f"{label}: {time.time() - start:.4f}s")

with timer("处理数据"):
    process_data()

# 临时修改工作目录
@contextmanager
def working_directory(path):
    old_dir = os.getcwd()
    os.chdir(path)
    try:
        yield
    finally:
        os.chdir(old_dir)

14. Python 的元类( metaclass )是什么

元类: 类的类。类是元类的实例。

Python
# 普通对象是类的实例
# 类是元类的实例
# 默认元类是 type

class MyClass:
    pass

print(type(MyClass))        # <class 'type'>
print(type(type))           # <class 'type'>  (type的元类是自身)

type 动态创建类:

Python
# 以下两种方式等价:

# 方式1: class语句
class Dog:
    sound = "woof"
    def speak(self):
        return self.sound

# 方式2: type()
Dog = type("Dog", (object,), {
    "sound": "woof",
    "speak": lambda self: self.sound
})

自定义元类:

Python
class MyMeta(type):
    def __new__(mcs, name, bases, namespace):
        # 在类创建时执行
        print(f"Creating class: {name}")

        # 强制所有方法名小写
        for key in list(namespace.keys()):
            if callable(namespace[key]) and not key.startswith('_'):
                if key != key.lower():
                    raise ValueError(f"方法名必须是小写: {key}")

        return super().__new__(mcs, name, bases, namespace)

class MyClass(metaclass=MyMeta):
    def my_method(self):  # ✅
        pass
    # def MyMethod(self):  # ❌ ValueError
    #     pass

ORM 示例 — 元类的实际应用:

Python
class ModelMeta(type):
    def __new__(mcs, name, bases, namespace):
        if name == 'Model':  # 跳过基类
            return super().__new__(mcs, name, bases, namespace)

        # 收集字段定义
        fields = {}
        for key, value in namespace.items():
            if isinstance(value, Field):
                fields[key] = value

        namespace['_fields'] = fields
        namespace['_table_name'] = name.lower() + 's'

        return super().__new__(mcs, name, bases, namespace)

class Field:
    def __init__(self, field_type):
        self.field_type = field_type

class Model(metaclass=ModelMeta):
    def save(self):
        fields = ', '.join(self._fields.keys())
        print(f"INSERT INTO {self._table_name} ({fields}) ...")

class User(Model):
    name = Field("VARCHAR(100)")
    age = Field("INT")

user = User()
user.save()  # INSERT INTO users (name, age) ...

15. 什么是描述符协议

描述符( Descriptor ): 实现了 __get____set____delete__ 中任意一个方法的类。

Python
class TypedField:
    """类型检查描述符"""
    def __init__(self, name, expected_type):
        self.name = name
        self.expected_type = expected_type

    def __get__(self, obj, objtype=None):
        if obj is None:
            return self
        return obj.__dict__.get(self.name)

    def __set__(self, obj, value):
        if not isinstance(value, self.expected_type):
            raise TypeError(f"{self.name}必须是{self.expected_type}")
        obj.__dict__[self.name] = value

    def __delete__(self, obj):
        del obj.__dict__[self.name]

class Person:
    name = TypedField("name", str)
    age = TypedField("age", int)

    def __init__(self, name, age):
        self.name = name    # 触发 __set__
        self.age = age

p = Person("张三", 25)       # ✅
# p = Person("张三", "25")   # ❌ TypeError

描述符的分类: - 数据描述符:实现了 __get____set__(优先级最高) - 非数据描述符:只实现了 __get__(如函数/方法)

Python 内置的描述符应用: - property(属性) - staticmethod(静态方法) - classmethod(类方法) - 函数(function.__get__ 实现了方法绑定)

16. property 装饰器的原理和用法是什么

Python
class Circle:
    def __init__(self, radius):
        self._radius = radius

    @property  # @property将方法变为属性访问
    def radius(self):
        """getter"""
        return self._radius

    @radius.setter
    def radius(self, value):
        """setter"""
        if value < 0:
            raise ValueError("半径不能为负数")
        self._radius = value

    @radius.deleter
    def radius(self):
        """deleter"""
        del self._radius

    @property
    def area(self):
        """只读属性(计算属性)"""
        return 3.14159 * self._radius ** 2

c = Circle(5)
print(c.radius)     # 5      (调用getter)
c.radius = 10       # 调用setter
print(c.area)       # 314.159 (只读计算属性)
# c.area = 100      # ❌ AttributeError (没有setter)

property 的底层是描述符:

Python
# @property 等价于:
class Circle:
    def get_radius(self):
        return self._radius
    def set_radius(self, value):
        self._radius = value
    radius = property(get_radius, set_radius)

17. Python 中如何实现抽象类和接口

Python
from abc import ABC, abstractmethod  # ABC抽象基类;abstractmethod强制子类实现

class Shape(ABC):  # 抽象基类
    @abstractmethod
    def area(self):
        """子类必须实现"""
        pass

    @abstractmethod
    def perimeter(self):
        pass

    def description(self):
        """普通方法,子类可以直接使用"""
        return f"这是一个{self.__class__.__name__}"

class Circle(Shape):
    def __init__(self, radius):
        self.radius = radius

    def area(self):      # 必须实现
        return 3.14 * self.radius ** 2

    def perimeter(self):  # 必须实现
        return 2 * 3.14 * self.radius

# shape = Shape()    # ❌ TypeError: 不能实例化抽象类
circle = Circle(5)   # ✅

18. __slots__ 的作用和原理是什么

Python
class WithoutSlots:
    def __init__(self, x, y):
        self.x = x
        self.y = y

class WithSlots:
    __slots__ = ('x', 'y')  # 限制实例只能有x和y属性

    def __init__(self, x, y):
        self.x = x
        self.y = y

# 不用__slots__: 使用__dict__存储属性
a = WithoutSlots(1, 2)
a.z = 3      # ✅ 可以动态添加属性
print(a.__dict__)  # {'x': 1, 'y': 2, 'z': 3}

# 使用__slots__: 不使用__dict__, 使用更紧凑的内部结构
b = WithSlots(1, 2)
# b.z = 3    # ❌ AttributeError
# b.__dict__ # ❌ 没有__dict__

__slots__ 的优点: 1. 节省内存:不再使用 __dict__,每个实例可以节省约 40-50%内存 2. 访问速度更快:属性存储使用固定的偏移量 3. 限制属性:防止意外添加属性

适用场景: 需要创建大量实例的类(如数据对象、 ORM 实体)

19. 协程是什么? async/await 的原理是什么

协程( Coroutine ): 可以在执行过程中暂停和恢复的函数,适用于 IO 密集型的并发编程。

Python
import asyncio

async def fetch_data(url):
    print(f"开始请求 {url}")
    await asyncio.sleep(1)       # 模拟IO操作,让出控制权
    print(f"请求完成 {url}")
    return f"数据: {url}"

async def main():
    # 并发执行多个协程
    tasks = [
        asyncio.create_task(fetch_data("url1")),
        asyncio.create_task(fetch_data("url2")),
        asyncio.create_task(fetch_data("url3")),
    ]
    results = await asyncio.gather(*tasks)
    print(results)

asyncio.run(main())
# 三个请求并发执行,总耗时约1秒而非3秒

async/await 的本质: - async def 定义协程函数,返回协程对象 - await 暂停当前协程,等待另一个协程完成 - 协程在单线程中运行,通过事件循环( Event Loop )调度 - 遇到 IO 等待时让出 CPU ,执行其他协程

20. Python 中的设计模式 — 观察者模式实现

Python
class EventEmitter:
    def __init__(self):
        self._listeners = {}

    def on(self, event, callback):
        """注册监听器"""
        if event not in self._listeners:
            self._listeners[event] = []
        self._listeners[event].append(callback)

    def emit(self, event, *args, **kwargs):
        """触发事件"""
        for callback in self._listeners.get(event, []):
            callback(*args, **kwargs)

    def off(self, event, callback):
        """移除监听器"""
        if event in self._listeners:
            self._listeners[event].remove(callback)

# 使用
emitter = EventEmitter()

def on_user_login(user):
    print(f"发送欢迎邮件给 {user}")

def on_user_login_log(user):
    print(f"记录登录日志: {user}")

emitter.on("login", on_user_login)
emitter.on("login", on_user_login_log)
emitter.emit("login", "张三")
# 发送欢迎邮件给 张三
# 记录登录日志: 张三

三、并发编程( 10 题)

21. Python 的 GIL 是什么?它有什么影响?如何规避

GIL ( Global Interpreter Lock ,全局解释器锁): CPython 解释器中的一个互斥锁,确保同一时刻只有一个线程执行 Python 字节码。

为什么有 GIL ? - CPython 的内存管理(引用计数)不是线程安全的 - GIL 是最简单的保护方式 - 历史原因:很多 C 扩展依赖 GIL

GIL 的影响: - CPU 密集型任务:多线程无法利用多核,性能约等于单线程 - IO 密集型任务:线程在等 IO 时会释放 GIL ,影响较小

Python
# CPU密集型: 多线程反而更慢(GIL + 线程切换开销)
import threading
import time

def cpu_bound():
    count = 0
    for _ in range(10**7):
        count += 1

# 单线程
start = time.time()
cpu_bound()
cpu_bound()
print(f"单线程: {time.time()-start:.2f}s")  # ~1.5s

# 多线程
start = time.time()
t1 = threading.Thread(target=cpu_bound)
t2 = threading.Thread(target=cpu_bound)
t1.start(); t2.start()
t1.join(); t2.join()
print(f"多线程: {time.time()-start:.2f}s")  # ~1.5s (没有加速!)

规避 GIL 的方法:

  1. 多进程( multiprocessing ):每个进程有自己的 GIL
Python
from multiprocessing import Pool

with Pool(4) as p:
    results = p.map(cpu_bound_func, data_list)
  1. C 扩展: Numpy 、 Pandas 等 C 实现的库在计算时会释放 GIL

  2. 异步 IO ( asyncio ): IO 密集型、高并发网络场景中的常见选择之一

  3. 使用其他解释器: PyPy 、 Jython (无 GIL )

  4. Python 3.13+ 自由线程模式:实验性的无 GIL 模式

22. 多线程、多进程和协程的区别是什么?各自的适用场景

维度 多线程 多进程 协程
并发模型 抢占式 抢占式 协作式
切换开销 中等 大(需要切换进程上下文) 小(用户态切换)
内存共享 共享(需要加锁) 不共享(需要 IPC ) 共享(单线程)
GIL 影响 受限 不受限 不涉及
适用场景 IO 密集型 CPU 密集型 IO 密集型(高并发)
资源消耗
创建数量 百级 十级 万级
编程复杂度 中(需要锁) 中(需要 IPC ) 低( async/await )

适用场景总结: - 多线程:爬虫( IO 等待多)、文件读写、网络请求 - 多进程:数据分析( CPU 计算密集)、图像处理、科学计算 - 协程:高并发网络服务( Web 服务器)、大量 API 调用

23. threading 模块的同步原语有哪些

1. Lock (互斥锁)

Python
import threading

lock = threading.Lock()
counter = 0

def increment():
    global counter
    for _ in range(100000):
        lock.acquire()      # 加锁
        try:
            counter += 1
        finally:
            lock.release()   # 释放锁

# 简洁写法
def increment():
    global counter
    for _ in range(100000):
        with lock:           # 自动加锁和释放
            counter += 1

2. RLock (可重入锁)

Python
rlock = threading.RLock()

def recursive_func(n):
    with rlock:             # 同一线程可以多次获取
        if n > 0:
            recursive_func(n - 1)

3. Semaphore (信号量)

Python
# 限制并发数
sem = threading.Semaphore(3)  # 最多3个线程同时执行

def worker():
    with sem:
        print(f"{threading.current_thread().name} 开始工作")
        time.sleep(1)

4. Event (事件)

Python
event = threading.Event()

def waiter():
    print("等待事件...")
    event.wait()        # 阻塞等待
    print("事件触发!")

def setter():
    time.sleep(2)
    event.set()         # 触发事件

5. Condition (条件变量)

Python
condition = threading.Condition()
items = []

def producer():
    with condition:
        items.append("item")
        condition.notify()      # 通知消费者

def consumer():
    with condition:
        while not items:
            condition.wait()    # 等待通知
        item = items.pop()

24. multiprocessing 模块怎么使用

进程池( Pool ):

Python
from multiprocessing import Pool

def process_data(x):
    return x ** 2

# 进程池
with Pool(processes=4) as pool:
    # map: 并行映射
    results = pool.map(process_data, range(100))

    # apply_async: 异步提交单个任务
    future = pool.apply_async(process_data, (42,))
    result = future.get(timeout=10)

    # starmap: 多参数映射
    results = pool.starmap(func, [(1, 2), (3, 4), (5, 6)])

进程间通信:

Python
from multiprocessing import Process, Queue, Pipe

# Queue
queue = Queue()

def producer(q):
    q.put("hello")

def consumer(q):
    msg = q.get()
    print(msg)

# Pipe
parent_conn, child_conn = Pipe()

def sender(conn):
    conn.send("message")
    conn.close()

def receiver(conn):
    msg = conn.recv()
    print(msg)

共享内存:

Python
from multiprocessing import Value, Array

counter = Value('i', 0)   # 共享整数
arr = Array('d', [0.0] * 10)  # 共享数组

def increment(counter):
    with counter.get_lock():
        counter.value += 1

25. asyncio 的事件循环和异步编程

Python
import asyncio
import aiohttp

# 异步HTTP请求
async def fetch_url(session, url):
    async with session.get(url) as response:
        return await response.text()

async def main():
    urls = [
        "https://api.example.com/1",
        "https://api.example.com/2",
        "https://api.example.com/3",
    ]

    async with aiohttp.ClientSession() as session:
        # 并发执行所有请求
        tasks = [fetch_url(session, url) for url in urls]
        results = await asyncio.gather(*tasks)

        # 或者使用 as_completed 按完成顺序处理
        for coro in asyncio.as_completed(tasks):
            result = await coro
            print(result)

asyncio.run(main())  # asyncio.run()启动异步事件循环

异步迭代器和异步生成器:

Python
# 异步生成器
async def async_range(n):
    for i in range(n):
        await asyncio.sleep(0.1)
        yield i  # yield生成器:惰性产出值,节省内存

# 异步迭代
async def main():
    async for num in async_range(10):
        print(num)

异步上下文管理器:

Python
class AsyncDB:
    async def __aenter__(self):
        self.conn = await create_connection()
        return self.conn

    async def __aexit__(self, exc_type, exc, tb):
        await self.conn.close()

async def main():
    async with AsyncDB() as conn:
        await conn.execute("SELECT ...")

26. concurrent.futures 模块的使用

Python
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor, as_completed

# 线程池
def fetch_data(url):
    import requests
    return requests.get(url).text

urls = ["url1", "url2", "url3", "url4"]

with ThreadPoolExecutor(max_workers=4) as executor:
    # 方式1: map (结果按提交顺序返回)
    results = list(executor.map(fetch_data, urls))

    # 方式2: submit + as_completed (结果按完成顺序返回)
    futures = {executor.submit(fetch_data, url): url for url in urls}
    for future in as_completed(futures):
        url = futures[future]
        try:
            data = future.result(timeout=10)
            print(f"{url}: {len(data)} bytes")
        except Exception as e:
            print(f"{url}: error {e}")

# 进程池 (用法一样,换成ProcessPoolExecutor)
with ProcessPoolExecutor(max_workers=4) as executor:
    results = list(executor.map(cpu_bound_func, data_list))

27. 如何在 Python 中安全地操作共享资源

Python
import threading
from queue import Queue
from collections import deque

# 方案1: 使用锁
lock = threading.Lock()
shared_data = []

def safe_append(item):
    with lock:
        shared_data.append(item)

# 方案2: 使用线程安全的Queue
task_queue = Queue()

def producer():
    task_queue.put("task1")

def consumer():
    task = task_queue.get()
    task_queue.task_done()

# 方案3: 使用threading.local()
local = threading.local()

def set_user(name):
    local.user = name  # 每个线程有独立的user变量

# 方案4: 使用atomic操作
# Python的某些操作是原子的(但不建议依赖):
# list.append(), dict[key]=value (由于GIL)

28. 什么是线程池?如何合理设置线程数

Python
from concurrent.futures import ThreadPoolExecutor

# 创建线程池
pool = ThreadPoolExecutor(max_workers=10)

# 线程数设置建议:
# IO密集型: 线程数 = CPU核心数 * 2 (或更多)
# CPU密集型: 进程数 = CPU核心数

import os
cpu_count = os.cpu_count()

# IO密集型任务
io_pool = ThreadPoolExecutor(max_workers=cpu_count * 2)

# CPU密集型任务(使用进程池)
from concurrent.futures import ProcessPoolExecutor
cpu_pool = ProcessPoolExecutor(max_workers=cpu_count)

29. Python 中的死锁问题如何避免

Python
# 死锁示例
lock_a = threading.Lock()
lock_b = threading.Lock()

def thread_1():
    with lock_a:
        time.sleep(0.1)
        with lock_b:    # 等待lock_b, 被thread_2持有
            pass

def thread_2():
    with lock_b:
        time.sleep(0.1)
        with lock_a:    # 等待lock_a, 被thread_1持有
            pass

# 避免死锁的方法:

# 方法1: 固定加锁顺序
def thread_1():
    with lock_a:        # 总是先获取lock_a
        with lock_b:
            pass

def thread_2():
    with lock_a:        # 总是先获取lock_a
        with lock_b:
            pass

# 方法2: 使用超时
acquired = lock_a.acquire(timeout=5)
if not acquired:
    # 获取锁超时,处理异常
    pass

# 方法3: 使用RLock(可重入锁)避免自锁

# 方法4: 使用with语句(自动释放锁,避免忘记释放)

30. asyncio 中的常用模式

Python
import asyncio

# 1. 超时控制
async def fetch_with_timeout():  # async def定义异步函数;用await调用
    try:
        result = await asyncio.wait_for(  # await等待异步操作完成
            slow_operation(),
            timeout=5.0
        )
    except asyncio.TimeoutError:
        print("超时!")

# 2. 限制并发数
async def limited_concurrency():
    semaphore = asyncio.Semaphore(10)  # 最多10个并发

    async def bounded_fetch(url):
        async with semaphore:
            return await fetch(url)

    tasks = [bounded_fetch(url) for url in urls]
    return await asyncio.gather(*tasks)

# 3. 异步队列
async def producer_consumer():
    queue = asyncio.Queue(maxsize=100)

    async def producer():
        for i in range(1000):
            await queue.put(i)
        await queue.put(None)  # 结束信号

    async def consumer():
        while True:
            item = await queue.get()
            if item is None:
                break
            await process(item)

    await asyncio.gather(producer(), consumer())

# 4. 异步锁
lock = asyncio.Lock()
async def safe_operation():
    async with lock:
        await critical_section()

四、实战问题( 10 题)

31. 单例模式的 5 种实现方法

方式 1 :使用模块(最简单,推荐)

Python
# singleton.py
class _Singleton:
    def __init__(self):
        self.value = None

instance = _Singleton()

# 使用: from singleton import instance

方式 2 :使用 __new__

Python
class Singleton:
    _instance = None

    def __new__(cls, *args, **kwargs):
        if cls._instance is None:
            cls._instance = super().__new__(cls)
        return cls._instance

a = Singleton()
b = Singleton()
print(a is b)  # True

方式 3 :使用装饰器

Python
def singleton(cls):
    instances = {}
    def get_instance(*args, **kwargs):
        if cls not in instances:
            instances[cls] = cls(*args, **kwargs)
        return instances[cls]
    return get_instance

@singleton
class Database:
    pass

方式 4 :使用元类

Python
class SingletonMeta(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]

class Database(metaclass=SingletonMeta):
    pass

方式 5 :线程安全的单例

Python
import threading  # 线程池/多线程:并发执行任务

class Singleton:
    _instance = None
    _lock = threading.Lock()

    def __new__(cls, *args, **kwargs):  # *args接收任意位置参数;**kwargs接收任意关键字参数
        if cls._instance is None:     # 双检锁
            with cls._lock:
                if cls._instance is None:
                    cls._instance = super().__new__(cls)  # super()调用父类方法
        return cls._instance

32. Python 性能优化的 10 个技巧

1. 选择合适的数据结构

Python
# 查找: dict/set O(1) vs list O(n)
# 大量查找时用set替代list
items = set(big_list)  # 查找O(1)
if item in items:      # 远快于 if item in big_list
    pass

2. 使用生成器处理大数据

Python
# ❌ 一次性加载
data = [process(line) for line in open("huge_file.txt")]

# ✅ 逐行处理
data = (process(line) for line in open("huge_file.txt"))

3. 利用局部变量

Python
# 局部变量比全局变量快
def process():
    local_func = some_module.func  # 缓存到局部
    for item in data:
        local_func(item)

4. 使用内置函数和 C 实现

Python
# ❌ Python循环
total = 0
for x in range(1000000):
    total += x

# ✅ 内置函数 (C实现, 快很多)
total = sum(range(1000000))

5. 字符串拼接用 join

Python
# ❌ 循环拼接 (每次创建新字符串)
s = ""
for x in items:
    s += str(x)

# ✅ join (一次性拼接)
s = "".join(str(x) for x in items)

6. 使用 collections 模块

Python
from collections import Counter, defaultdict, deque  # defaultdict带默认值的字典,避免KeyError

# Counter: 计数
word_count = Counter(words)  # Counter计数器:统计元素出现次数

# defaultdict: 默认值
graph = defaultdict(list)
graph[node].append(neighbor)

# deque: 双端队列 (左端操作O(1))
queue = deque()
queue.appendleft(item)  # O(1) vs list.insert(0, item) O(n)

7. 使用 lru_cache 缓存

Python
from functools import lru_cache

@lru_cache(maxsize=128)
def fibonacci(n):
    if n < 2:
        return n
    return fibonacci(n-1) + fibonacci(n-2)

8. 列表推导优于循环

Python
# ❌
result = []
for x in data:
    if x > 0:
        result.append(x ** 2)

# ✅ 更快
result = [x ** 2 for x in data if x > 0]

9. 使用 numpy 处理数值计算

Python
import numpy as np

# ❌ Python循环
result = [x * 2 for x in range(1000000)]

# ✅ numpy向量化 (快10-100倍)
arr = np.arange(1000000)
result = arr * 2

10. 使用性能分析工具

Bash
# cProfile
python -m cProfile script.py
Python
# line_profiler
@profile
def my_func():
    pass

# memory_profiler
@profile
def my_func():
    pass

33. Python 常用的 20 个魔术方法整理

魔术方法 用途 触发时机
__init__ 初始化 创建实例时
__new__ 创建实例 __init__之前
__del__ 析构 对象被销毁时
__str__ 用户友好的字符串 print()str()
__repr__ 开发者友好的字符串 repr()、交互式环境
__len__ 长度 len()
__getitem__ 索引取值 obj[key]
__setitem__ 索引赋值 obj[key] = value
__delitem__ 索引删除 del obj[key]
__contains__ 包含 item in obj
__iter__ 迭代 for x in obj
__next__ 下一个元素 next(obj)
__call__ 调用 obj()
__eq__ 等于 obj == other
__lt__ 小于 obj < other
__hash__ 哈希值 hash(obj)、 dict 的 key
__bool__ 布尔值 if objbool(obj)
__enter__/__exit__ 上下文管理器 with obj
__add__ 加法 obj + other
__slots__ 限制属性 类定义时
Python
class Vector:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f"Vector({self.x}, {self.y})"

    def __str__(self):
        return f"({self.x}, {self.y})"

    def __add__(self, other):
        return Vector(self.x + other.x, self.y + other.y)

    def __eq__(self, other):
        return self.x == other.x and self.y == other.y

    def __hash__(self):
        return hash((self.x, self.y))

    def __len__(self):
        return int((self.x**2 + self.y**2) ** 0.5)

    def __bool__(self):
        return self.x != 0 or self.y != 0

    def __call__(self, scalar):
        return Vector(self.x * scalar, self.y * scalar)

v1 = Vector(3, 4)
v2 = Vector(1, 2)
print(v1 + v2)      # (4, 6)
print(v1 == v2)      # False
print(v1(2))         # (6, 8)
print(len(v1))       # 5

34. Python 常用内置函数及其用法

Python
# map: 对每个元素应用函数
nums = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, nums))  # [1, 4, 9, 16, 25]

# filter: 过滤元素
even = list(filter(lambda x: x % 2 == 0, nums))  # [2, 4]

# reduce: 累积计算
from functools import reduce
total = reduce(lambda a, b: a + b, nums)  # 15
product = reduce(lambda a, b: a * b, nums)  # 120

# zip: 并行迭代
names = ["Alice", "Bob"]
ages = [25, 30]
for name, age in zip(names, ages):
    print(f"{name}: {age}")
# zip_longest: 不等长时填充
from itertools import zip_longest

# enumerate: 带索引迭代
for i, item in enumerate(["a", "b", "c"], start=1):  # enumerate同时获取索引和值
    print(f"{i}: {item}")

# sorted: 排序 (返回新列表)
students = [("Alice", 85), ("Bob", 92), ("Charlie", 78)]
sorted(students, key=lambda x: x[1], reverse=True)
# [("Bob", 92), ("Alice", 85), ("Charlie", 78)]

# any / all
any([False, True, False])   # True (至少一个为True)
all([True, True, True])     # True (全部为True)

# isinstance / issubclass
isinstance(1, (int, float))    # True
issubclass(bool, int)          # True

# getattr / setattr / hasattr
class Obj:
    x = 10
getattr(Obj, 'x', None)       # 10  # hasattr/getattr/setattr动态操作对象属性
hasattr(Obj, 'y')              # False
setattr(Obj, 'y', 20)

35. lambda 表达式的高级用法

Python
# 基础
square = lambda x: x ** 2  # lambda匿名函数:简洁的单行函数

# 排序key
data = [{"name": "Bob", "age": 30}, {"name": "Alice", "age": 25}]
sorted(data, key=lambda x: x["age"])

# 即时函数
(lambda: print("IIFE"))()

# 条件表达式
classify = lambda x: "正数" if x > 0 else ("零" if x == 0 else "负数")

# 函数工厂
def make_multiplier(n):
    return lambda x: x * n

double = make_multiplier(2)
triple = make_multiplier(3)
print(double(5))  # 10
print(triple(5))  # 15

# 与map/filter组合
result = list(map(lambda x: x.upper(), ["hello", "world"]))
# ["HELLO", "WORLD"]

# 注意:复杂逻辑不应该用lambda,用def更清晰

36. 列表推导 vs 生成器表达式的性能对比

Python
import sys
import time

# 列表推导: 立即创建所有元素
start = time.time()
lst = [x**2 for x in range(1000000)]
print(f"列表推导耗时: {time.time()-start:.4f}s")
print(f"列表占用内存: {sys.getsizeof(lst)} bytes")  # ~8MB

# 生成器表达式: 惰性计算
start = time.time()
gen = (x**2 for x in range(1000000))
print(f"生成器创建耗时: {time.time()-start:.6f}s")  # 几乎为0
print(f"生成器占用内存: {sys.getsizeof(gen)} bytes")  # ~120 bytes

# 如果只需要遍历一次: 用生成器
# 如果需要多次访问/索引: 用列表
# 如果数据量大: 用生成器(节省内存)
# 如果需要 len/index/slice: 用列表

其他推导形式:

Python
# 字典推导
d = {k: v for k, v in zip(keys, values)}  # zip并行遍历多个可迭代对象

# 集合推导
s = {x % 10 for x in range(100)}

# 嵌套推导
matrix = [[1,2,3], [4,5,6], [7,8,9]]
flat = [x for row in matrix for x in row]
# [1, 2, 3, 4, 5, 6, 7, 8, 9]

37. Python 中的类型注解( Type Hints )

Python
from typing import List, Dict, Tuple, Optional, Union, Callable, Generator

# 基础类型注解
def greet(name: str) -> str:
    return f"Hello, {name}"

# 复杂类型
def process(
    data: List[int],
    config: Dict[str, str],
    coord: Tuple[float, float],
    callback: Optional[Callable[[int], bool]] = None,
) -> Union[str, None]:
    pass

# Python 3.10+ 简化写法
def process(
    data: list[int],
    config: dict[str, str],
    callback: Callable[[int], bool] | None = None,
) -> str | None:
    pass

# TypeVar 泛型
from typing import TypeVar
T = TypeVar('T')

def first(items: list[T]) -> T:
    return items[0]

# dataclass
from dataclasses import dataclass

@dataclass  # 自动生成__init__等方法
class User:
    name: str
    age: int
    email: str = ""

    def greet(self) -> str:
        return f"Hi, I'm {self.name}"

38. 常见的 Python 陷阱和注意事项

1. 可变默认参数

Python
# ❌ 危险! 默认参数只创建一次
def append_to(item, lst=[]):
    lst.append(item)
    return lst

print(append_to(1))  # [1]
print(append_to(2))  # [1, 2]  不是 [2]!

# ✅ 使用None
def append_to(item, lst=None):
    if lst is None:
        lst = []
    lst.append(item)
    return lst

2. 循环中的闭包(前面已讨论)

3. 整数除法

Python
# Python 3
7 / 2   # 3.5  (真除法)
7 // 2  # 3    (整除)

4. 字符串乘法和列表乘法

Python
# 字符串乘法
"ha" * 3  # "hahaha"

# 列表乘法的陷阱
matrix = [[0] * 3] * 3           # ❌ 三个子列表是同一对象!
matrix[0][0] = 1
print(matrix)                     # [[1,0,0], [1,0,0], [1,0,0]]

matrix = [[0] * 3 for _ in range(3)]  # ✅ 独立的子列表

5. try-except-else-finally

Python
try:  # try/except捕获异常
    result = do_something()
except ValueError as e:
    handle_error(e)
else:
    # 没有异常时执行
    print(f"成功: {result}")
finally:
    # 无论如何都执行
    cleanup()

39. Python 中的序列化和反序列化

Python
import json
import pickle

# JSON序列化(跨语言通用)
data = {"name": "张三", "age": 25, "scores": [90, 85, 92]}

# 序列化为字符串
json_str = json.dumps(data, ensure_ascii=False, indent=2)  # json.dumps将Python对象转为JSON字符串

# 序列化到文件
with open("data.json", "w", encoding="utf-8") as f:  # with自动管理资源,确保文件正确关闭
    json.dump(data, f, ensure_ascii=False)

# 反序列化
data = json.loads(json_str)  # json.loads将JSON字符串转为Python对象
with open("data.json", "r") as f:
    data = json.load(f)

# 自定义序列化
class User:
    def __init__(self, name, age):
        self.name = name
        self.age = age

def user_encoder(obj):
    if isinstance(obj, User):  # isinstance检查对象类型
        return {"name": obj.name, "age": obj.age, "_type": "User"}
    raise TypeError(f"不支持序列化 {type(obj)}")

json.dumps(User("张三", 25), default=user_encoder)

# Pickle序列化(Python专用,支持任意对象)
data = pickle.dumps(complex_object)
obj = pickle.loads(data)
# 注意: pickle不安全,不要反序列化不可信的数据

40. Python 项目的常见工程建议

项目结构:

Text Only
my_project/
├── src/
│   └── my_package/
│       ├── __init__.py
│       ├── core.py
│       └── utils.py
├── tests/
│   ├── __init__.py
│   ├── test_core.py
│   └── test_utils.py
├── docs/
├── pyproject.toml        # 项目配置(推荐)
├── requirements.txt      # 依赖
├── .gitignore
├── README.md
└── Makefile

代码质量工具:

Bash
# 格式化
black .                   # 代码格式化
isort .                   # import排序

# 类型检查
mypy src/                 # 静态类型检查

# Lint
ruff check .              # 快速Lint (替代flake8)
pylint src/               # 详细Lint

# 测试
pytest tests/ -v --cov=src  # 测试 + 覆盖率

虚拟环境:

Bash
# venv
python -m venv .venv
source .venv/bin/activate

# poetry (推荐)
poetry init
poetry add requests
poetry install

# uv(较新的高性能 Python 工具链之一)
uv init
uv add requests

面试答题技巧

  1. 基础题:简洁准确,给出代码示例
  2. 原理题:讲清底层机制(如 GIL 、 MVCC ),画图辅助
  3. 高级特性:对装饰器、元类等讲清本质(函数也是对象)
  4. 并发题:对比多线程/多进程/协程的区别,结合 GIL 分析
  5. 实战题:结合项目经验,讲解如何选择方案和优化性能

⚠️ 核验说明(2026-04-03):本页已完成 2026-04-03 人工复核。涉及 CPython 3.13 自由线程/JIT 的内容已改为版本敏感口径;工程建议部分不再写成唯一最佳实践。


最后更新日期: 2026-04-03