1、python 语言的基础特性

  • python中一切皆对象:
    • 在python中,无论函数、类、模块等等都是对象,他们都继承自object
    • 所有变量的本质都是对象的引用(指针)
  • 动态解释性语言:
    • python是解释性语言,运行时需要一行一行解释执行,不会编译成二进制文件执行。
    • python类型是动态的:变量无需声明类型,运行时动态决定。
  • python的数据类型
    • 内置数据类型: int float dict set list str bool tuple
      • 可变数据类型: list dict set
      • 不可变数据类型:int float 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、python的执行过程

python是一种解释性语言,这意味着python代码在执行时先转换成子字节码,然后由python虚拟机PVM执行

  1. 源代码::编写的Python文件
  2. 编译::Python解释器首先将源代码编译成字节码。这一过程涉及到语法分析和语义分析,确保代码符合Python的语法规则。字节码是一种低级、与平台无关的代码,保存在.pyc中
  3. 字节码::编译得到的字节码是一种中间表示形式,存储在内存中。字节码的执行比直接解释源代码要快。
  4. python虚拟机::Python虚拟机(PVM)是Python运行时环境的一部分,负责读取字节码,将其转换成机器码,然后执行。PVM是解释器的核心,它执行存储在pyc中
  5. 执行::PVM逐条执行字节码指令,进行函数调用、内存管理等

3、常见算法: 散列表、红黑树、二叉树,能否对应适合的应用场景(通用)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

┌───────────────┐
│ 数据结构 │
└──────┬────────┘

┌──────────────┴───────────────┐
│ │
┌─────────────┐ ┌─────────────┐
│ 散列表 │ │ 树类 │
│ (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保存,但逻辑上还是哈希表)
  • 支持快速查询、插入、删除
  • 通过哈希碰撞处理(开发寻址或者链表)

时间复杂度

1
2
3
4
5
| 操作 | 平均   | 最坏 |
| -- | ---- | ---- |
| 查找 | O(1) | O(n) |
| 插入 | O(1) | O(n) |
| 删除 | O(1) | O(n) |

典型引用场景

  • 去重:set存储已访问元素
  • 频率统计:词频统计、日志统计
  • 缓存/映射表:用户ID–> 用户信息
  • 面试高频题目:

1、两数之和

1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 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、回溯)

常见题

  • 二叉树最大深度
1
2
3
4
5
6
7
8
 
# 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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

# 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闭包

定义
函数内部定一函数,并且内部函数引用了外部函数的局部变量,就形成了闭包。
闭包能保存函数运行时的环境。

1
2
3
4
5
6
7
8

def make_multiplier(factor):
def multiply(x):
return x* factor #引用外部变量
return multiply

times2 = make_multiplier(2)
print(times2(5)) # 10

✅ 面试考点:

闭包常用于延迟计算、函数工厂、隐藏实现细节。

注意 Python 中闭包变量是 引用 而非拷贝。

5.2、装饰器(Decorator)

定义
本质是一个函数,接收一个函数作为参数,返回一个增强后的函数
常用语日志、权限检验、性能统计、缓存等等
装饰器本质上是一个函数,它接受一个函数作为参数并返回一个新的函数。

1
2
3
4
5
6
7
8
9
10
11
12
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 来处理异常,保证程序健壮性。

1
2
3
4
5
6
7
8
9
10
11
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 密集型任务(网络、磁盘)有明显加速。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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、语法

1
2
3
4
5
6
7
8
9
10
11
12

# 文件操作
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、自定义上下文管理器

1
2
3
4
5
6
7
8
9
10
11
12

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
1
2
3
4
5
6
7
8
9
10
11
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。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

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

1
2
3
4
5
6
7
8
9
10
11
12

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 浅拷贝

浅拷贝会创建一个新的对象,但是它包含是对原对象地址的引用,而不是其副本。因此如果原始对象的项是可变的,修改
这些项会影响到拷贝后的对象。
  • 创建浅拷贝的方法:
    1. 使用列表的list.copy()方法
    2. 切片操作,例如 new_list = old_list[:]
    3. 使用copy模块的copy函数: from copy import copy; new_list=copy(old_list);
1
2
3
4
5
6
7
8
9
import copy

original = [1, 2, [3, 4]]
shallow = copy.copy(original)

