1、python 语言的基础特性
- python中一切皆对象:
- 在python中,无论函数、类、模块等等都是对象,他们都继承自object
- 所有变量的本质都是对象的引用(指针)
- 动态解释性语言:
- python是解释性语言,运行时需要一行一行解释执行,不会编译成二进制文件执行。
- python类型是动态的:变量无需声明类型,运行时动态决定。
- python的数据类型
- 内置数据类型: int float dict set list str bool tuple
- 可变数据类型: list dict set
- 不可变数据类型:int float tuple
- 内置数据类型: int float dict set list str bool tuple
- 函数式编程的支持:
- python支持高阶函数、lambda、map/filter/reduce、生成器和迭代器
- 主要功能节省内存
- 迭代器
- 定义:实现了__iter__和__next__方法的对象
- 特点:
- 按顺序逐个访问元素
- 只能向前遍历icing
- 节省内存,不会一次性加上所有元素
常见的迭代器: iter(list) 、 iter(dict)、open() 返回的文件对象
- 生成器
- 定义: 一种特殊的迭代器,用yield返回数据
- 特点:
- 惰性计算: 只在需要生成时生成值
- 语法简洁,比写完整的迭代器类跟更方便
- 自动实现__iter__() 和 next() 方法
- 什么时候用迭代器,什么使用用生成器
- 迭代器:
- 需要对自定义对象支持for…in … 遍历
- 比如设计一个树结果,希望for node in tree 能迭代所有节点
- 生成器:
- 数据量大,不相一次性加载数据到内存
- 流式处理(语音帧、日志流、网络数据流)
- 典型的场景:
1
2
3
4
5
6
7# 文件逐行读取
def read_file(path):
with open(path) as f:
for line in f:
yield line
无限序列(斐波那契、自然数流)
- 迭代器:
2、常见算法: 散列表、红黑树、二叉树,能否对应适合的应用场景(通用)
1 |
|
2.1 散列表(Hash Table /dict ,set)
定义
- 基于哈希函数,将key映射到内存地址存储值
- python的dict和set就是典型的实现
特性
- 无序存储(python3.7+ dict保存,但逻辑上还是哈希表)
- 支持快速查询、插入、删除
- 通过哈希碰撞处理(开发寻址或者链表)
时间复杂度
1 | | 操作 | 平均 | 最坏 | |
典型引用场景
- 去重:set存储已访问元素
- 频率统计:词频统计、日志统计
- 缓存/映射表:用户ID–> 用户信息
- 面试高频题目:
1、两数之和
1 |
|
2、统计词频 TopK
1 | # https://leetcode.cn/problems/word-frequency/ |
2.2 二叉树 & 二叉搜索树
定义
- 每个节点最多有两个子节点(左右)
- BST 左边 < 根 < 右
特性
- 树形结构 --> 支持分层、递归处理
- 中序遍历BST --> 得到有序列表
| 操作 | 普通二叉树 | BST(平均) | BST(最坏退化成链) |
|---|---|---|---|
| 查找 | O(n) | O(log n) | O(n) |
| 插入 | O(n) | O(log n) | O(n) |
| 删除 | O(n) | O(log n) | O(n) |
典型的应用场景
- 分层结构表示: 组织结构、文件目录
- 排序存储+ 范围查询
- 遍历恩替(DFS、BFS、回溯)
常见题
- 二叉树最大深度
1 |
|
- 验证BST
1 |
|
2.3 红黑树(自平衡二叉搜索树)
定义
- 自平衡二叉搜索树
特性:
-
根节点黑色
-
红节点不能连续
-
任意路径黑节点数量相同
-
保证 O(log n) 查找/增删
| 操作 | 时间 |
|---|---|
| 查找 | O(log n) |
| 插入 | O(log n) |
| 删除 | O(log n) |
| 典型应用场景 |
需要动态维护有序数据的场景
系统底层实现:
Java TreeMap / TreeSet
C++ map / set
高频题:动态排行榜、区间查询、调度系统
2.4 堆(Heap/优先队列)
定义
完全二叉树
父节点 ≥ 子节点(最大堆)或 ≤ 子节点(最小堆)
特性
查找最大/最小元素 O(1)
插入、删除 O(log n)
典型应用场景
Top K 问题(高频词、排行榜)
优先级任务调度(调度器、操作系统)
图算法(Dijkstra, Prim)
3、Pytorch框架的搭建
4、python闭包、装饰器、异常捕获、多线程用法?
1、python闭包
定义
函数内部定一函数,并且内部函数引用了外部函数的局部变量,就形成了闭包。
闭包能保存函数运行时的环境。
1 |
|
✅ 面试考点:
闭包常用于延迟计算、函数工厂、隐藏实现细节。
注意 Python 中闭包变量是 引用 而非拷贝。
2、装饰器(Decorator)
定义
本质是一个函数,接收一个函数作为参数,返回一个增强后的函数
常用语日志、权限检验、性能统计、缓存等等
1 | def time(func): |
3、异常捕获
Python 用 try-except-finally 来处理异常,保证程序健壮性。
1 | try: |
4、多线程(Threading)
Python 提供 threading 模块,但要注意 GIL 限制:CPU 密集型任务不能真正并行,但 I/O 密集型任务(网络、磁盘)有明显加速。
1 | import Threading |
10、python中with语句的了解?
1、with语句是什么?
with是上下文管理器的语法糖,用来简化资源的获取和释放
核心的两个方法是:
- __enter__(self): 进入上下文时执行
- __exit__(self, exc_type, exc_val, exc_tb)): 退出上下文执行,无论是否发生异常
2、语法
1 |
|
3、自定义上下文管理器
1 |
|
11、python多线程的用法
Python 提供threading模块
1、启动方式
- 方式1: 直接创建Thread
1 | import threading |
- 方式2:继承Thread
1 | class MyThread(thread.Thread): |
2、现成同步(锁)
多线程同时访问共享数据时,容易出现竞态条件,需要用 锁 Lock。
1 |
|
3、线程池(推荐)ThreadPoolExecutor
1 |
|
4. GIL 限制
Python 有 GIL(全局解释器锁),同一时刻只有一个线程能执行 Python 字节码。
因此:
CPU 密集型任务(计算) → 适合用 multiprocessing(多进程)。
I/O 密集型任务(网络请求、文件读写) → 多线程能显著提升性能。
12、如何提高python执行效率的方法用过哪些?
1. 算法与数据结构优化(最重要)
时间复杂度 > 语言性能
例:搜索用 set/dict(O(1))替代 list(O(n))。
例:用堆 (heapq) 实现 TopK,比排序快。
应用场景:语音识别时,查询词典用 dict 而不是 list。
2. 内置函数和库替代手写循环
Python 内置函数(sum, map, any, all)和 列表推导式 通常比手动 for 循环快。
NumPy/Pandas:矩阵、数据处理用 C 实现,比 Python 循环高效几个数量级。
import numpy as np
a = np.arange(1e6)
print(np.sum(a)) # 比 for 循环快很多
3. 并行与并发
多线程 (threading):适合 I/O 密集型(语音流读取、网络请求)。
多进程 (multiprocessing):适合 CPU 密集型(语音特征提取、模型推理)。
异步 (asyncio):高并发网络任务。
应用场景:车载语音系统中,多线程负责多个音频流并发录音;多进程负责特征提取。
4. JIT 编译 & C 扩展
PyPy:带 JIT 编译,比 CPython 快。
Cython:将 Python 代码编译为 C,提高数倍性能。
Numba:用 @jit 装饰器,加速数值计算。
from numba import jit
@jit(nopython=True)
def add(a, b):
return a + b
5## . 内存管理优化
生成器 (yield) 替代一次性加载(节省内存)。
迭代器 代替列表,避免存储全部数据。
应用场景:逐帧读取语音文件,而不是一次性加载整个音频。
6. 减少不必要的开销
避免重复计算(缓存结果,用 functools.lru_cache)。
局部变量比全局变量访问快。
避免频繁的字符串拼接,用 str.join()。
from functools import lru_cache
@lru_cache(maxsize=128)
def fib(n):
if n < 2: return n
return fib(n-1) + fib(n-2)
7. 使用合适的解释器 & 框架
CPython:默认实现。
PyPy:JIT 加速。
C/C++ 扩展:关键部分用 C 实现(如 torch, numpy)。
应用场景:深度学习框架 PyTorch 底层就是 C++/CUDA。
8. 分布式与缓存
多机并行(Ray, Dask, Spark)。
缓存:热点数据放 Redis,减少重复计算。
13、*args和**kwargs的区别是什么?
1. *args
作用:接收 任意数量的位置参数,会打包成一个 元组。
适合参数个数不确定的函数。
def foo(*args):
print(args)
foo(1, 2, 3)
输出: (1, 2, 3)
2. **kwargs
作用:接收 任意数量的关键字参数,会打包成一个 字典。
适合需要灵活传递键值对参数的场景。
def bar(**kwargs):
print(kwargs)
bar(a=1, b=2, c=3)
输出: {‘a’: 1, ‘b’: 2, ‘c’: 3}
3. *args 和 **kwargs 一起用
一般写法:def func(*args, **kwargs)
*args 处理位置参数
**kwargs 处理关键字参数
def func(*args, **kwargs):
print(“args:”, args)
print(“kwargs:”, kwargs)
func(1, 2, x=10, y=20)
args: (1, 2)
kwargs: {‘x’: 10, ‘y’: 20}
- 区别总结
特性 *args **kwargs
参数形式 位置参数 关键字参数
数据类型 元组 (tuple) 字典 (dict)
应用场景 参数数量不定(如加法函数) 配置灵活(如传递参数给API) - 面试延伸问题(华为 OD 常问)
❓ 为什么要用 *args 和 **kwargs?
👉 提高函数的通用性和可扩展性,适用于接口设计、装饰器开发。
❓ 如果调用函数时用 * 或 ** 会怎样?
👉 会进行 参数解包:
def add(x, y): return x + y
nums = (1, 2)
print(add(*nums)) # 3
params = {“x”: 3, “y”: 4}
print(add(**params)) # 7
❓ 在装饰器里为什么常见 *args, **kwargs?
👉 因为装饰器要支持 任意函数签名,保证通用性。
⚡ 记忆口诀:
*args → tuple → 位置参数
**kwargs → dict → 关键字参数
14、Django、Flask、Tornado三大框架各种应用的场景?
1. Django —— 重量级、全家桶
特点:
自带 ORM、模板系统、Admin 后台、用户认证等一整套“全家桶”。
遵循 MTV 模式,强调快速开发、约定大于配置。
有较多内置组件,适合开发复杂的大型 Web 应用。
适用场景:
大型企业应用、内容管理系统(CMS)、电商平台、新闻门户网站。
对数据一致性、权限管理要求高的系统。
典型案例: Instagram、知乎早期。
2. Flask —— 轻量级、自由度高
特点:
只有最核心的功能(路由 + WSGI 支持),其余功能通过扩展实现。
灵活度高,开发者可以自由选择 ORM(SQLAlchemy、Peewee 等)、模板引擎等。
学习曲线较低,适合快速搭建原型。
适用场景:
中小型 Web 应用、原型验证、API 服务、微服务。
对框架约束少,希望灵活度高的项目。
典型案例: Pinterest、国内很多中小型 SaaS。
3. Tornado —— 高性能异步框架
特点:
内置高性能异步非阻塞 I/O,适合处理长连接和高并发请求。
自带 Web Server,不依赖 Gunicorn/uWSGI。
学习成本稍高,生态不如 Django/Flask 丰富。
适用场景:
即时通讯(IM)、WebSocket、长轮询、实时推送系统。
对高并发、低延迟有要求的后台服务。
典型案例: FriendFeed(Facebook 收购的实时社交网站)。
✅ 一句话总结:
Django:全家桶,适合 大型复杂系统。
Flask:轻量自由,适合 中小项目、微服务、原型。
Tornado:异步高并发,适合 实时系统。
__END__