所有文章 > API术语解释 > Python字典(dict)完全指南
Python字典(dict)完全指南

Python字典(dict)完全指南

1. 字典的基本概念

字典(dict)是Python中的一种可变映射类型,它使用键值对(key-value pair)的形式来存储数据。字典的特点包括:

  • 键(key)必须是不可变类型(如字符串、数字或元组)
  • 值(value)可以是任意Python对象
  • 键必须是唯一的
  • Python 3.7+版本中字典会保持插入顺序

2. 字典的创建方法

# 1. 使用花括号创建
# 最常用的创建方式,直观且灵活
# 可以在创建时直接初始化多个键值对
# 支持嵌套字典结构
student = {
'name': '张三', # 字符串类型的键值对
'age': 20, # 数字类型的值
'scores': {'语文': 85, '数学': 92} # 嵌套字典
}

# 2. 使用dict()构造函数
# 适用于键名符合变量命名规则的情况
# 代码更简洁,但不支持复杂的键名
info = dict(name='李四', age=22) # 等同于 {'name': '李四', 'age': 22}

# 3. 使用字典推导式
# 适合批量创建有规律的键值对
# 代码简洁,可读性好
squares = {x: x**2for x in range(5)} # 创建数字及其平方的映射

# 4. 使用dict.fromkeys()创建具有默认值的字典
# 适合初始化具有相同默认值的多个键
# 注意:所有键会共享同一个默认值对象
keys = ['a', 'b', 'c']
default_dict = dict.fromkeys(keys, 0) # 创建所有键对应值为0的字典

3. 字典的基本操作

3.1 访问和修改元素

# 创建示例字典
user = {
'name': '张三',
'age': 25,
'email': 'zhangsan@example.com'
}

# 1. 访问元素的多种方式
# 使用方括号访问 - 最直接的方式,但键不存在时会抛出KeyError
print(user['name']) # 输出:张三

# 使用get()方法访问 - 推荐的安全访问方式
# 第一个参数是键名,第二个参数是键不存在时的默认值
age = user.get('age', 0) # 如果'age'键不存在,返回默认值0
phone = user.get('phone', '未设置') # 获取可能不存在的键

# 2. 修改元素
# 直接赋值修改已存在的键值对
user['age'] = 26# 修改已存在的键的值

# 3. 添加新元素
# 使用新键直接赋值
user['phone'] = '13800138000'# 添加新的键值对

# 4. 删除元素的多种方式
# 使用del语句 - 删除指定键值对,键不存在会抛出KeyError
del user['email']

# 使用pop()方法 - 删除并返回值,可以提供默认值
phone = user.pop('phone', None) # 如果键不存在,返回None

# 使用popitem()方法 - 删除并返回最后一个键值对
last_item = user.popitem() # 返回元组(key, value)

3.2 常用字典方法

# 1. 获取字典信息的方法
# keys() - 获取所有键
# 返回一个动态视图对象,会随字典变化而更新
keys = user.keys() # 获取所有键的视图
key_list = list(keys) # 转换为列表

# values() - 获取所有值
# 同样返回动态视图对象
values = user.values() # 获取所有值的视图
value_list = list(values) # 转换为列表

# items() - 获取所有键值对
# 返回(key, value)元组的视图对象
items = user.items() # 获取所有键值对的视图
for key, value in items: # 常用于遍历字典
print(f"{key}: {value}")

# 2. 修改字典的方法
# update() - 批量更新字典
# 可以使用另一个字典或键值对序列更新
user.update({'city': '北京', 'age': 27}) # 使用字典更新
user.update(zip(['hobby', 'job'], ['读书', '程序员'])) # 使用键值对序列更新

# setdefault() - 设置默认值
# 如果键不存在,则设置默认值并返回
# 如果键存在,则返回现有值
email = user.setdefault('email', 'default@example.com')

# 3. 清理字典的方法
# clear() - 清空字典
# 删除所有键值对
user.clear() # 字典变为空字典 {}

# copy() - 创建字典的浅拷贝
# 创建新字典,但嵌套的可变对象仍然共享引用
user_copy = user.copy()

4. 字典的高级应用

4.1 嵌套字典

