目录
- [1 python 垃圾处理机制](#1 python 垃圾处理机制)
- [2 yield](#2 yield)
- [3 python 多继承,两个父类有同名方法怎么办?](#3 python 多继承,两个父类有同名方法怎么办?)
- [4 python 多线程/多进程/协程](#4 python 多线程/多进程/协程)
-
- [4.1 多线程与GIL全局解释器锁](#4.1 多线程与GIL全局解释器锁)
- [4.2 多进程](#4.2 多进程)
- [4.3 协程](#4.3 协程)
- [5 乐观锁/悲观锁](#5 乐观锁/悲观锁)
- [6 基本数据结构](#6 基本数据结构)
-
-
- [**1. 列表(List)**](#1. 列表(List))
- [**2. 元组(Tuple)**](#2. 元组(Tuple))
- [**3. 字典(Dictionary)**](#3. 字典(Dictionary))
- [**4. 集合(Set)**](#4. 集合(Set))
- [**5. 字符串(String)**](#5. 字符串(String))
- [**6. 队列(Queue)**](#6. 队列(Queue))
- [**7. 栈(Stack)**](#7. 栈(Stack))
- [**8. 堆(Heap)**](#8. 堆(Heap))
- **汇总**
-
- [7 `is` 和 `==` 的区别(适用于 Python 3.7)](#7
is
和==
的区别(适用于 Python 3.7)) - [8 什么是 Lambda 函数(适用于 Python 3.8)](#8 什么是 Lambda 函数(适用于 Python 3.8))
- [9 函数传参](#9 函数传参)
- [10 `*args` 和 `**kwargs` 的用法与原理**](#10
*args
和**kwargs
的用法与原理**) -
-
-
- [**(1) `*args`(可变位置参数)**](#(1)
*args
(可变位置参数)) - [**(2) `**kwargs`(可变关键字参数)**](#(2)
**kwargs
(可变关键字参数)) - [**(3) `*args` 和 `**kwargs` 混用**](#(3)
*args
和**kwargs
混用)
- [**(1) `*args`(可变位置参数)**](#(1)
-
-
- [11 装饰器(Decorator)的作用与原理](#11 装饰器(Decorator)的作用与原理)
-
-
-
- [**(1) 装饰器的作用**](#(1) 装饰器的作用)
- [**(2) 装饰器的原理**](#(2) 装饰器的原理)
-
-
- [12 Python 变量的作用域](#12 Python 变量的作用域)
- [13 解释型和编译型语言的区别](#13 解释型和编译型语言的区别)
-
-
-
- [**(1) 解释型语言**](#(1) 解释型语言)
- [**(2) 编译型语言**](#(2) 编译型语言)
-
-
- [14 `init `和 `new `的区别](#14
__init__
和__new__
的区别) - [15 Python 的 `list` 和 `numpy.array`(数组)的区别](#15 Python 的
list
和numpy.array
(数组)的区别) -
-
-
- [**1. 类型限制**](#1. 类型限制)
- [**2. 性能**](#2. 性能)
- [**3. 功能与方法**](#3. 功能与方法)
- [**4. 内存效率**](#4. 内存效率)
- [**5. 维度支持**](#5. 维度支持)
- [**6. 广播机制**](#6. 广播机制)
- **总结**
-
-
- [16 Python 的面向对象(OOP)](#16 Python 的面向对象(OOP))
-
-
- [1. **封装 (Encapsulation)**](#1. 封装 (Encapsulation))
- [2. **继承 (Inheritance)**](#2. 继承 (Inheritance))
- [3. **多态 (Polymorphism)**](#3. 多态 (Polymorphism))
-
- 17
1 python 垃圾处理机制
2 yield
python
def fibonacci(n):
result = []
a, b = 0, 1
for _ in range(n):
result.append(a) # 存储所有 Fibonacci 数值
a, b = b, a + b
return result # 一次性返回所有值
fib = fibonacci(1000000) # 计算 100 万个斐波那契数
def fibonacci(n):
a, b = 0, 1
for _ in range(n):
yield a # 每次迭代返回一个值,而不是存入列表
a, b = b, a + b
fib = fibonacci(1000000) # 创建生成器对象,但不立即计算
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
print(next(fib))
0
1
1
2
3
3 python 多继承,两个父类有同名方法怎么办?
单继承
python
class Parent:
def greet(self):
print("Hello from Parent!")
class Child(Parent): # Child 继承 Parent
pass
c = Child()
c.greet() # 输出: Hello from Parent!
多继承
python
class Parent1:
def greet(self):
print("Hello from Parent1!")
class Parent2:
def greet(self):
print("Hello from Parent2!")
class Child(Parent1, Parent2): # 继承多个父类
pass
c = Child()
c.greet() # 输出什么?
Python 解决多继承方法冲突的方法是 MRO(Method Resolution Order),即方法解析顺序。在 Python 中,MRO 遵循 C3 线性化算法,它按照深度优先+广度遍历的方式来确定方法的调用顺序。
可以用 .__ mro__ 或 mro() 方法查看 MRO:
print(Child.__mro__)
(<class 'main .Child'>, <class 'main .Parent1'>, <class 'main .Parent2'>, <class 'object'>)
先查找 Child
再查找 Parent1
再查找 Parent2
最后查找 object(所有类的基类)
解决方法冲突
直接指定某个父类的方法
python
class Parent1:
def greet(self):
print("Hello from Parent1!")
class Parent2:
def greet(self):
print("Hello from Parent2!")
class Child(Parent1, Parent2):
def greet(self):
Parent2.greet(self) # 直接调用 Parent2 的方法
c = Child()
c.greet() # 输出: Hello from Parent2!
4 python 多线程/多进程/协程
多线程指在同一个进程内通过创建多个线程来执行任务。每个线程都可以执行不同的任务,但它们共享同一进程的内存空间和资源。
多进程是指通过创建多个进程来并行执行任务。每个进程拥有独立的内存空间和资源,可以完全独立地运行。

4.1 多线程与GIL全局解释器锁
在同一进程中创建多个线程,共享进程内存空间,通过线程调度器实现并发执行。由于 Python 的 GIL(全局解释器锁)GIL全局解释器锁,多线程在 CPU 密集型任务(如计算)下无法真正实现并行,只适用于 I/O 密集型任务(如网络请求、文件读写)。
python
使用方式1 传入目标方法
import threading
def worker():
print('线程正在执行')
# 创建线程
t = threading.Thread(target=worker)
# 启动线程
t.start()
# 等待线程执行完毕
t.join()
使用方式2 集成重写方法
class MyThread(threading.Thread):
def run(self):
print(f'{self.name} 线程正在执行')
# 创建线程实例
my_thread = MyThread()
# 启动线程
my_thread.start()
# 等待线程执行完毕
my_thread.join()
4.2 多进程
4.3 协程
- 协程极高的执行效率。因为子程序切换不是线程切换,而是由程序自身控制,因此,没有线程切换的开销,和多线程比,线程数量越多,协程的性能优势就越明显。
- 第二大优势就是不需要多线程的锁机制,因为只有一个线程,也不存在同时写变量冲突,在协程中控制共享资源不加锁,只需要判断状态就好了,所以执行效率比多线程高很多。
python
def coroutine_example():
print("Coroutine started")
x = yield "First yield value"
print(f"Received: {x}")
y = yield "Second yield value"
print(f"Received: {y}")
return "Coroutine finished"
# 创建协程实例
coroutine = coroutine_example()
# 启动协程,执行到第一个yield处
print(next(coroutine)) # 输出: Coroutine started,并返回 "First yield value"
# 恢复协程,传入值给x,继续执行到第二个yield处
print(coroutine.send(10)) # 输出: Received: 10,并返回 "Second yield value"
# 再次恢复协程,传入值给y,继续执行到结束
result = coroutine.send(20) # 输出: Received: 20,然后协程结束
# 捕获协程结束时的返回值
print(f"Coroutine result: {result}") # 输出: Coroutine result: Coroutine finished
# 尝试再次恢复协程会引发StopIteration异常
try:
coroutine.send(30)
except StopIteration as e:
print(f"Coroutine ended with exception: {e}") # 捕获异常并输出
5 乐观锁/悲观锁
悲观锁 适用于高并发、冲突频繁的场景 确保同一时刻只有一个线程能访问数据,从而避免数据不一致
乐观锁 适用于并发冲突较少的场景 它允许多个线程同时读取数据,更新时检查数据是否被修改,若有冲突则重试。
6 基本数据结构
Python 的基本数据结构主要包括以下几类:
1. 列表(List)
- 可变,支持增删改查
- 有序,支持索引访问
- 允许重复元素
- 底层实现:动态数组
python
lst = [1, 2, 3, 4]
lst.append(5) # 添加元素
lst.pop() # 删除末尾元素
lst[1] = 99 # 修改元素
2. 元组(Tuple)
- 不可变,一旦创建不能修改
- 有序,支持索引访问
- 允许重复元素
- 底层实现:静态数组
python
tup = (1, 2, 3, 4)
val = tup[1] # 访问元素
3. 字典(Dictionary)
- 可变,支持动态添加键值对
- 无序(Python 3.6 之前) ,有序(Python 3.7+)
- 键唯一,不可变;值可变
- 底层实现:哈希表(dict 使用哈希函数存储键值对)
python
d = {'a': 1, 'b': 2}
d['c'] = 3 # 添加键值对
d.pop('b') # 删除键值对
4. 集合(Set)
- 可变,支持增删元素
- 无序
- 不允许重复元素
- 底层实现:哈希表
python
s = {1, 2, 3}
s.add(4) # 添加元素
s.remove(2) # 删除元素
5. 字符串(String)
- 不可变
- 有序,支持索引访问
- 支持切片
- 底层实现:字符数组
python
s = "hello"
print(s[1]) # 'e'
print(s[:3]) # 'hel'
6. 队列(Queue)
- FIFO(先进先出)
- 通常使用
collections.deque
实现
python
from collections import deque
q = deque()
q.append(1) # 入队
q.popleft() # 出队
7. 栈(Stack)
- LIFO(后进先出)
- 通常使用
list
或collections.deque
实现
python
stack = []
stack.append(1) # 入栈
stack.pop() # 出栈
8. 堆(Heap)
- 默认是最小堆
- Python 使用
heapq
模块
python
import heapq
heap = [3, 1, 4]
heapq.heapify(heap) # 转换为堆
heapq.heappush(heap, 2) # 入堆
heapq.heappop(heap) # 出堆(最小值)
汇总
数据结构 | 可变性 | 有序性 | 允许重复 | 适用场景 |
---|---|---|---|---|
列表(list) | ✅ 可变 | ✅ 有序 | ✅ 允许 | 需要动态增删改查 |
元组(tuple) | ❌ 不可变 | ✅ 有序 | ✅ 允许 | 需要不可变序列 |
字典(dict) | ✅ 可变 | ✅ 有序 (Py3.7+) | ❌ 键唯一 | 需要键值对存储 |
集合(set) | ✅ 可变 | ❌ 无序 | ❌ 不允许 | 需要去重 |
字符串(str) | ❌ 不可变 | ✅ 有序 | ✅ 允许 | 处理文本 |
队列(queue) | ✅ 可变 | ✅ 有序 | ✅ 允许 | 先进先出(FIFO) |
栈(stack) | ✅ 可变 | ✅ 有序 | ✅ 允许 | 后进先出(LIFO) |
堆(heap) | ✅ 可变 | ✅ 有序 | ✅ 允许 | 维护最小/最大值 |
7 is
和 ==
的区别(适用于 Python 3.7)
is
比较的是对象的内存地址(是否是同一个对象)。==
比较的是对象的值(内容是否相等)。
示例
python
a = [1, 2, 3]
b = [1, 2, 3]
c = a
print(a == b) # True (内容相同)
print(a is b) # False (a 和 b 是不同的对象)
print(a == c) # True (内容相同)
print(a is c) # True (a 和 c 指向同一对象)
8 什么是 Lambda 函数(适用于 Python 3.8)
lambda
函数是匿名函数 ,即没有名字的函数 ,使用 lambda
关键字定义。
语法
python
lambda 参数: 表达式
示例
python
add = lambda x, y: x + y
print(add(3, 5)) # 8
等价于:
python
def add(x, y):
return x + y
应用场景
- 用于
map()
、filter()
、sorted()
python
nums = [1, 2, 3, 4, 5]
squared = list(map(lambda x: x**2, nums))
print(squared) # [1, 4, 9, 16, 25]
even_nums = list(filter(lambda x: x % 2 == 0, nums))
print(even_nums) # [2, 4]
pairs = [(1, 2), (3, 1), (5, 0)]
pairs.sort(key=lambda x: x[1])
print(pairs) # [(5, 0), (3, 1), (1, 2)]
- 作为
functools.reduce()
的参数
python
from functools import reduce
nums = [1, 2, 3, 4]
product = reduce(lambda x, y: x * y, nums)
print(product) # 24
9 函数传参
类型 | 可变性 | 示例 | 函数内部修改是否影响原变量 |
---|---|---|---|
不可变对象 | ❌ 不可变 | int 、float 、str 、tuple |
❌ 不影响,创建新对象 |
可变对象 | ✅ 可变 | list 、dict 、set |
✅ 影响,会修改原对象 |
10 *args
和 **kwargs
的用法与原理**
(1) *args
(可变位置参数)
- 允许函数接收任意数量的位置参数,并将它们存储为一个 元组 (
tuple
)。
python
def add(*args):
return sum(args)
print(add(1, 2, 3)) # 6
print(add(4, 5, 6, 7)) # 22
等价于:
python
def add(a, b, c):
return a + b + c
原理 :
*args
作用是 收集 多个位置参数,将它们封装成一个元组传递给函数。
(2) **kwargs
(可变关键字参数)
- 允许函数接收任意数量的 关键字参数 ,并将它们存储为 字典 (
dict
)。
python
def greet(**kwargs):
for key, value in kwargs.items():
print(f"{key} : {value}")
greet(name="Alice", age=25, country="USA")
# name : Alice
# age : 25
# country : USA
原理 :
**kwargs
作用是 收集 多个关键字参数,并存储为字典 {key: value}
传递给函数。
(3) *args
和 **kwargs
混用
*args
必须放在**kwargs
之前,否则会报错。
python
def demo(a, b, *args, c=10, **kwargs):
print(a, b, args, c, kwargs)
demo(1, 2, 3, 4, 5, c=20, x=100, y=200)
# 输出:1 2 (3, 4, 5) 20 {'x': 100, 'y': 200}
11 装饰器(Decorator)的作用与原理
(1) 装饰器的作用
装饰器用于 在不修改原函数代码的情况下,增强函数的功能,比如:
- 计算函数执行时间
- 记录日志
- 检查权限
- 缓存数据
(2) 装饰器的原理
装饰器本质上是一个函数,它接受一个函数作为参数,并返回一个新的函数。
python
def decorator(func):
def wrapper():
print("执行前")
func()
print("执行后")
return wrapper
@decorator
def hello():
print("Hello, world!")
hello()
# 执行前
# Hello, world!
# 执行后
等价于:
python
def hello():
print("Hello, world!")
hello = decorator(hello)
hello()
@decorator
语法糖的作用 :等价于 hello = decorator(hello)
12 Python 变量的作用域
Python 作用域遵循 LEGB 规则:
- Local(局部作用域):函数内部定义的变量。
- Enclosing(闭包作用域):外部嵌套函数的变量。
- Global(全局作用域):模块级变量。
- Built-in(内建作用域) :Python 预定义的变量,如
len()
。
python
x = "global"
def outer():
x = "enclosing"
def inner():
x = "local"
print(x) # 输出 "local"
inner()
print(x) # 输出 "enclosing"
outer()
print(x) # 输出 "global"
13 解释型和编译型语言的区别
(1) 解释型语言
- 代码逐行执行,不需要预先编译。
- 运行时才翻译,直接执行。
- 适用于动态语言(Python、JavaScript)。
python
print("Hello, World!") # Python 解释器逐行执行
(2) 编译型语言
- 代码需要 先编译 成机器码(
.exe
等),然后执行。 - 运行速度快,但需要编译过程。
- 适用于静态语言(C、C++、Rust)。
c
#include <stdio.h>
int main() {
printf("Hello, World!");
return 0;
}
编译后生成 a.out
文件,运行时不需要解释。
14 __init__
和 __new__
的区别
方法 | 作用 | 调用时机 |
---|---|---|
__new__ |
创建对象,返回对象实例 | 类实例化时,先调用 __new__ |
__init__ |
初始化对象,设置属性 | __new__ 之后调用 __init__ |
python
class A:
def __new__(cls, *args, **kwargs):
print("调用 __new__")
instance = super().__new__(cls)
return instance
def __init__(self, name):
print("调用 __init__")
self.name = name
a = A("Tom")
# 调用 __new__
# 调用 __init__
15 Python 的 list
和 numpy.array
(数组)的区别
虽然 list
和 numpy.array
都是可以存储一系列元素的容器,但它们在以下几个方面有显著区别:
1. 类型限制
-
list
:
list
是 动态类型,可以存储不同类型的元素,例如整数、字符串、浮点数等。元素的类型可以混合在一起。pythonmy_list = [1, "hello", 3.14]
-
numpy.array
:
numpy.array
是 同质类型,即所有元素必须是相同的数据类型(例如,全是整数或浮点数),并且在创建时会固定类型。这样做的好处是可以更高效地进行数值计算。pythonimport numpy as np arr = np.array([1, 2, 3]) # 类型为整数
2. 性能
-
list
:Python 的
list
是为通用数据存储设计的,它的元素可以是任何对象,因此它的操作(如访问、添加或删除元素)通常需要更多的内存管理和更复杂的逻辑。对于大规模数值计算或高性能需求,list
可能不够高效。 -
numpy.array
:
numpy.array
是专门为科学计算设计的,所有元素都是同一数据类型,因此在内存中是连续存储的。这样可以利用低级优化(如 SIMD)来提高性能,特别是在进行大量数学运算时,numpy.array
显著优于list
。pythonimport numpy as np arr1 = np.array([1, 2, 3, 4, 5]) arr2 = np.array([6, 7, 8, 9, 10]) result = arr1 + arr2 # 进行高效的向量加法
3. 功能与方法
-
list
:
list
是 Python 内建的数据结构,支持的基本操作包括添加、删除、修改、切片等,但它不支持直接进行数学或向量操作。pythonmy_list = [1, 2, 3] my_list.append(4) my_list.pop()
-
numpy.array
:
numpy.array
提供了 大量的数学运算和线性代数操作,例如向量加法、矩阵乘法、元素级操作、广播等。pythonimport numpy as np arr = np.array([1, 2, 3]) result = arr * 2 # 每个元素都乘以 2 print(result) # 输出 [2, 4, 6]
numpy
还支持很多函数,比如矩阵乘法(np.dot()
)、求和(np.sum()
)等。
4. 内存效率
-
list
:Python 的
list
是动态数组,元素存储为指针,因此每个元素的内存开销较大。此外,由于 Python 的list
是动态扩展的,可能会发生重新分配内存,这也会影响性能。 -
numpy.array
:
numpy.array
使用 紧凑的内存布局,所有元素连续存储,这使得它的内存使用更加高效,尤其是当处理大量数据时。
5. 维度支持
-
list
:Python 的
list
只能表示一维数组。如果要表示多维数据(如二维矩阵),通常会使用嵌套list
。pythonmy_list = [[1, 2], [3, 4], [5, 6]] # 需要嵌套 list 来模拟二维矩阵
-
numpy.array
:
numpy.array
支持任意维度的数组,能够表示 一维、二维、三维 等复杂的数据结构,并可以轻松地进行切片和变形操作。pythonarr = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]) # 2D array
6. 广播机制
-
list
:
list
不支持 广播机制 (Broadcasting),这意味着你不能直接对list
进行元素级的算术操作。 -
numpy.array
:
numpy.array
支持广播机制,可以让不同形状的数组之间进行运算。它会自动扩展数组的形状,以便进行元素级运算。pythonarr = np.array([1, 2, 3]) result = arr + 10 # 结果是 [11, 12, 13]
总结
list
是 Python 内建的通用容器,适用于存储不同类型的元素,且易于使用,但在进行数值计算时性能不佳。numpy.array
是为科学计算设计的高效数组类型,它支持同质数据存储、广播机制和大量的数学运算操作,特别适用于需要高性能的数值计算任务。
在处理大量数值数据时,numpy.array
更加高效。如果你的任务主要涉及到数值计算、矩阵操作等,建议使用 numpy
。而如果你需要处理混合类型的数据或进行常规的存储,list
可能更合适。
16 Python 的面向对象(OOP)
Python 的面向对象(OOP)特性包括 封装 、继承 和 多态,这三个是面向对象编程的核心概念。下面详细解释这三个特性:
1. 封装 (Encapsulation)
封装是指将对象的状态(属性)和行为(方法)绑定在一起,并对外界隐藏实现细节,只暴露必要的接口。
封装的关键点:
- 私有属性和方法 :可以使用双下划线(
__
)将属性或方法标记为私有,防止外部直接访问或修改。 - 公共接口:通过公共的接口(通常是方法),提供对私有数据的访问或操作。这样,外部只能通过这些方法访问和修改对象的状态,而无法直接改变对象的内部实现。
示例:
python
class Person:
def __init__(self, name, age):
self.__name = name # 私有属性
self.__age = age # 私有属性
def get_name(self): # 公共方法
return self.__name
def set_name(self, name): # 公共方法
self.__name = name
def get_age(self): # 公共方法
return self.__age
def set_age(self, age): # 公共方法
self.__age = age
# 创建对象
person = Person("Alice", 30)
print(person.get_name()) # 通过公共接口访问私有属性
通过封装,我们可以控制对象的属性的读取和修改方式,保证对象的状态在有效范围内。
2. 继承 (Inheritance)
继承是面向对象的一种机制,允许一个类继承另一个类的属性和方法。继承实现了代码的复用,并支持子类重写父类的方法,从而能够对父类的行为进行定制。
继承的关键点:
- 父类和子类:父类(或基类)是被继承的类,子类(或派生类)是继承父类的类。子类可以继承父类的所有公有属性和方法,也可以重写父类的方法。
- 方法重写:子类可以重写父类的方法来改变或扩展其行为。
示例:
python
class Animal:
def speak(self):
print("Animal makes a sound")
class Dog(Animal): # Dog 类继承 Animal 类
def speak(self): # 重写父类方法
print("Dog barks")
class Cat(Animal): # Cat 类继承 Animal 类
def speak(self): # 重写父类方法
print("Cat meows")
# 创建对象
dog = Dog()
dog.speak() # 输出 Dog barks
cat = Cat()
cat.speak() # 输出 Cat meows
在上面的例子中,Dog
和 Cat
都继承了 Animal
类,并且各自重写了 speak
方法,实现了不同的行为。继承让代码更具可复用性。
3. 多态 (Polymorphism)
多态是指同一个方法或操作可以作用于不同的对象上,并且表现出不同的行为。多态可以通过方法重写(子类中重新定义父类方法)和接口统一来实现。
多态的关键点:
- 方法重写:子类可以重写父类的方法,使得不同子类的对象能够调用相同的方法时表现出不同的行为。
- 统一接口:不同类型的对象可以通过统一的接口(方法)进行操作,方法的具体实现取决于对象的类型。
示例:
python
class Animal:
def speak(self):
raise NotImplementedError("Subclass must implement abstract method")
class Dog(Animal):
def speak(self):
print("Dog barks")
class Cat(Animal):
def speak(self):
print("Cat meows")
# 创建对象
animals = [Dog(), Cat()]
for animal in animals:
animal.speak() # 输出不同的行为:Dog barks 和 Cat meows
在上面的例子中,Dog
和 Cat
都继承自 Animal
类,并重写了 speak
方法。通过父类引用调用 speak()
方法时,Python 会根据实际的对象类型(Dog
或 Cat
)来决定调用哪个版本的 speak
方法,从而实现了多态。
总结:
- 封装:通过限制直接访问对象的属性和方法,保证对象的状态不被外部直接修改,提供了更好的数据保护和接口管理。
- 继承:通过继承机制,子类可以复用父类的代码,并可以通过方法重写扩展或修改父类的行为。
- 多态:允许同一接口根据对象的不同类型表现出不同的行为,从而使得程序更具扩展性和灵活性。
这三个特性是面向对象编程的基础,设计更清晰、更易维护的代码。