Python
一、基础与数据结构
- Python 中的变量是如何绑定内存对象的?
- 名称绑定机制:变量是名称,绑定到对象,而非值本身
- 动态类型: 变量可以随时绑定不同类型的对象。
- 引用计数: Python内部使用引用计数管理内存
- 对象复用: 小整数、短字符串等常用对象可能会被复用
- 一切皆对象: 函数、类、模块等都是对象,变量都只是引用
- Python 中浅拷贝和深拷贝的区别?
- 浅拷贝: 创建一个新对象,不复制嵌套对象,新对象中嵌套部分仍然只想原始对象中的引用
- 深拷贝: 创建一个新对象,并递归复制所有嵌套对象,新对象与原始对象完全独立。
- 如何判断两个变量是否引用同一个对象?
- 使用is运算符(判断是否是同一个对象)
- == 判断两个对象的值是否相等
- 请实现一个栈和队列的数据结构。
# 栈先进后出
Class Stack:
def __init__(self):
self._data = []
def push(self, item):
self._data.append(item)
def pop(self):
if self.is_empty():
raise IndexError("pop from empty stack")
return self._data.pop()
def peek(self):
if self.is_empty():
raise IndexError("peek from empty stack")
return self._data[-1]
def is_empty(self):
return len(self._data) == 0
def size(self):
return len(self._data)
s = Stack()
s.push(1)
s.push(2)
print(s.pop()) #2
print(s.peek()) #1
# 队列是先进先出
from collections import deque
Class Queue:
def __init__(self):
self._data = deque()
def enqueue(self, item):
self._data.append(item)
def dequeue(self):
if self.is_empty():
raise.IndexError("dequeue from empty queue")
return self._data.popleft()
def front(self):
if self.is_empty():
raise IndexError("peek from empty queue")
return self._data[0]
def is_empty(self):
return self._data == 0
def size(self):
return len(self._data)
q = Queue()
q.enqueue(10)
q.enqueue(20)
print(q.dequeue()) # 10
print(q.front()) # 20 - Python 中字符串是不可变类型,它是如何优化性能的?
- 字符串驻留
- 可哈希
- 安全性
- 内存复用
- join优化拼接
二、函数与作用域
- Python 中的 LEGB 规则是什么?
- 什么是LEGB?
顺序 作用域类型 描述 L Local 当前函数内部的局部作用域 E Enclosing 外部嵌套函数的作用域(闭包) G Global 当前模块的全局作用域 B Built-in Python 内置作用域,如 len()、print()
- 什么是LEGB?
global和nonlocal有什么区别?- global: 全局作用域,可修改目标变量
- nonlocal: 用于外层函数的局部作用域,用于闭包使用
- 解释闭包(closure)及其应用。
- 基础:闭包通常在函数式编程、装饰器、回调函数等使用
- 场景:
- 延迟计算(懒加载)
- 数据封装(私有变量)
- 装饰器内部函数
- 编写一个函数缓存(memoization)装饰器
- 用于缓存函数调用的记过,提高性能,适用于递归或重复计算的函数
- Python 中默认参数的陷阱及其避免方式?
- 默认参数只在函数定义时被计算一次,尤其是可变类型(如list、dict),会导致多次调用函数时共用同一个对象。
三、面向对象编程
- Python 中类变量与实例变量的区别?
- 类变量: 类体内、方法体外,被所有实例共享
- 实例变量: 通常在__init__中定义,每个实例独有,互不干扰。
- 如何实现抽象类和接口?有哪些用途?
- 使用abc模块中的ABC和@abstractmethod装饰器来定义抽象类和接口
- 如何使用
super()调用父类方法?- super用来调用父类(或祖先类)的方法内置函数,用于多继承和子类重写方法时保留父类行为。
- Python 中
__slots__的作用是什么?__slots__是一个用于限制实例属性的特殊机制- 作用:
- 节省内存
- 限制属性动态添加
- 请实现一个简单的事件派发系统(支持订阅和发布)
class EventDispatcher:
def __init__(self):
self._listeners = {}
def subscribe(self, event_name, callback):
"""订阅某个事件"""
if event_name not in self._listeners:
self._listeners[event_name] = []
self._listeners[event_name].append(callback)
def unsubscribe(self, event_name, callback):
"""取消订阅某个事件"""
if event_name in self._listeners:
self._listeners[event_name] = [cb for cb in self._listeners[event_name] if cb != callback]
def dispatch(self, event_name, *args, **kwargs):
"""发布事件并传递数据给订阅者"""
if event_name in self._listeners:
for callback in self._listeners[event_name]:
callback(*args, **kwargs)
def on_user_registered(username):
print(f"User registered: {username}")
def on_send_welcome_email(username):
print(f"Sending welcome email to {username}")
# 创建事件派发器
dispatcher = EventDispatcher()
# 订阅事件
dispatcher.subscribe("user_registered", on_user_registered)
dispatcher.subscribe("user_registered", on_send_welcome_email)
# 派发事件
dispatcher.dispatch("user_registered", "Alice")
# 输出:
# User registered: Alice
# Sending welcome email to Alice
# 取消订阅
dispatcher.unsubscribe("user_registered", on_user_registered)
dispatcher.dispatch("user_registered", "Bob")
# 输出:
# Sending welcome email to Bob
四、模块与包管理
__init__.py的作用是什么?- 将目标表示为包: 当一个目录包含__init__.py文件时,才会将该目录识别为一个"包",从而允许你用模块导入语法访问其中的模块
- 用途:
- 生命包
- 初始化逻辑
- 统一接口
- 保持兼容性
- Python 模块导入时的搜索路径如何确定?
- 使用
sys.path的构成
- 使用
- 什么是相对导入和绝对导入?使用场景?
- 绝对导入
- 定义:使用模块的完整路径来导入模块,从项目的根包开始写起
- 格式: 直接从顶层包开始写路径
- 相对导入
- 定义: 通过当前模块所在的包的位置,使用点(.)表示相对路径进行导入。
- 格式:
- .表示当前目录(当前包)
- ..表示上一级包
- ...表示上上级包,以此类推
- 绝对导入
- 如何使用
importlib动态导入模块?# 字符串导入模块
import importlib
module_name = "math" # 也可以是自己项目里的模块名
module = imortlib.import_module(module_name)
print(module.sqrt(16)) # 4.0
# 动态导入子模块
mod = importlib.import_module("mypackage.submodule")
五、异常与上下文管理
- Python 中异常处理流程是怎样的?
执行try块代码
|
出现异常? -----> 是 ----> 是否有匹配的except? ----> 是 ----> 执行except块
| |
否 否
| |
执行else块 异常向上层传播
| |
执行finally块 <---------------------- 直到捕获或程序终止 - 使用 contextlib 实现一个上下文管理器。
import contextlib
@contextlib.contextmanager
def my_context():
print("开始")
try:
yield
finally:
print("结束")
with my_context():
print("上下文中的代码执行")
# 结果
开始
上下文中的代码执行
结束
六、函数式编程
- 什么是高阶函数?哪些是典型例子?
- 高阶函数(以函数为参数或返回函数的函数):
- 接受一个或多个函数作为参数
- 返回一个函数作为结果
- 高阶函数(以函数为参数或返回函数的函数):
map、reduce、filter的用途和区别?- map: 对iterable中的每个元素应用函数func,返回一个新的迭代器
- filter: 保留iterable中所有满足func(x)为True的元素
- reduce: 将iterable中的元素两两规约为一个值,需要从functools模块导入
- 什么是偏函数?如何用
functools.partial实现?- 偏函数是指固定(预先设置)一个函数的部分参数,返回一个新的函数,这个新函数可以像原函数一样继续传入剩余的参数
七、并发与异步编程
- GIL 的存在意味着什么?
- 全局解释器锁,是CPython中的一个机制,它对Python多线程的并行执行带来了重要的影响
- 定义和作用: GIL是一个互斥锁,确保同一时刻只有一个线程在执行Python字节码
- 多线程适合什么场景?多进程又适合什么场景?
- 多线程: IO密集型任务,轻量并发
- 多进程: CPU密集型任务,充分利用多核
- 使用
threading.Lock()实现线程安全计数器import threading
class SafeCounter:
def __init__(self):
self.count = 0
self.locak = threading.Lock()
def increment(self):
with self.lock:
self.count += 1
def get_count(self):
with self.lock:
return self.count
def worker(counter, num_items):
for _ in range(num_items):
counter.increment()
if __name__ == '__main__':
counter = SafeCounter()
threads = []
for _ in range(10): # 启动10个线程
t = threading.Thread(target=worker, args=(counter, 10000))
threads.append(t)
t.start()
for t in threads:
t.join()
print("Final count is:", counter.get_count()) # 预期值应为 10 * 10000 = 100000 - Python 中的 Queue、Event、Semaphore 是做什么用的?
- Queue ———— 线程/进程安全的队列(用于通信):
- 线程安全(queue.Queue)或进程安全(multiprocessing.Queue)的数据结构,常用于线程/进程之间的数据传递
- 生产者-消费者模式
- 线程/进程间通信
from queue import Queue
from threading import Thread
q = Queue()
def producer():
for i in range(5):
q.put(i)
print(f"Produced {i}")
def consumer():
while True:
item = q.get()
if item is None:
break
print(f"Consumed {item}")
q.task_done()
t1 = Thread(target=producer)
t2 = Thread(target=consumer)
t1.start()
t2.start()
t1.join()
q.put(None) # 结束信号
t2.join() - 线程安全(queue.Queue)或进程安全(multiprocessing.Queue)的数据结构,常用于线程/进程之间的数据传递
- Event ———— 通知机制(用于线程同步)
- .set(): 设置标志位True
- .clear(): 清除标志位为False
- .wait(timeout): 阻塞直到标志为True
from threading import Thread, Event
import time
event = Event()
def wait_for_event():
print("Waiting for event...")
event.wait()
print("Event triggered!")
Thread(target=wait_for_event).start()
time.sleep(2)
print("Sending event signal...")
event.set() - Semaphore — 控制并发数量(信号量)
from threading import Thread, Semaphore
import time
sem = Semaphore(2)
def limited_access(name):
print(f"{name} waiting to enter...")
with sem:
print(f"{name} entered")
time.sleep(2)
print(f"{name} exiting")
for i in range(5):
Thread(target=limited_access, args=(f"Thread-{i}",)).start()
- Queue ———— 线程/进程安全的队列(用于通信):
八、标准库与工具库模块
collections中常用的结构有哪些?如何用?- namedtupe: 有字段名的元组(类字典 + 轻量对象)
from collections import namedtuple
Point = namedtuple('Point', ['x', 'y'])
p = Point(1, 2)
print(p.x, p.y) # 1 2
print(p._asdict()) # {'x': 1, 'y': 2} - deque ————双端队列(适合频繁插入/删除)
from collections import deque
d = deque([1, 2, 3])
d.appendleft(0)
d.append(4)
print(d) # deque([0, 1, 2, 3, 4])
d.pop() # 4
d.popleft() # 0 - Counter ————多用途计数器
from collections import Counter
c = Counter('abracdafdasfdas')
print(c) # Counter({'a': 5, 'd': 3, 'f': 2, 's': 2, 'b': 1, 'r': 1, 'c': 1})
print(c.most_common(2)) # [('a', 5), ('d', 3)] - OrderedDict ————记住顺序插入的字典
from collections import OrderedDict
od = OrderedDict()
od['apple'] = 1
od['banana'] = 2
print(list(od.keys)) - defaultdict ———— 不存在的键返回默认值
from collections import defaultdict
d = defaultdict(int)
d['a'] += 1
print(d['a']) # 1
print(d['b'])# 0(自动返回 int(),即 0) - ChainMap ———— 多个字典合并视图(适合配置合并)
from collections import ChainMap
dict1 = {'a':1}
dict2 = {'b':2, 'a':3}
cm = ChainMap(dict1, dict2)
print(cm['a']) # 1
print(cm['b']) # 2
- namedtupe: 有字段名的元组(类字典 + 轻量对象)
- 如何使用
itertools实现组合/排列生成?- permutations:所有元素的全排列或指定长度排列,有序
- combinations: 生成组合,如何无序,不能重复,r参数必须指定
itertools.combinations(iterable, r) - combinations_with_replacement: 允许元素重复选择(和顺序无关),
itertools.combinations_with_replacement(iterable, r) - product: 多项式排列,类似于嵌套循环,支持可重复排列
- 使用
datetime实现一个倒计时器。import time
from datetime import timedelta
def countdown(seconds):
while seconds:
td = str(timedelta(seconds=seconds))
print(f"\rCountdown: {td}", end="")
time.sleep(1)
seconds -= 1
print("\rCountdown: 00:00:00 ✅ Time's up!")
# 倒计时10秒
countdown(10) subprocess模块如何执行系统命令并获取结果?import subprocess
result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
print("Return code:", result.returncode)
print("STDOUT:\n", result.stdout)
print("STDERR:\n", result.stderr)
# capture_output=True 表示捕获标准输出和错误
# text=True 表示以字符串形式返回(否则是bytes)pathlib相比os.path有什么优势?- pathlib: 提供了PATH类,用对象方法替代了杂乱的函数式调用,不用处理分隔符"","/"
- os.path: 需要处理不同系统的分隔符,
九、性能优化与调试
- 如何使用
timeit测量函数性能?场景 方法 测量代码字符串执行时间 timeit.timeit('code', number=N)测量函数执行时间(推荐) timeit.timeit(func, number=N)命令行快速测试 python -m timeit 'expression'精细控制时间/自动选择次数 timeit.Timer(...).autorange()
十、设计模式
- 单例模式
# 使用类变量保存实例
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
# 使用装饰器实现单例
def singleton(cls):
instances = {}
def wrapper(*args, **kwargs):
if cls not in instances:
instances[cls] = cls(*args, **kwargs)
return instances[cls]
return wrapper
@singleton
class MyClass:
pass
a = MyClass()
b = MyClass()
print(a is b)
# 元类方式实现单例
class SingletonMeta(type):
_instances = {}
def __call__(self, *args, **kwargs):
if self not in self._instances:
self._instances[self] = super().__call__(*args, **kwargs)
return self._instances[self]
class MyClass1(metaclass=SingletonMeta):
pass
a = MyClass1()
b = MyClass1()
print(a is b) # True - 实现观察者模式、策略模式、工厂模式。
# 观察者模式
# 订阅者
from abc import ABC, abstractmethod
class Subject():
def __init__(self):
self._observers = []
def subscribe(self, observer):
self._observers.append(observer)
def unsubscribe(self, observer):
self._observers.remove(observer)
def notify(self, message):
for observer in self._observers:
observer.update(message)
# 观察者
class Observer(ABC):
@abstractmethod
def update(self, message):
pass
# 具体实现
class ConcreateObserver(Observer):
def __init__(self, name):
self.name = name
def update(self, message):
print(f'{self.name} received message: {message}')
# 调用
subject = Subject()
a = ConcreateObserver("ObserverA")
b = ConcreateObserver("ObserverB")
subject.subscribe(a)
subject.subscribe(b)
subject.notify("Event occurred")# 策略模式
from abc import ABC, abstractmethod
# 接口
class Strategy(ABC):
@abstractmethod
def execute(self, a, b):
pass
# 具体策略
class AddStrategy(Strategy):
def execute(self, a, b):
return a + b
class SubStrategy(Strategy):
def execute(self, a, b):
return a - b
# 使用上下文选择策略模式
class Calculator:
def __init__(self, strategy: Strategy):
self.strategy = strategy
def set_strategy(self, strategy: Strategy):
self.strategy = strategy
def calculate(self, a, b):
return self.strategy.execute(a, b)
# 调用
clac = Calculator(AddStrategy())
print(clac.calculate(3, 4))
clac.set_strategy(SubStrategy())
print(clac.calculate(3, 4))# 工厂模式
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def draw(self):
pass
class Circle(Shape):
def draw(self):
print("Drawing a circle")
class Square(Shape):
def draw(self):
print("Drawing a square")
class ShapeFactory:
@staticmethod
def create_shape(shape_type: str) -> Shape:
if shape_type == 'circle':
return Circle()
elif shape_type == 'square':
return Square()
else:
raise ValueError(f"Unknown shape type {shape_type}")
shape = ShapeFactory.create_shape("circle")
shape.draw() # 输出: Drawing a circle - 使用装饰器模式为函数添加行为。
# 装饰器
# 类实现装饰器
class MyDecorator:
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
print("装饰器前操作")
result = self.func(*args, **kwargs)
print("装饰器后操作")
return result
@MyDecorator
def say_hello(name):
print(f"Hello, {name}!")
say_hello("Alice")
class Repeat:
def __init__(self, times):
self.times = times # 装饰器的参数
def __call__(self, func):
def wrapper(*args, **kwargs):
for _ in range(self.times):
func(*args, **kwargs)
return wrapper
@Repeat(3)
def greet():
print("Hello!")
greet() - 使用责任链模式组织业务逻辑流程。
from typing import Optional
class Handler:
def __init__(self):
self._next: Optional['Handler'] = None
def set_next(self, handler: 'Handler') -> 'Handler':
self._next = handler
return handler
def handler(self, request: dict):
if self._next:
return self._next.handler(request)
return True
class AuthHandler(Handler):
def handler(self, request: dict):
if not request.get("user"):
print("认证失败:未提供用户信息")
return False
print("认证通过")
return super().handler(request)
class ValidateHandler(Handler):
def handler(self, request: dict):
if "data" not in request:
print("校验失败:缺少参数")
return False
print("校验通过")
return super().handler(request)
class PermissionHandler(Handler):
def handler(self, request: dict):
if request.get("user") != "admin":
print("权限不足")
return False
print("校验通过")
return super().handler(request)
auth = AuthHandler()
validate = ValidateHandler()
permission = PermissionHandler()
auth.set_next(validate).set_next(permission)
# 发起请求
request = {"user": "admin", "data": {"id": 1}}
result = auth.handler(request)
print("请求处理结果:", result)
十一、高级主题
- Python 的元类(metaclass)是什么?能干什么?
-
元类是什么:
- 示例是由类创建的
- 类是由元类创建的
-
作用:
- 控制类的创建行为(比如修改类属性、注入方法等)
- 实现自动注册机制(如插件系统、ORM模型注册等)
- 校验类是符合某种规则(如是否实现某种方法、变量)
- 代码增强(自动添加装饰器、日志等)
名称 描述 实例 由类创建的对象 类 由元类创建,定义实例的行为 元类 控制类的创建过程(默认是 type)作用 动态控制类结构、注册、增强逻辑等
-
- 描述 CPython 的内存管理机制。
- 总体机制概览CPython使用私有的内存管理机制,其核心包括:
模块/机制 作用说明 引用计数 主机制,自动管理对象的生命周期。 垃圾回收(GC) 用于处理引用计数无法检测的“循环引用”。 内存池(PyMalloc) 避免频繁向操作系统申请/释放内存,提高性能。 ┌─────────────┐ │ Python对象 │ └─────────────┘ │ ┌────────────┼─────────────┐ ▼ ▼ 引用计数(主) 垃圾回收 GC(辅) │ ┌──────────┴──────────┐ ▼ ▼ 循环引用检查 分代回收策略(0/1/2)
- 总体机制概览CPython使用私有的内存管理机制,其核心包括:
- Python 中的协程与 greenlet 的区别?
- 基本定义
对比点 协程(Coroutine) greenlet 核心模块 asyncio(Python3.5+内建)greenlet(第三方库)本质 使用 await、async def的异步函数更底层的“微线程”切换 调度方式 事件循环调度(自动) 手动切换(程序员控制) 是否标准库 ✅ 是( asyncio)❌ 不是(需安装: pip install greenlet)
- 基本定义
- 什么是 monkey patch?有何风险?
- 什么是猴子补丁
- 在运行时修改或替换类、模块、函数的行为。
- 不需要访问或修改原始定义文件。
- 什么是猴子补丁
实战类:
- 实现一个 LRU 缓存装饰器。
from collections import OrderedDict
from functools import wraps
def lru_cache(maxsize=128):
def decorator(func):
cache = OrderedDict()
@wraps(func)
def wrapper(*args):
if args in cache:
cache.move_to_end(args) # 标记为最近使用
return cache[args]
result = func(*args)
cache[args] = result
if len(cache) > maxsize:
cache.popitem(last=False) # 移除最久未使用
return result
return wrapper
return decorator
# 调用:
@lru_cache(maxsize=3)
def slow_square(n):
print(f"Computing square({n})")
return n * n
print(slow_square(2))
print(slow_square(3))
print(slow_square(2)) # 命中缓存
print(slow_square(4))
print(slow_square(5)) # 会触发淘汰旧的缓存 - 实现一个简单的任务调度器。
import time
import threading
class TaskScheduler:
def __init__(self):
self.tasks = []
self.running = False
def add_task(self, func, delay, repeat=False):
'''
注册任务
:param func:要执行的函数
:param delay:延迟(秒)
:param repeat:是否重复执行(周期性任务)
:return:
'''
task = {
'func': func,
'delay': delay,
'repeat': repeat,
}
self.tasks.append(task)
def _run_task(self, task):
task['func']()
if task['repeat'] and self.running:
task['timer'] = threading.Timer(task['delay'], self._run_task, [task])
task['timer'].start()
def start(self):
self.running = True
for task in self.tasks:
task['timer'] = threading.Timer(task['delay'], self._run_task, [task])
task['timer'].start()
def stop(self):
self.running = False
for task in self.tasks:
if task['timer']:
task['timer'].cancel()
def say_hello():
print(f"Hello! Time: {time.strftime('%X')}")
def print_heartbeat():
print(f"Heartbeat at {time.strftime('%X')}")
scheduler = TaskScheduler()
scheduler.add_task(say_hello, delay=2, repeat=False) # 执行一次
scheduler.add_task(print_heartbeat, delay=1, repeat=True) # 每秒执行一次
print("任务调度器启动")
scheduler.start()
# 运行 5 秒后停止调度器
time.sleep(5)
scheduler.stop()
print("调度器已停止") - 编写一个支持插件加载的命令行工具。
- 基础命令行功能(支持argparse)
- 插件为Python脚本,可动态加载
- 插件定义自己的命令和处理逻辑
- 实现一个带访问统计的 Web API 装饰器。
from flask import Flask, jsonify, request
from functools import wraps
app = Flask(__name__)
# 全局访问计数器
visit_counts = {}
def count_visit(func):
@wraps(func)
def wrapper(*args, **kwargs):
route = request.endpoint
visit_counts[route] = visit_counts.get(route, 0) + 1
return func(*args, **kwargs)
return wrapper
@app.route('/hello')
@count_visit
def hello():
return "hello, visitor!"
@app.route('/visits')
def visits():
return jsonify(visit_counts)
if __name__ == '__main__':
app.run(debug=True) - 实现一个简易 ORM(对象关系映射)模型。
1. 数据结构与算法
- 解释Python中的列表、元组、集合和字典的区别及适用场景。
- 列表:有序、增删改频繁、索引查找、可变元素、支持重复元素(队列、堆栈等)
- 元组:不可变、有序、包含任意类型、保持插入顺序、支持重复元素(存储不便元素,常量集合等)
- 集合: 无序、可变、元素必须是哈希、不支持索引访问,只能迭代(适合判断成员是否存在、集合运算(交集、并集、差集))
- 字典: 可变、键是哈希类型,保持插入顺序,键可以重复值不行,快速查找(JSON数据结构等,引用与各种数据映射)
- 实现一个函数,找出一个字符串中第一个不重复的字符,时间复杂度要求O(n)。
def first_non_repeating_char(s:str):
char_count = {}
# 第一次遍历,统计字符频率
for ch in s:
char_count[ch] = char_count.get(ch, 0) + 1
# 第二次遍历
for ch in s:
if char_count[ch] ==1:
return ch
return None; # 没有不重复字符时返回None
2. Python语言特性
- 什么是Python的生成器(generator),和迭代器(iterator)有什么区别?
- 迭代器
- 迭代器是一个实现了迭代协议的对象
- 迭代协议要求对象必须实现两个方法
- __iter__(): 返回迭代器本身
- __next__(): 返回序列的下一个元素,如果没有元素则抛出StopIteration异常
- 生成器
- 带有yield关键字的函数,每次遇到yield暂停,返回一个值,下次从暂停处继续执行.
- 生成器函数调用后返回一个生成器对象(生成器是迭代器的一种)
- 迭代器