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 能迭代所有节点
- 生成器:
- 数据量大,不相一次性加载数据到内存
- 流式处理(语音帧、日志流、网络数据流)
- 典型的场景:
# 文件逐行读取 def read_file(path): with open(path) as f: for line in f: yield line 无限序列(斐波那契、自然数流)
- 迭代器:
2、python的执行过程
python是一种解释性语言,这意味着python代码在执行时先转换成子字节码,然后由python虚拟机PVM执行
- 源代码::编写的Python文件
- 编译::Python解释器首先将源代码编译成字节码。这一过程涉及到语法分析和语义分析,确保代码符合Python的语法规则。字节码是一种低级、与平台无关的代码,保存在.pyc中
- 字节码::编译得到的字节码是一种中间表示形式,存储在内存中。字节码的执行比直接解释源代码要快。
- python虚拟机::Python虚拟机(PVM)是Python运行时环境的一部分,负责读取字节码,将其转换成机器码,然后执行。PVM是解释器的核心,它执行存储在pyc中
- 执行::PVM逐条执行字节码指令,进行函数调用、内存管理等
3、常见算法: 散列表、红黑树、二叉树,能否对应适合的应用场景(通用)
┌───────────────┐
│ 数据结构 │
└──────┬────────┘
│
┌──────────────┴───────────────┐
│ │
┌─────────────┐ ┌─────────────┐
│ 散列表 │ │ 树类 │
│ (Hash Table) │ └─────┬───────┘
└─────┬───────┘ │
│ │
┌───────┴─────────┐ ┌────────┴─────────┐
│ │ │ │
Key-Value / Set 特点:查找快 二叉树 堆
典型应用: O(1) 平均 │ │
- 去重 优点:快速 ├─────┬─────────┤
- 缓存 缺点:无序 BST 红黑树 完全二叉树
- 频率统计 │ │ │
- 映射表 │ │ │
范围查找 平衡树 O(log n) TopK/优先队列
排序维护 系统调度 /排行榜
| 数据结构 | 特性 | 时间复杂度(查/增/删) | 典型应用场景 |
| ---------------------------------- | --------------------- | --------------------------------- | ------------------------------------------------------------------------- |
| **散列表(Hash Table / dict, set)** | 无序,基于哈希,O(1) 平均查找 | 查 O(1),增 O(1),删 O(1) | - 唯一性检查(去重)<br>- 频率统计(词频、日志统计)<br>- 缓存(LRU/Redis)<br>- 快速查找(用户 ID → 信息映射) |
| **二叉树(Binary Tree)** | 每个节点最多两个子节点 | 查 O(n),增 O(n),删 O(n)(普通二叉树) | - 表示分层结构(组织结构、文件目录)<br>- 基础遍历算法练习(前序、中序、后序)<br>- 递归问题(DFS、回溯) |
| **二叉搜索树(BST, Binary Search Tree)** | 左 < 根 < 右 | 平均查 O(log n),最坏 O(n) | - 排序存储数据<br>- 快速查找 / 范围查询(如查找 > x 且 < y 的值) |
| **平衡二叉树(AVL / 红黑树)** | 保持高度平衡 → O(log n) 查增删 | 查 O(log n),增 O(log n),删 O(log n) | - 高速查找 + 动态更新<br>- Java TreeMap、C++ map/set 底层<br>- 操作系统任务调度(红黑树管理定时器) |
| **堆(Heap / 优先队列)** | 完全二叉树,父节点 ≥ / ≤ 子节点 | 查最大/最小 O(1),增 O(log n),删 O(log n) | - Top K 问题(高频元素、排行榜)<br>- 实时任务调度(优先队列)<br>- Dijkstra / A\* 算法中的最短路径 |
3.1 散列表(Hash Table /dict ,set)
定义
- 基于哈希函数,将key映射到内存地址存储值
- python的dict和set就是典型的实现
特性
- 无序存储(python3.7+ dict保存,但逻辑上还是哈希表)
- 支持快速查询、插入、删除
- 通过哈希碰撞处理(开发寻址或者链表)
时间复杂度
| 操作 | 平均 | 最坏 |
| -- | ---- | ---- |
| 查找 | O(1) | O(n) |
| 插入 | O(1) | O(n) |
| 删除 | O(1) | O(n) |
典型引用场景
- 去重:set存储已访问元素
- 频率统计:词频统计、日志统计
- 缓存/映射表:用户ID–> 用户信息
- 面试高频题目:
1、两数之和
# https://leetcode.cn/problems/two-sum/
class Solution:
def twoSum(self, nums: List[int], target: int) -> List[int]:
d = {}
# [2,7,11,15] 9
for i, num in enumerate(nums):
if target - num in d:
return [d[target-num], i] # [1,0]
d[num] = i # d[2]
# 标记数字跟索引之间的关系
d = {2: 0,7:1, 11:2,15:3 }
2、统计词频 TopK
# https://leetcode.cn/problems/word-frequency/
words = """
the day is sunny the the
the sunny is is
"""
res = {}
def count(words: str):
lines = words.strip().split("\n")
for line in lines:
ls = str(line).strip().split(" ")
for j in ls:
if j in res.keys():
res[j] = res[j] + 1
else:
res[j] = 1
return res
print(count(words))
from collections import Counter
# 或者counter = Counter([data])
3.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、回溯)
常见题
- 二叉树最大深度
# https://leetcode.cn/problems/er-cha-shu-de-shen-du-lcof/description/
def maxDepth(root):
if not root:
return 0
return 1 + max(maxDepth(root.left),maxDepth(root.right))
# 递归DFS
- 验证BST
# Definition for a binary tree node.
# class TreeNode(object):
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution(object):
def isValidBST(self, root,low=float('-inf'), high=float('inf')):
"""
:type root: Optional[TreeNode]
:rtype: bool
"""
if not root:
return True
if not rlow < root.val < high:
return False
return self.isValidBST(root.left, low, root.val) and self.isValidBST(root.right, root.val, high)
# 核心点:递归 + 边界判断
3.3 红黑树(自平衡二叉搜索树)
定义
- 自平衡二叉搜索树
特性:
-
根节点黑色
-
红节点不能连续
-
任意路径黑节点数量相同
-
保证 O(log n) 查找/增删
| 操作 | 时间 |
|---|---|
| 查找 | O(log n) |
| 插入 | O(log n) |
| 删除 | O(log n) |
| 典型应用场景 |
需要动态维护有序数据的场景
系统底层实现:
Java TreeMap / TreeSet
C++ map / set
高频题:动态排行榜、区间查询、调度系统
3.4 堆(Heap/优先队列)
定义
完全二叉树
父节点 ≥ 子节点(最大堆)或 ≤ 子节点(最小堆)
特性
查找最大/最小元素 O(1)
插入、删除 O(log n)
典型应用场景
Top K 问题(高频词、排行榜)
优先级任务调度(调度器、操作系统)
图算法(Dijkstra, Prim)
4、Pytorch框架的搭建
5、python闭包、装饰器、异常捕获、多线程用法?
5.1、python闭包
定义
函数内部定一函数,并且内部函数引用了外部函数的局部变量,就形成了闭包。
闭包能保存函数运行时的环境。
def make_multiplier(factor):
def multiply(x):
return x* factor #引用外部变量
return multiply
times2 = make_multiplier(2)
print(times2(5)) # 10
✅ 面试考点:
闭包常用于延迟计算、函数工厂、隐藏实现细节。
注意 Python 中闭包变量是 引用 而非拷贝。
5.2、装饰器(Decorator)
定义
本质是一个函数,接收一个函数作为参数,返回一个增强后的函数
常用语日志、权限检验、性能统计、缓存等等
装饰器本质上是一个函数,它接受一个函数作为参数并返回一个新的函数。
def time(func):
def wapper(*args,**kwargs):
start = time.time()
result = func(*args,**kwargs)
print(f"{func.__name__} 耗时: {time.time() - start:.4f}s")
return result
return wrapper
def slow_function():
time.sleep(1)
slow_function()
5.3、异常捕获
Python 用 try-except-finally 来处理异常,保证程序健壮性。
try:
x = 1 / 0
except ZeroDivisionError as e:
print("除零错误:", e)
except Exception as e:
print("其他错误:", e)
else:
print("没有异常时执行")
finally:
print("无论如何都会执行")
5.4、多线程(Threading)
Python 提供 threading 模块,但要注意 GIL
限制:CPU 密集型任务不能真正并行,但 I/O 密集型任务(网络、磁盘)有明显加速。
import Threading
import time
def worker(name):
print(f"{name} 开始工作")
time.sleep(1)
print(f"{name} 完成")
threads = []
for i range(3):
t = threading.Thread(target=worker, args=(f"线程{i}",))
t.start()
threads.append(t)
for t in threads:
t.join()
I/O 密集型 → threading / concurrent.futures.ThreadPoolExecutor。
CPU 密集型 → multiprocessing(绕开 GIL)。
threading.Lock() / RLock() 用于线程同步。
6、python中with语句的了解?
6.1、with语句是什么?
with是上下文管理器的语法糖,用来简化资源的获取和释放
核心的两个方法是:
- __enter__(self): 进入上下文时执行
- __exit__(self, exc_type, exc_val, exc_tb)): 退出上下文执行,无论是否发生异常
6.2、语法
# 文件操作
with open("test.txt","w") as f:
f.write("Hello world!!")
# 自动关闭文件
# 等价于
f = open("test.txt",w)
try:
f.write("Hello world!!")
finally:
f.close()
6.3、自定义上下文管理器
class MyResource:
def __enter__(self):
print("资源初始化")
return self
def __exit__(self, exc_type, exc_val, exc_tb):
print("资源释放")
return False # 返回 True 可以屏蔽异常
with MyResource() as r:
print("使用资源")
7、python多线程的用法
Python 提供threading模块
7.1、启动方式
- 方式1: 直接创建Thread
import threading
import time
def worker(name):
print(f"{name} 开始工作")
time.sleep(1)
print(f"{name} 完成")
# 创建并启动线程
t1 = threading.Thread(target=worker,args =("线程1"))
t2 = threading.Thread(target=worker,args = ("线程2"))
t1.start()
t2.start()
# 等等所有线程结束
t1.join()
t2.join()
- 方式2:继承Thread
class MyThread(thread.Thread):
def __init__(self,name):
super().__int__()
self.name = name
def run(self):
print(f"{self.name} 开始工作")
t = Thread("线程A")
t.start()
t.join()
7.2、现成同步(锁)
多线程同时访问共享数据时,容易出现竞态条件,需要用 锁 Lock。
lock = threading.Lock()
counter = 0
def safe_worker():
global counter
with lock: # 自动上锁解锁
for _ in range(100000):
counter += 1
threads = [threading.Thread(target=safe_worker) for _ in range(5)]
[t.start() for t in threads]
[t.join() for t in threads]
print("最终计数:", counter)
# 👉 没有锁时,结果可能小于 5 * 100000。
7.3、线程池(推荐)ThreadPoolExecutor
from concurrent.futures import ThreadPoolExecutor
import time
def task(n):
time.sleep(1)
return n * n
with ThreadPoolExecutor(max_workers=3) as executor:
results = executor.map(task, [1, 2, 3, 4, 5])
print(list(results))
8、python的深拷贝、浅拷贝
8.1 浅拷贝
浅拷贝会创建一个新的对象,但是它包含是对原对象地址的引用,而不是其副本。因此如果原始对象的项是可变的,修改
这些项会影响到拷贝后的对象。
- 创建浅拷贝的方法:
- 使用列表的list.copy()方法
- 切片操作,例如 new_list = old_list[:]
- 使用copy模块的copy函数: from copy import copy; new_list=copy(old_list);
import copy
original = [1, 2, [3, 4]]
shallow = copy.copy(original)
# 修改原始列表中的嵌套列表也会影响浅拷贝
original[2][0] = "changed"
print(shallow) # 输出:[1, 2, ['changed', 4]]
8.2 深拷贝
深拷贝创建一个新的对象,并且递归拷贝原始对象中的所有项。这意味着它将创建所有项的副本,包括嵌套对象。
修改原始对象不会影响到新创建的副本。
- 创建深拷贝
from copy import deepcopy
deep = deepcopy(original)
9. GIL 限制
Python 有 GIL(全局解释器锁),同一时刻只有一个线程能执行 Python 字节码。
因此:
CPU 密集型任务(计算) → 适合用 multiprocessing(多进程)。
I/O 密集型任务(网络请求、文件读写) → 多线程能显著提升性能。
10、Python lambda匿名函数
在python中,lambda函数是一种轻量级的匿名函数,它通常用以编写简单的,一行的函数,无须定义正式的函数名
- 基本语法:
lambda arguments: expression
- arguments: 参数,可以是多个,用逗号隔开
- expression: 一个表达式,描述函数的行为,返回值是个表达式的结果
- 特点:
- 匿名: lambda函数通常是匿名的,没有函数名
- 一行表达式: 只能有一个表达式,不能包含其他的语句或者多个表达式
- 可随时使用: 可以在任何地方使用
- 灵活性: 常用简化代码,特别是在函数编程或者需要传递小函数作为参数的场合。
# 使用map将每个元素加倍
list(map(lambda x: x*2, [1,2,3,4])) # [2,4,6,8]
# 使用filter()过滤大于2的元素
list(filter(lambda x: x>2, [1,2,3,4])) # [3,4]
# 使用sorted()根据列表的元祖的第二个元素进行排序
sorted([(1, 'one'), (2, 'two'), (3, 'three')], key=lambda x: x[1])
11、如何提高python执行效率的方法用过哪些?
11.1. 算法与数据结构优化(最重要)
时间复杂度 > 语言性能
例:搜索用 set/dict(O(1))替代 list(O(n))。
例:用堆 (heapq) 实现 TopK,比排序快。
应用场景:语音识别时,查询词典用 dict 而不是 list。
11.2. 内置函数和库替代手写循环
Python 内置函数(sum, map, any, all)和 列表推导式 通常比手动 for 循环快。
NumPy/Pandas:矩阵、数据处理用 C 实现,比 Python 循环高效几个数量级。
import numpy as np
a = np.arange(1e6)
print(np.sum(a)) # 比 for 循环快很多
11.3. 并行与并发
多线程 (threading):适合 I/O 密集型(语音流读取、网络请求)。
多进程 (multiprocessing):适合 CPU 密集型(语音特征提取、模型推理)。
异步 (asyncio):高并发网络任务。
应用场景:车载语音系统中,多线程负责多个音频流并发录音;多进程负责特征提取。
12. JIT 编译 & C 扩展
PyPy:带 JIT 编译,比 CPython 快。
Cython:将 Python 代码编译为 C,提高数倍性能。
Numba:用 @jit 装饰器,加速数值计算。
from numba import jit
@jit(nopython=True)
def add(a, b):
return a + b
13. 内存管理优化
生成器 (yield) 替代一次性加载(节省内存)。
迭代器 代替列表,避免存储全部数据。
应用场景:逐帧读取语音文件,而不是一次性加载整个音频。
14. 减少不必要的开销
避免重复计算(缓存结果,用 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)
15. 使用合适的解释器 & 框架
CPython:默认实现。
PyPy:JIT 加速。
C/C++ 扩展:关键部分用 C 实现(如 torch, numpy)。
应用场景:深度学习框架 PyTorch 底层就是 C++/CUDA。
16. 分布式与缓存
多机并行(Ray, Dask, Spark)。
缓存:热点数据放 Redis,减少重复计算。
17、*args和**kwargs的区别是什么?
17.1. *args
作用:接收 任意数量的位置参数,会打包成一个 元组。
适合参数个数不确定的函数。
def foo(*args):
print(args)
foo(1, 2, 3)
输出: (1, 2, 3)
17.2. **kwargs
作用:接收 任意数量的关键字参数,会打包成一个 字典。
适合需要灵活传递键值对参数的场景。
def bar(**kwargs):
print(kwargs)
bar(a=1, b=2, c=3)
输出: {‘a’: 1, ‘b’: 2, ‘c’: 3}
17.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 → 关键字参数
18、Django、Flask、Tornado三大框架各种应用的场景?
18.1 Django —— 重量级、全家桶
特点:
自带 ORM、模板系统、Admin 后台、用户认证等一整套“全家桶”。
遵循 MTV 模式,强调快速开发、约定大于配置。
有较多内置组件,适合开发复杂的大型 Web 应用。
适用场景:
大型企业应用、内容管理系统(CMS)、电商平台、新闻门户网站。
对数据一致性、权限管理要求高的系统。
典型案例: Instagram、知乎早期。
18.2. Flask —— 轻量级、自由度高
特点:
只有最核心的功能(路由 + WSGI 支持),其余功能通过扩展实现。
灵活度高,开发者可以自由选择 ORM(SQLAlchemy、Peewee 等)、模板引擎等。
学习曲线较低,适合快速搭建原型。
适用场景:
中小型 Web 应用、原型验证、API 服务、微服务。
对框架约束少,希望灵活度高的项目。
典型案例: Pinterest、国内很多中小型 SaaS。
18.3. Tornado —— 高性能异步框架
特点:
内置高性能异步非阻塞 I/O,适合处理长连接和高并发请求。
自带 Web Server,不依赖 Gunicorn/uWSGI。
学习成本稍高,生态不如 Django/Flask 丰富。
适用场景:
即时通讯(IM)、WebSocket、长轮询、实时推送系统。
对高并发、低延迟有要求的后台服务。
典型案例: FriendFeed(Facebook 收购的实时社交网站)。
✅ 一句话总结:
Django:全家桶,适合 大型复杂系统。
Flask:轻量自由,适合 中小项目、微服务、原型。
Tornado:异步高并发,适合 实时系统。
19、什么是元编程?python中如何实现元编程?
1、什么是元编程?
元编程(Metaprogramming)是指编写能够操作、生成或修改其他程序代码的程序。换句话说,元编程允许程序在运行时动态地创建或改变代码结构,从而实现更高层次的抽象和灵活性。
简单的说,当你的程序存在大量的重复代码时候,你就需要考虑是否有更好的解决方案
2、python中如何实现元编程?
Python 提供了多种实现元编程的方式,主要包括以下几种:
2.1 使用装饰器(Decorators)
装饰器是一种特殊的函数,可以在不修改原函数代码的情况下,动态地增强或修改函数的行为。装饰器本质上是一个高阶函数,接受一个函数作为参数,并返回一个新的函数。
def log_decorator(func):
def wrapper(*args, **kwargs):
print(f"Calling function {func.__name__} with args {args} and kwargs {kwargs}")
result = func(*args, **kwargs)
print(f"Function {func.__name__} returned {result}")
return result
return wrapper
@log_decorator
def add(a, b):
return a + b
add(2, 3)
2.2 使用元类(Metaclasses)
元类是用于创建类的类。通过定义元类,可以在类创建时动态地修改类的属性和方法。元类通常继承自 type 类。
class MyMeta(type):
def __new__(cls, name, bases, attrs):
attrs['greet'] = lambda self: f"Hello from {name}!"
return super().__new__(cls, name, bases, attrs)
class MyClass(metaclass=MyMeta):
pass
obj = MyClass()
print(obj.greet()) # 输出: Hello from MyClass!
2.3 使用反射(Reflection)
反射允许程序在运行时动态地检查和修改对象的属性和方法。Python 提供了内置函数如 getattr、setattr、hasattr 和 dir 来实现反射。
class Person:
def __init__(self, name):
self.name = name
p = Person("Alice")
# 使用反射获取属性
print(getattr(p, 'name')) # 输出: Alice
# 使用反射设置属性
setattr(p, 'age', 30)
print(p.age) # 输出: 30
2.4 动态代码生成
Python 允许在运行时动态地生成和执行代码。可以使用 exec 和 eval 函数来实现动态代码生成。
code = """
def dynamic_function(x):
return x * x
exec(code)
print(dynamic_function(5)) # 输出: 25
2.5 使用描述符(Descriptors)
描述符是一种特殊的对象属性,可以通过定义 get、set 和 delete 方法来控制属性的访问和修改。
class Descriptor:
def __get__(self, instance, owner):
return "Getting value"
def __set__(self, instance, value):
print(f"Setting value to {value}")
class MyClass:
attr = Descriptor()
obj = MyClass()
print(obj.attr) # 输出: Getting value
obj.attr = 42 # 输出: Setting value to 42
16、python中的反射机制是什么?如何使用反射机制?
1、什么是反射机制?
反射机制(Reflection)是指程序在运行时能够动态地检查和修改自身结构和行为的能力。通过反射,程序可以在运行时获取对象的类型信息、属性、方法等,并且可以动态地调用方法或修改属性值。反射机制使得程序具有更高的灵活性和动态性,能够适应不同的运行环境和需求。
2、python中的反射机制
Python 提供了丰富的内置函数和方法来实现反射机制,主要包括以下几个方面:
2.1 获取对象的属性和方法
Python 提供了内置函数 getattr、setattr、hasattr 和 dir 来获取对象的属性和方法。
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
p = Person("Alice", 30)
# 获取属性
print(getattr(p, 'name')) # 输出: Alice
# 检查属性是否存在
print(hasattr(p, 'age')) # 输出: True
# 获取所有属性和方法
print(dir(p))
# 设置属性
setattr(p, 'age', 31)
print(p.age) # 输出: 31
2.2 动态调用方法
可以使用 getattr 函数动态地获取并调用对象的方法。
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
calc = Calculator()
method_name = 'add'
method = getattr(calc, method_name)
result = method(5, 3)
print(result) # 输出: 8
2.3 动态创建类和对象
可以使用 type 函数动态地创建类,并使用反射机制创建对象。
# 动态创建类
MyClass = type('MyClass', (object,), {'greet': lambda self: "Hello!"})
obj = MyClass()
print(obj.greet()) # 输出: Hello!
2.4 使用反射加载模块
可以使用 importlib 模块动态地加载模块。
import importlib
module_name = 'math'
math_module = importlib.import_module(module_name)
print(math_module.sqrt(16)) # 输出: 4.0
2.5 使用反射实现插件机制
可以通过反射机制动态地加载和使用插件。
class PluginBase:
def run(self):
raise NotImplementedError("Subclasses must implement this method.")
class PluginA(PluginBase):
def run(self):
return "Plugin A running"
class PluginB(PluginBase):
def run(self):
return "Plugin B running"
plugins = [PluginA(), PluginB()]
for plugin in plugins:
print(plugin.run())
# 输出:
# Plugin A running
# Plugin B running
17、python中的反射机制在实际开发中有哪些应用场景?
1、动态加载模块和类
在大型应用中,可能需要根据配置或用户输入动态加载不同的模块或类。反射机制允许程序在运行时根据字符串名称加载模块或类,从而实现插件化设计。
import importlib
module_name = 'my_plugin'
plugin_module = importlib.import_module(module_name)
PluginClass = getattr(plugin_module, 'PluginClass')
plugin_instance = PluginClass()
plugin_instance.run()
2、动态调用方法
在某些情况下,程序需要根据用户输入或配置动态调用不同的方法。反射机制允许程序在运行时根据方法名称字符串获取并调用方法。
class Calculator:
def add(self, a, b):
return a + b
def subtract(self, a, b):
return a - b
calc = Calculator()
method_name = input("Enter method (add/subtract): ")
method = getattr(calc, method_name)
result = method(5, 3)
print(result)
3、对象序列化与反序列化
在对象序列化与反序列化过程中,反射机制可以用来动态地获取对象的属性和值,从而实现通用的序列化逻辑。
import json
class Person:
def __init__(self, name, age):
self.name = name
self.age = age
def serialize(obj):
return json.dumps({key: getattr(obj, key) for key in dir(obj) if not key.startswith('__')})
p = Person("Alice", 30)
print(serialize(p)) # 输出: {"age": 30, "name": "Alice"}
4、ORM(对象关系映射)
ORM 框架通常使用反射机制动态地将数据库表映射为类,并将表字段映射为类属性。
class User:
id = IntegerField()
name = StringField()
age = IntegerField()
user = User()
user.name = "Alice"
user.age = 30
db.save(user) # ORM 使用反射将属性映射为数据库字段