# 复杂的嵌套字典示例
# 展示了多层嵌套的数据结构
# 适用于表示层级关系的数据
school = {
'class_1': {
'teacher': '王老师',
'students': {
'001': {
'name': '张三',
'scores': {'语文': 85, '数学': 92}
},
'002': {
'name': '李四',
'scores': {'语文': 89, '数学': 94}
}
}
}
}

# 访问嵌套数据的方法
# 1. 使用多级键访问
print(school['class_1']['students']['001']['scores']['语文']) # 输出:85

# 2. 使用get()方法的安全访问
# 避免键不存在时的异常
score = school.get('class_1', {}).get('students', {}).get('001', {}).get('scores', {}).get('语文', 0)

# 3. 修改嵌套数据
# 逐层创建或修改数据
school['class_2'] = {} # 创建新的班级
school['class_2']['teacher'] = '李老师'# 添加教师信息
school['class_2']['students'] = {} # 初始化学生字典

4.2 字典推导式高级用法

# 1. 条件字典推导式
# 根据条件筛选键值对
scores = {'张三': 85, '李四': 92, '王五': 78, '赵六': 95}
# 筛选成绩大于等于85分的学生
pass_students = {name: score for name, score in scores.items() if score >= 85}

# 2. 转换值的字典推导式
# 对原字典的值进行转换
grades = {name: 'A'if score >= 90else'B'if score >= 80else'C'
for name, score in scores.items()}

# 3. 嵌套字典推导式
# 创建复杂的嵌套字典结构
# 生成乘法表字典
matrix = {i: {j: i*j for j in range(3)} for i in range(3)}
# 结果示例:{0: {0: 0, 1: 0, 2: 0}, 1: {0: 0, 1: 1, 2: 2}, 2: {0: 0, 1: 2, 2: 4}}

5. 使用字典格式化字符串

5.1 基本格式化

# 1. 使用%操作符(旧式格式化)
# 语法简单,但功能有限
info = {'name': '张三', 'age': 25}
print('%(name)s is %(age)d years old' % info)

# 2. 使用str.format()方法
# 更灵活,支持更多格式化选项
print('{name} is {age} years old'.format(**info))

# 3. 使用f-string(推荐,Python 3.6+)
# 最简洁、直观的方式
# 支持直接使用表达式
print(f"{info['name']} is {info['age']} years old")

5.2 高级格式化技巧

# 1. 对齐和填充
data = {'name': '张三', 'score': 95.5}
# 左对齐,宽度10
# 右对齐,宽度8,保留2位小数
print(f"{data['name']:<10}|{data['score']:>8.2f}")

# 2. 使用字典进行复杂模板格式化
# 适用于生成报告、配置文件等
template = '''
学生信息:
姓名:{name}
年龄:{age}
成绩:{score:.1f}
'''

student = {
'name': '张三',
'age': 18,
'score': 95.6
}

print(template.format(**student))

6. 字典性能优化建议

6.1 字典创建优化

# 1. 预分配空间
# 当知道字典大小时,使用dict.fromkeys()预分配空间
# 避免频繁的内存重新分配
keys = range(10000)
optimized_dict = dict.fromkeys(keys) # 预分配10000个空间

# 对比:动态增长的字典
unoptimized_dict = {}
for i in range(10000):
unoptimized_dict[i] = None# 会导致多次内存重新分配

# 2. 使用字典推导式替代循环
# 字典推导式通常比循环创建字典更快
squares_comprehension = {x: x**2for x in range(1000)} # 更快

squares_loop = {}
for x in range(1000): # 更慢
squares_loop[x] = x**2

6.2 访问优化

# 1. 使用get()方法的最佳实践
# 当确定键存在时,使用方括号访问更快
user = {'name': '张三', 'age': 25}

# 快:确定键存在时使用方括号
name = user['name']

# 慢:不必要的get()调用
name = user.get('name')

# 正确使用场景:键可能不存在时使用get()
phone = user.get('phone', '未设置')

# 2. 避免重复访问
# 对频繁访问的值进行本地缓存
def process_user_slow(user):
# 差:重复访问字典
print(f"姓名:{user['name']}")
print(f"年龄:{user['age']}")
if user['age'] > 18:
print(f"{user['name']}是成年人")

