python语言中的常用容器(集合)
1.核心内置容器
1. 列表
类型名:
list
可变性: 可变
有序性: 有序(元素按插入顺序排列,可通过索引访问)
元素要求: 可存放任意类型、可重复的元素。
语法: 使用方括号
[]
创建,元素用逗号分隔。主要特性:
最通用、最常用的序列类型。
支持丰富的操作:索引 (
lst[0]
)、切片 (lst[1:3]
)、拼接 (+
)、重复 (*
)、成员检查 (in
)。提供多种方法来修改内容:
.append()
,.insert()
,.pop()
,.remove()
,.sort()
等。
my_list = [1, 2, 'hello', 3.14, 1] # 可重复,不同类型
my_list[0] = 100 # 可变,可以修改元素
print(my_list) # 输出: [100, 2, 'hello', 3.14, 1]
2. 元组
类型名:
tuple
可变性: 不可变
有序性: 有序(元素按插入顺序排列,可通过索引访问)
元素要求: 可存放任意类型、可重复的元素。
语法: 使用圆括号
()
创建,元素用逗号分隔。单元素元组需加逗号(如(1,)
)。主要特性:
一旦创建,其内容无法修改(但如果元素本身是可变对象,如列表,则该列表的内容可以修改)。
因其不可变性,常用于需要数据安全、保证不会被更改的场景,如作为字典的键、函数返回多个值等。
性能通常略优于列表。
my_tuple = (1, 2, 'world', [3, 4])
# my_tuple[0] = 100 # 错误!元组不可变
my_tuple[3].append(5) # 正确。因为元组中的列表是可变的
print(my_tuple) # 输出: (1, 2, 'world', [3, 4, 5])
3. 集合
类型名:
set
可变性: 可变
有序性: 无序(Python 3.7+ 后,实现细节上保留了插入顺序,但绝不能依赖于此进行编程。从语言定义上讲,它是无序的)。
元素要求: 元素必须是可哈希的(如数字、字符串、元组等不可变类型)。元素不可重复。
语法: 使用花括号
{}
创建(但空集合必须用set()
创建),元素用逗号分隔。主要特性:
核心功能是去重和成员关系测试(检查元素是否存在),这两项操作效率极高(时间复杂度为 O(1))。
支持数学上的集合运算:并集 (
|
), 交集 (&
), 差集 (-
), 对称差集 (^
)。
my_set = {1, 2, 3, 2, 'hello'} # 自动去重
print(my_set) # 输出可能是 {1, 2, 3, 'hello'} (顺序不确定)
my_set.add(4) # 可变,可以添加元素
print(2 in my_set) # 成员检查,输出: True
4. 冻结集合
类型名:
frozenset
可变性: 不可变
有序性: 无序
元素要求: 同
set
,元素必须是可哈希的且不可重复。语法: 使用
frozenset()
函数创建,可传入一个可迭代对象(如列表、元组)。主要特性:
具有
set
的所有特性(去重、成员测试、集合运算),但内容不可变。因其不可变性,它本身是可哈希的,因此可以作为字典的键或另一个集合的元素。
my_frozenset = frozenset([1, 2, 2, 3])
print(my_frozenset) # 输出: frozenset({1, 2, 3})
# my_frozenset.add(4) # 错误!不可变集合
5. 字典
类型名:
dict
可变性: 可变
有序性: 有序(自 Python 3.7 起,字典正式保持键的插入顺序)。
元素要求: 键必须是可哈希的,值可以是任意对象。键不可重复。
语法: 使用花括号
{}
创建,键值对形式key: value
,用逗号分隔。空字典为{}
。主要特性:
存储键值对映射关系,通过键来高效地查找、插入和删除对应的值(时间复杂度为 O(1))。
是 Python 中极其重要的数据结构。
my_dict = {'name': 'Alice', 'age': 25, 1: 'number'}
my_dict['country'] = 'USA' # 添加新的键值对
print(my_dict['name']) # 通过键访问值,输出: Alice
print(list(my_dict.keys())) # 输出键列表: ['name', 'age', 1, 'country'] (保持插入顺序)
2.collections模块中的高级集合
collections
模块提供了多种专门化的容器数据类型,它们是对 Python 通用内置容器(如字典、列表、集合)的强大补充。这些数据结构针对特定用例进行了优化,能够提供更好的性能或更便利的接口。
6. 命名元组
namedtuple
是元组的子类,它为元组的每个位置分配一个名称,同时保留元组的特性(不可变、有序、可通过索引访问)。普通元组需要通过数字索引访问元素(如 point[0]
, point[1]
),这使得代码可读性差且容易出错。namedtuple
允许使用有意义的名称访问相同的数据。
from collections import namedtuple# 创建一个名为'Point'的namedtuple类,具有字段'x'和'y'
Point = namedtuple('Point', ['x', 'y'])# 创建实例
p = Point(11, y=22)# 访问字段
print(p.x) # 输出: 11
print(p.y) # 输出: 22
print(p[0]) # 仍然可以通过索引访问: 11# 不可变性(继承自元组)
# p.x = 33 # 这会报错:AttributeError: can't set attribute
7. 双端队列
deque
是一个线程安全、可以快速从两端添加或删除元素的序列容器。Python 的列表在尾部操作(追加和弹出)非常高效(O(1)时间复杂度),但在头部操作(插入和删除)效率较低(O(n)时间复杂度)。deque
在两端操作都是 O(1) 时间复杂度。
from collections import deque# 创建双端队列
d = deque(['b', 'c', 'd'])# 从左侧添加元素
d.appendleft('a') # deque(['a', 'b', 'c', 'd'])# 从右侧添加元素
d.append('e') # deque(['a', 'b', 'c', 'd', 'e'])# 从左侧弹出元素
left_item = d.popleft() # 'a', deque变为['b', 'c', 'd', 'e']# 从右侧弹出元素
right_item = d.pop() # 'e', deque变为['b', 'c', 'd']# 限制最大长度(当队列满时,添加新元素会从另一端自动删除元素)
limited_deque = deque(maxlen=3)
limited_deque.extend([1, 2, 3]) # deque([1, 2, 3], maxlen=3)
limited_deque.append(4) # deque([2, 3, 4], maxlen=3) - 自动删除最左边的1
8. 计数器
Counter
是 dict
的子类,用于统计可哈希对象的出现次数。它是一个无序集合,其中元素存储为字典键,它们的计数存储为字典值。手动统计元素频率需要编写循环和条件判断,而 Counter
提供了简洁高效的接口来完成这一常见任务。
from collections import Counter# 从可迭代对象创建
words = ['apple', 'banana', 'apple', 'orange', 'banana', 'apple']
word_count = Counter(words)
print(word_count) # Counter({'apple': 3, 'banana': 2, 'orange': 1})# 从映射创建
c = Counter({'red': 4, 'blue': 2}) # Counter({'red': 4, 'blue': 2})# 从关键字参数创建
c = Counter(cats=4, dogs=8) # Counter({'dogs': 8, 'cats': 4})# 常用操作
print(word_count.most_common(2)) # 出现频率最高的2个元素: [('apple', 3), ('banana', 2)]c = Counter(a=3, b=1)
d = Counter(a=1, b=2)
print(c + d) # 相加: Counter({'a': 4, 'b': 3})
print(c - d) # 相减: Counter({'a': 2})
print(c & d) # 交集: Counter({'a': 1, 'b': 1})
print(c | d) # 并集: Counter({'a': 3, 'b': 2})
9. 默认字典
defaultdict
是 dict
的子类,它重写了一个方法并添加了一个可写的实例变量。当尝试访问不存在的键时,它会自动创建该键并使用提供的工厂函数初始化其值。使用普通字典时,访问不存在的键会引发 KeyError
,需要先检查键是否存在或使用 get()
方法。defaultdict
自动处理这种情况,使代码更简洁。
from collections import defaultdict# 使用list作为工厂函数,当键不存在时创建空列表
dd = defaultdict(list)dd['fruits'].append('apple') # 自动创建'fruits'键并初始化为空列表
dd['fruits'].append('banana')
print(dd) # defaultdict(<class 'list'>, {'fruits': ['apple', 'banana']})# 使用int作为工厂函数,默认值为0
counts = defaultdict(int)
counts['apple'] += 1 # 自动创建'apple'键并初始化为0,然后加1
print(counts) # defaultdict(<class 'int'>, {'apple': 1})# 使用lambda函数提供自定义默认值
prices = defaultdict(lambda: 10.0) # 默认价格为10.0
print(prices['unknown_item']) # 输出: 10.0
3.numpy数组
NumPy 是 Python 科学计算生态系统的基石和核心库。几乎所有处理数据、进行科学计算或机器学习的 Python 工具(如 Pandas, Scikit-learn, SciPy, TensorFlow, PyTorch)都构建在 NumPy 的基础之上。这也是为什么numpy单独开一章来讲!
对比一下list与numpy:
# 使用 Python list (效率低)
a = [1, 2, 3, 4]
b = [5, 6, 7, 8]
result = []
for x, y in zip(a, b):result.append(x**2 + y**2)# 使用 NumPy (高效、简洁)
import numpy as np
a_np = np.array([1, 2, 3, 4])
b_np = np.array([5, 6, 7, 8])
result_np = a_np**2 + b_np**2 # 直接对整个数组操作
numpy无需编写循环,就可以直接对整个数组进行算术运算、逻辑运算等。这得益于其广播(Broadcasting) 机制,使得不同形状的数组可以进行数学运算。
广播规则:从尾部维度开始,向前面维度推进,如果两个数组的维度大小相等或其中一个为1,则它们是兼容的,可以进行广播。
# 将一个向量加到矩阵的每一行上
a = np.array([[1, 2, 3],[4, 5, 6]]) # Shape: (2, 3)
b = np.array([10, 20, 30]) # Shape: (3,)
# b 的 shape 会被“广播”成 (1, 3),然后再“广播”成 (2, 3)
result = a + b
print(result)
# [[11 22 33]
# [14 25 36]]
除此之外numpy还有更多更强大的优势,例如具有丰富的数学函数库提供了大量标准的数学函数(sin
, cos
, exp
, log
...)、线性代数运算(矩阵乘法、求逆、行列式...)、随机数生成、傅里叶变换等,全部针对数组进行优化;强大的索引功能,除了类似列表的基础索引,还支持布尔索引、花式索引等,可以非常灵活地访问和修改数组数据。等等优势
下面简要介绍一下numpy的基础用法
3.1 导入 NumPy
import numpy as np
3.2 创建数组
# 从列表创建
arr1 = np.array([1, 2, 3, 4, 5]) # 一维数组
arr2 = np.array([[1, 2, 3], [4, 5, 6]]) # 二维数组# 使用内置函数创建
zeros_arr = np.zeros((3, 4)) # 创建 3x4 的全0数组
ones_arr = np.ones((2, 3)) # 创建 2x3 的全1数组
empty_arr = np.empty((2, 2)) # 创建未初始化的数组(内容随机)
range_arr = np.arange(0, 10, 2) # 类似 range(), 创建 [0, 2, 4, 6, 8]
linspace_arr = np.linspace(0, 1, 5) # 在0到1之间创建5个等间隔的数 [0., 0.25, 0.5, 0.75, 1.]# 创建随机数组
random_arr = np.random.rand(3, 2) # 创建 3x2 的数组,元素来自[0,1)的均匀分布
randn_arr = np.random.randn(1000) # 创建1000个符合标准正态分布的随机数
3.3数组的属性
arr = np.array([[1, 2, 3], [4, 5, 6]])print(arr.ndim) # 数组的维数 (秩): 2
print(arr.shape) # 数组的维度 (行数, 列数): (2, 3)
print(arr.size) # 数组的元素总数: 6
print(arr.dtype) # 数组中元素的数据类型: int64 (取决于系统)
3.4切片功能
arr = np.array([[1, 2, 3, 4],[5, 6, 7, 8],[9, 10, 11, 12]])# 基础索引
print(arr[0, 1]) # 获取第0行第1列的元素: 2# 切片 (支持负索引和步长)
print(arr[:2, 1:3]) # 前两行,第1到2列:# [[2, 3],# [6, 7]]# 布尔索引 (非常强大!)
mask = arr > 5
print(mask) # 布尔数组: [[False False False False],# [False True True True],# [ True True True True]]
print(arr[mask]) # 获取所有大于5的元素: [ 6 7 8 9 10 11 12]# 花式索引 (使用整数数组进行索引)
rows = np.array([0, 2])
cols = np.array([1, 3])
print(arr[rows, cols]) # 获取(0,1)和(2,3)位置上的元素: [ 2 12]
3.5数组计算
a = np.array([1, 2, 3])
b = np.array([4, 5, 6])# 元素级运算
print(a + b) # [5 7 9]
print(a * b) # [4 10 18] (逐元素相乘,不是矩阵乘法!)
print(a ** 2) # [1 4 9]
print(np.sin(a)) # 对每个元素求正弦# 矩阵乘法 (使用 @ 运算符或 .dot() 方法)
x = np.array([[1, 2], [3, 4]])
y = np.array([[5, 6], [7, 8]])
print(x @ y) # 矩阵乘法: [[19 22],# [43 50]]
print(x.dot(y)) # 同上# 聚合函数 (对整组数据进行计算)
arr = np.array([1, 2, 3, 4, 5])
print(arr.sum()) # 总和: 15
print(arr.mean()) # 平均值: 3.0
print(arr.std()) # 标准差
print(arr.min()) # 最小值: 1
print(arr.max()) # 最大值: 5
print(arr.argmax()) # 最大值的索引: 4
4总结
完,以上就是python中常用的一些容器!