# 修改原始列表中的嵌套列表也会影响浅拷贝
original[2][0] = "changed"
print(shallow) # 输出:[1, 2, ['changed', 4]]

8.2 深拷贝

深拷贝创建一个新的对象,并且递归拷贝原始对象中的所有项。这意味着它将创建所有项的副本,包括嵌套对象。
修改原始对象不会影响到新创建的副本。
  • 创建深拷贝
1
2
from copy import deepcopy
deep = deepcopy(original)

9. GIL 限制

Python 有 GIL(全局解释器锁),同一时刻只有一个线程能执行 Python 字节码。

因此:
CPU 密集型任务(计算) → 适合用 multiprocessing(多进程)。
I/O 密集型任务(网络请求、文件读写) → 多线程能显著提升性能。

10、Python lambda匿名函数

在python中,lambda函数是一种轻量级的匿名函数,它通常用以编写简单的,一行的函数,无须定义正式的函数名

  • 基本语法:
1
2
3
4
lambda arguments: expression

- arguments: 参数,可以是多个,用逗号隔开
- expression: 一个表达式,描述函数的行为,返回值是个表达式的结果
  • 特点:
    1. 匿名: lambda函数通常是匿名的,没有函数名
    2. 一行表达式: 只能有一个表达式,不能包含其他的语句或者多个表达式
    3. 可随时使用: 可以在任何地方使用
    4. 灵活性: 常用简化代码,特别是在函数编程或者需要传递小函数作为参数的场合。
1
2
3
4
5
6
7
8
# 使用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}

  1. 区别总结
    特性 *args **kwargs
    参数形式 位置参数 关键字参数
    数据类型 元组 (tuple) 字典 (dict)
    应用场景 参数数量不定(如加法函数) 配置灵活(如传递参数给API)
  2. 面试延伸问题(华为 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)

装饰器是一种特殊的函数,可以在不修改原函数代码的情况下,动态地增强或修改函数的行为。装饰器本质上是一个高阶函数,接受一个函数作为参数,并返回一个新的函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
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 类。

1
2
3
4
5
6
7
8
9
10
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 来实现反射。

1
2
3
4
5
6
7
8
9
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 函数来实现动态代码生成。

1
2
3
4
5
6
code = """
def dynamic_function(x):
return x * x
exec(code)
print(dynamic_function(5)) # 输出: 25

2.5 使用描述符(Descriptors)

描述符是一种特殊的对象属性,可以通过定义 getsetdelete 方法来控制属性的访问和修改。

1
2
3
4
5
6
7
8
9
10
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 来获取对象的属性和方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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 函数动态地获取并调用对象的方法。

1
2
3
4
5
6
7
8
9
10
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 函数动态地创建类,并使用反射机制创建对象。

1
2
3
4
# 动态创建类
MyClass = type('MyClass', (object,), {'greet': lambda self: "Hello!"})
obj = MyClass()
print(obj.greet()) # 输出: Hello!

2.4 使用反射加载模块

可以使用 importlib 模块动态地加载模块。

1
2
3
4
5
import importlib
module_name = 'math'
math_module = importlib.import_module(module_name)

print(math_module.sqrt(16)) # 输出: 4.0

2.5 使用反射实现插件机制

可以通过反射机制动态地加载和使用插件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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、动态加载模块和类

在大型应用中,可能需要根据配置或用户输入动态加载不同的模块或类。反射机制允许程序在运行时根据字符串名称加载模块或类,从而实现插件化设计。

1
2
3
4
5
6
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、动态调用方法

在某些情况下,程序需要根据用户输入或配置动态调用不同的方法。反射机制允许程序在运行时根据方法名称字符串获取并调用方法。

1
2
3
4
5
6
7
8
9
10
11
12
  
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、对象序列化与反序列化

在对象序列化与反序列化过程中,反射机制可以用来动态地获取对象的属性和值,从而实现通用的序列化逻辑。

1
2
3
4
5
6
7
8
9
10
11

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 框架通常使用反射机制动态地将数据库表映射为类,并将表字段映射为类属性。

1
2
3
4
5
6
7
8
9

class User:
id = IntegerField()
name = StringField()
age = IntegerField()
user = User()
user.name = "Alice"
user.age = 30
db.save(user) # ORM 使用反射将属性映射为数据库字段

__END__