跳转至

Python面试题

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 3.13起实验性支持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)
    

  2. C扩展:Numpy、Pandas等C实现的库在计算时会释放GIL

  3. 异步IO(asyncio):IO密集型任务的最佳选择

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

  5. 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. 使用性能分析工具

Python
# cProfile
python -m cProfile script.py

# 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项目的最佳实践

项目结构:

Python
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 (最新,超快)
uv init
uv add requests


面试答题技巧

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

最后更新:2025年