def process_user_fast(user):
# 好:将频繁使用的值缓存到局部变量
name = user['name']
age = user['age']
print(f"姓名:{name}")
print(f"年龄:{age}")
if age > 18:
print(f"{name}是成年人")

6.3 更新优化

# 1. 批量更新优化
# 使用update()方法进行批量更新,而不是多次单独更新
user = {'name': '张三'}

# 差:多次单独更新
user['age'] = 25
user['city'] = '北京'
user['email'] = 'zhangsan@example.com'

# 好:使用update()批量更新
user.update({
'age': 25,
'city': '北京',
'email': 'zhangsan@example.com'
})

# 2. 避免频繁的增删操作
# 如果需要频繁增删,考虑使用collections.defaultdict或set
from collections import defaultdict

# 统计单词频率的例子
# 使用defaultdict避免键检查
word_counts = defaultdict(int)
text = "the quick brown fox jumps over the lazy dog"
for word in text.split():
word_counts[word] += 1# 无需检查键是否存在

6.4 内存优化

# 1. 使用__slots__优化类字典
# 当类属性固定时,使用__slots__可以显著减少内存使用
class UserNormal:
def __init__(self, name, age):
self.name = name
self.age = age

class UserOptimized:
__slots__ = ['name', 'age'] # 显著减少内存使用
def __init__(self, name, age):
self.name = name
self.age = age

# 2. 及时清理不需要的数据
# 使用clear()方法而不是重新赋值
large_dict = {i: i**2for i in range(10000)}

# 差:直接赋值新字典
large_dict = {} # 旧字典仍在内存中,等待垃圾回收

# 好:使用clear()清理
large_dict.clear() # 立即释放内存

# 3. 使用弱引用字典
# 当需要缓存对象但不阻止它们被垃圾回收时
from weakref import WeakKeyDictionary

class Cache:
def __init__(self):
# 当键对象没有其他引用时,自动从字典中删除
self.data = WeakKeyDictionary()

6.5 性能测试示例

import timeit
import sys

# 1. 字典创建性能对比
def test_dict_creation():
# 测试不同创建方法的性能
setup = """size = 1000"""

test1 = """dict_comp = {x: x**2 for x in range(size)}"""
test2 = """dict_loop = {}
for x in range(size):
dict_loop[x] = x**2"""

time1 = timeit.timeit(test1, setup, number=1000)
time2 = timeit.timeit(test2, setup, number=1000)

print(f"字典推导式: {time1:.4f}秒")
print(f"循环创建: {time2:.4f}秒")

# 2. 内存使用对比
def compare_memory_usage():
# 测试普通类和使用__slots__的类的内存占用
normal_users = [UserNormal(f"user{i}", i) for i in range(1000)]
optimized_users = [UserOptimized(f"user{i}", i) for i in range(1000)]

normal_size = sys.getsizeof(normal_users[0]) * len(normal_users)
optimized_size = sys.getsizeof(optimized_users[0]) * len(optimized_users)

print(f"普通类对象占用内存: {normal_size/1024:.2f}KB")
print(f"优化类对象占用内存: {optimized_size/1024:.2f}KB")

if __name__ == '__main__':
print("性能测试结果:")
test_dict_creation()
print("\n内存使用对比:")
compare_memory_usage()

6.6 最佳实践总结

  1. 创建优化
  • 预知大小时使用dict.fromkeys()预分配空间
  • 优先使用字典推导式而不是循环创建
  • 批量数据优先使用dict()构造函数
  1. 访问优化
  • 确定键存在时使用方括号访问
  • 键可能不存在时才使用get()
  • 频繁访问的值存储在局部变量中
  1. 更新优化
  • 多个键值对更新时使用update()
  • 频繁增删操作考虑使用defaultdict
  • 避免频繁的单键更新操作
  1. 内存优化
  • 属性固定的类使用__slots__
  • 及时使用clear()释放内存
  • 合理使用弱引用字典
  • 避免存储重复数据
  1. 其他建议
  • 使用适当的数据结构(如set代替值为None的字典)
  • 定期进行性能分析和内存监控
  • 在性能关键场景进行基准测试
#你可能也喜欢这些API文章!