Python字典详解
字典(Dictionary)是Python中最重要的数据结构之一,用于存储键值对(key-value pairs)。Python字典提供了高效的键值查找机制,是日常开发中最常用的数据结构之一。本文将详细介绍Python字典的特性、操作和最佳实践。
一、字典概述
1. 什么是字典?
字典是Python中的一种无序、可变的映射类型(Mapping Type),用于存储键值对集合。每个键值对之间用逗号,分隔,整个字典用花括号{}包裹。
2. 字典的特点
- 无序性:Python 3.7之前字典是无序的,Python 3.7及以后版本字典保持插入顺序
- 可变性:字典创建后可以修改其内容(添加、删除、修改键值对)
- 映射关系:通过键(key)映射到对应的值(value)
- 键的唯一性:字典中的键必须唯一
- 键的可哈希性:字典的键必须是可哈希的(不可变类型,如字符串、数字、元组)
- 值的任意性:字典的值可以是任意类型(包括可变类型,如列表、字典)
3. 字典的表示
字典使用花括号{}表示,键值对之间用冒号:分隔:
# 字典示例
person = {"name": "张三", "age": 30, "city": "北京"}
# 键可以是不同类型
mixed = {1: "整数键", "字符串键": 2, (1, 2): "元组键"}
# 空字典
empty_dict = {}
二、字典的创建
1. 基本创建方法
使用花括号{}直接创建字典:
# 基本创建方法示例
# 创建空字典
empty = {}
# 创建包含键值对的字典
person = {"name": "李四", "age": 25, "email": "lisi@example.com"}
# 使用不同类型的键
mixed = {
1: "数字键",
"字符串键": "字符串值",
(1, 2): "元组键",
True: "布尔键"
}
print(empty) # {}
print(person) # {'name': '李四', 'age': 25, 'email': 'lisi@example.com'}
print(mixed) # {1: '布尔键', '字符串键': '字符串值', (1, 2): '元组键'}(注意True和1在字典中视为同一个键)
2. 使用dict()函数创建
dict()函数可以从不同的数据源创建字典:
# 使用dict()函数创建字典示例
# 从关键字参数创建
d = dict(name="王五", age=35, city="上海")
print(d) # {'name': '王五', 'age': 35, 'city': '上海'}
# 从键值对序列创建
pairs = [("name", "赵六"), ("age", 40), ("city", "广州")]
d = dict(pairs)
print(d) # {'name': '赵六', 'age': 40, 'city': '广州'}
# 从两个列表创建(使用zip()函数)
keys = ["name", "age", "city"]
values = ["钱七", 45, "深圳"]
d = dict(zip(keys, values))
print(d) # {'name': '钱七', 'age': 45, 'city': '深圳'}
# 从另一个字典创建(浅拷贝)
original = {"name": "孙八", "age": 50}
d = dict(original)
print(d) # {'name': '孙八', 'age': 50}
print(d is original) # False(创建了新字典)
3. 使用字典推导式创建
字典推导式是一种简洁创建字典的方法,语法为{key_expression: value_expression for item in iterable if condition}:
# 使用字典推导式创建字典示例
# 基本字典推导式
numbers = [1, 2, 3, 4, 5]
squares = {num: num ** 2 for num in numbers}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 带有条件的字典推导式
even_squares = {num: num ** 2 for num in numbers if num % 2 == 0}
print(even_squares) # {2: 4, 4: 16}
# 使用两个列表创建
a = ["name", "age", "city"]
b = ["周九", 55, "杭州"]
person = {k: v for k, v in zip(a, b)}
print(person) # {'name': '周九', 'age': 55, 'city': '杭州'}
# 转换字符串为字符计数字典
word = "hello"
char_count = {char: word.count(char) for char in word}
print(char_count) # {'h': 1, 'e': 1, 'l': 2, 'o': 1}
4. 使用fromkeys()方法创建
fromkeys()方法可以从序列创建字典,所有键的初始值相同:
# 使用fromkeys()方法创建字典示例
# 创建所有键值为None的字典
keys = ["name", "age", "city"]
d = dict.fromkeys(keys)
print(d) # {'name': None, 'age': None, 'city': None}
# 创建所有键值为相同值的字典
d = dict.fromkeys(keys, "默认值")
print(d) # {'name': '默认值', 'age': '默认值', 'city': '默认值'}
# 注意:如果默认值是可变对象,所有键会共享同一个对象
keys = ["a", "b", "c"]
d = dict.fromkeys(keys, [])
d["a"].append(1)
print(d) # {'a': [1], 'b': [1], 'c': [1]}(所有键共享同一个列表)
三、字典的基本操作
1. 访问字典元素
可以通过键来访问字典中的值:
# 访问字典元素示例
person = {"name": "吴十", "age": 60, "city": "南京"}
# 使用方括号访问
print(person["name"]) # 吴十
print(person["age"]) # 60
# 访问不存在的键会报错
try:
print(person["email"])
except KeyError as e:
print(f"错误:{e}") # 错误:'email'
# 使用get()方法访问(更安全)
print(person.get("name")) # 吴十
print(person.get("email")) # None(键不存在时返回None)
print(person.get("email", "默认邮箱")) # 默认邮箱(键不存在时返回指定的默认值)
2. 修改字典元素
可以通过键来修改字典中的值:
# 修改字典元素示例
person = {"name": "郑十一", "age": 65, "city": "成都"}
# 修改现有键的值
person["age"] = 70
print(person) # {'name': '郑十一', 'age': 70, 'city': '成都'}
# 使用update()方法修改多个键值对
person.update({"age": 75, "city": "重庆"})
print(person) # {'name': '郑十一', 'age': 75, 'city': '重庆'}
# 使用关键字参数修改
person.update(age=80, city="西安")
print(person) # {'name': '郑十一', 'age': 80, 'city': '西安'}
3. 添加字典元素
可以通过赋值或update()方法添加新的键值对:
# 添加字典元素示例
person = {"name": "王十二", "age": 30}
# 添加新的键值对
person["city"] = "武汉"
print(person) # {'name': '王十二', 'age': 30, 'city': '武汉'}
# 使用update()方法添加多个键值对
person.update({"email": "wang12@example.com", "phone": "13800138000"})
print(person) # {'name': '王十二', 'age': 30, 'city': '武汉', 'email': 'wang12@example.com', 'phone': '13800138000'}
# 使用关键字参数添加
person.update(gender="男")
print(person) # {'name': '王十二', 'age': 30, 'city': '武汉', 'email': 'wang12@example.com', 'phone': '13800138000', 'gender': '男'}
4. 删除字典元素
可以使用多种方法删除字典中的元素:
# 删除字典元素示例
person = {"name": "赵十三", "age": 35, "city": "长沙", "email": "zhao13@example.com"}
# 使用del语句删除
print(person) # {'name': '赵十三', 'age': 35, 'city': '长沙', 'email': 'zhao13@example.com'}
del person["city"]
print(person) # {'name': '赵十三', 'age': 35, 'email': 'zhao13@example.com'}
# 删除不存在的键会报错
try:
del person["phone"]
except KeyError as e:
print(f"错误:{e}") # 错误:'phone'
# 使用pop()方法删除(返回被删除的值)
email = person.pop("email")
print(email) # zhao13@example.com
print(person) # {'name': '赵十三', 'age': 35}
# pop()方法可以指定默认值(键不存在时返回默认值)
phone = person.pop("phone", "默认电话")
print(phone) # 默认电话
print(person) # {'name': '赵十三', 'age': 35}
# 使用popitem()方法删除最后一个键值对(Python 3.7+)
pair = person.popitem()
print(pair) # ('age', 35)
print(person) # {'name': '赵十三'}
# 使用clear()方法清空字典
person.clear()
print(person) # {}
5. 字典的其他基本操作
# 字典的其他基本操作示例
person = {"name": "钱十四", "age": 40, "city": "青岛"}
# 获取字典的长度(键值对数量)
print(len(person)) # 3
# 检查键是否存在
print("name" in person) # True
print("email" not in person) # True
# 字典的复制(浅拷贝)
person2 = person.copy()
print(person2) # {'name': '钱十四', 'age': 40, 'city': '青岛'}
print(person2 is person) # False
# 字典的合并
person3 = {"email": "qian14@example.com", "phone": "13900139000"}
merged = {**person, **person3}
print(merged) # {'name': '钱十四', 'age': 40, 'city': '青岛', 'email': 'qian14@example.com', 'phone': '13900139000'}
# Python 3.9+支持使用|运算符合并
# merged = person | person3
四、字典的常用方法
Python字典提供了丰富的方法用于操作字典:
1. keys()、values()和items()
这些方法用于获取字典的键、值和键值对:
# keys()、values()和items()方法示例
person = {"name": "孙十五", "age": 45, "city": "济南"}
# 获取所有键
keys = person.keys()
print(keys) # dict_keys(['name', 'age', 'city'])
print(list(keys)) # ['name', 'age', 'city']
# 获取所有值
values = person.values()
print(values) # dict_values(['孙十五', 45, '济南'])
print(list(values)) # ['孙十五', 45, '济南']
# 获取所有键值对
items = person.items()
print(items) # dict_items([('name', '孙十五'), ('age', 45), ('city', '济南')])
print(list(items)) # [('name', '孙十五'), ('age', 45), ('city', '济南')]
# 遍历字典的键
for key in person.keys():
print(key)
# 遍历字典的值
for value in person.values():
print(value)
# 遍历字典的键值对
for key, value in person.items():
print(f"{key}: {value}")
2. get()方法
get()方法用于获取指定键的值,如果键不存在则返回默认值:
# get()方法示例
person = {"name": "周十六", "age": 50, "city": "福州"}
# 获取存在的键
print(person.get("name")) # 周十六
# 获取不存在的键(返回None)
print(person.get("email")) # None
# 获取不存在的键(返回默认值)
print(person.get("email", "no email")) # no email
# 获取不存在的键(返回默认值)
print(person.get("phone", 1234567890)) # 1234567890
3. update()方法
update()方法用于更新字典中的键值对:
# update()方法示例
person = {"name": "吴十七", "age": 55, "city": "厦门"}
# 使用字典更新
person.update({"age": 60, "email": "wu17@example.com"})
print(person) # {'name': '吴十七', 'age': 60, 'city': '厦门', 'email': 'wu17@example.com'}
# 使用关键字参数更新
person.update(age=65, phone="13800138000")
print(person) # {'name': '吴十七', 'age': 65, 'city': '厦门', 'email': 'wu17@example.com', 'phone': '13800138000'}
# 使用键值对序列更新
person.update([("city", "南宁"), ("gender", "男")])
print(person) # {'name': '吴十七', 'age': 65, 'city': '南宁', 'email': 'wu17@example.com', 'phone': '13800138000', 'gender': '男'}
4. setdefault()方法
setdefault()方法用于获取指定键的值,如果键不存在则添加该键并设置默认值:
# setdefault()方法示例
person = {"name": "郑十八", "age": 70, "city": "昆明"}
# 获取存在的键
name = person.setdefault("name", "默认姓名")
print(name) # 郑十八
print(person) # {'name': '郑十八', 'age': 70, 'city': '昆明'}
# 获取不存在的键(添加键并设置默认值)
email = person.setdefault("email", "默认邮箱")
print(email) # 默认邮箱
print(person) # {'name': '郑十八', 'age': 70, 'city': '昆明', 'email': '默认邮箱'}
# 获取不存在的键(默认值为None)
phone = person.setdefault("phone")
print(phone) # None
print(person) # {'name': '郑十八', 'age': 70, 'city': '昆明', 'email': '默认邮箱', 'phone': None}
5. 其他方法
# 其他方法示例
# 创建字典
d1 = {"a": 1, "b": 2, "c": 3}
d2 = {"c": 4, "d": 5, "e": 6}
# 使用copy()方法复制字典
d3 = d1.copy()
print(d3) # {'a': 1, 'b': 2, 'c': 3}
# 使用clear()方法清空字典
d3.clear()
print(d3) # {}
# 使用pop()方法删除键值对
value = d1.pop("a")
print(value) # 1
print(d1) # {'b': 2, 'c': 3}
# 使用popitem()方法删除最后一个键值对
pair = d1.popitem()
print(pair) # ('c', 3)
print(d1) # {'b': 2}
五、字典的高级操作
1. 嵌套字典
字典中可以包含其他字典,形成嵌套字典:
# 嵌套字典示例
# 创建嵌套字典
student = {
"name": "王十九",
"age": 18,
"scores": {
"数学": 95,
"语文": 90,
"英语": 85
},
"address": {
"city": "贵阳",
"street": "解放路",
"zipcode": "550000"
}
}
# 访问嵌套字典中的元素
print(student["name"]) # 王十九
print(student["scores"]["数学"]) # 95
print(student["address"]["city"]) # 贵阳
# 修改嵌套字典中的元素
student["scores"]["数学"] = 100
print(student["scores"]["数学"]) # 100
# 添加嵌套字典中的元素
student["scores"]["物理"] = 92
print(student["scores"]) # {'数学': 100, '语文': 90, '英语': 85, '物理': 92}
# 遍历嵌套字典
for subject, score in student["scores"].items():
print(f"{subject}: {score}")
# 遍历整个嵌套字典
for key, value in student.items():
if isinstance(value, dict):
print(f"{key}:")
for k, v in value.items():
print(f" {k}: {v}")
else:
print(f"{key}: {value}")
2. 字典推导式
字典推导式是一种简洁创建字典的方法:
# 字典推导式示例
# 基本字典推导式
numbers = [1, 2, 3, 4, 5]
squares = {num: num ** 2 for num in numbers}
print(squares) # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 带有条件的字典推导式
even_squares = {num: num ** 2 for num in numbers if num % 2 == 0}
print(even_squares) # {2: 4, 4: 16}
# 使用两个列表创建
keys = ["name", "age", "city"]
values = ["赵二十", 20, "拉萨"]
person = {k: v for k, v in zip(keys, values)}
print(person) # {'name': '赵二十', 'age': 20, 'city': '拉萨'}
# 转换字符串为字符计数字典
word = "python"
char_count = {char: word.count(char) for char in word}
print(char_count) # {'p': 1, 'y': 1, 't': 1, 'h': 1, 'o': 1, 'n': 1}
# 反转字典键值对
original = {"a": 1, "b": 2, "c": 3}
reversed_dict = {v: k for k, v in original.items()}
print(reversed_dict) # {1: 'a', 2: 'b', 3: 'c'}
# 注意:如果原字典的值不唯一,反转后会丢失一些键值对
original = {"a": 1, "b": 2, "c": 1}
reversed_dict = {v: k for k, v in original.items()}
print(reversed_dict) # {1: 'c', 2: 'b'}('a'键丢失)
3. 字典的排序
可以使用sorted()函数对字典进行排序:
# 字典的排序示例
# 创建字典
scores = {"数学": 95, "语文": 90, "英语": 85, "物理": 92, "化学": 88}
# 按键排序
for key in sorted(scores.keys()):
print(f"{key}: {scores[key]}")
# 按键排序并创建新字典
keys_sorted = {k: scores[k] for k in sorted(scores.keys())}
print(keys_sorted) # {'化学': 88, '物理': 92, '数学': 95, '英语': 85, '语文': 90}
# 按值排序
for key, value in sorted(scores.items(), key=lambda x: x[1]):
print(f"{key}: {value}")
# 按值降序排序
for key, value in sorted(scores.items(), key=lambda x: x[1], reverse=True):
print(f"{key}: {value}")
# 按值的绝对值排序
scores = {"a": -5, "b": 3, "c": -1, "d": 2}
for key, value in sorted(scores.items(), key=lambda x: abs(x[1])):
print(f"{key}: {value}")
4. 字典的合并
Python提供了多种合并字典的方法:
# 字典的合并示例
dict1 = {"a": 1, "b": 2}
dict2 = {"b": 3, "c": 4}
# 方法1:使用update()方法(会修改原字典)
dict1_copy = dict1.copy()
dict1_copy.update(dict2)
print(dict1_copy) # {'a': 1, 'b': 3, 'c': 4}
# 方法2:使用**运算符(Python 3.5+)
merged = {**dict1, **dict2}
print(merged) # {'a': 1, 'b': 3, 'c': 4}
# 方法3:使用字典推导式
merged = {k: v for d in [dict1, dict2] for k, v in d.items()}
print(merged) # {'a': 1, 'b': 3, 'c': 4}
# 方法4:使用chain()函数(from itertools)
from itertools import chain
merged = dict(chain(dict1.items(), dict2.items()))
print(merged) # {'a': 1, 'b': 3, 'c': 4}
# 方法5:使用|运算符(Python 3.9+)
# merged = dict1 | dict2
# print(merged) # {'a': 1, 'b': 3, 'c': 4}
5. 字典的键值对转换
可以将字典转换为其他数据结构:
# 字典的键值对转换示例
person = {"name": "钱二十一", "age": 21, "city": "银川"}
# 转换为列表
keys_list = list(person.keys())
values_list = list(person.values())
items_list = list(person.items())
print(keys_list) # ['name', 'age', 'city']
print(values_list) # ['钱二十一', 21, '银川']
print(items_list) # [('name', '钱二十一'), ('age', 21), ('city', '银川')]
# 转换为元组
keys_tuple = tuple(person.keys())
values_tuple = tuple(person.values())
items_tuple = tuple(person.items())
print(keys_tuple) # ('name', 'age', 'city')
print(values_tuple) # ('钱二十一', 21, '银川')
print(items_tuple) # (('name', '钱二十一'), ('age', 21), ('city', '银川'))
# 转换为集合
keys_set = set(person.keys())
values_set = set(person.values())
print(keys_set) # {'name', 'age', 'city'}
print(values_set) # {'钱二十一', 21, '银川'}
六、字典的性能分析
1. 时间复杂度
字典的核心优势是高效的键值查找,主要操作的时间复杂度如下:
| 操作 | 时间复杂度 | 描述 |
|---|---|---|
| 访问元素 | O(1) | 通过键访问值 |
| 修改元素 | O(1) | 通过键修改值 |
| 添加元素 | O(1) | 添加新的键值对 |
| 删除元素 | O(1) | 删除键值对 |
| 成员检查 | O(1) | 检查键是否存在 |
| 获取所有键 | O(n) | 获取字典的所有键 |
| 获取所有值 | O(n) | 获取字典的所有值 |
| 获取所有键值对 | O(n) | 获取字典的所有键值对 |
2. 性能优化建议
- 尽量使用不可变类型作为键(字符串、数字、元组)
- 避免使用可变类型作为键(列表、字典)
- 使用
get()方法而不是[]访问元素(避免KeyError) - 对于频繁查找的场景,字典比列表更高效
- 对于需要保持插入顺序的场景,使用Python 3.7+的字典
3. 字典与列表的性能比较
# 字典与列表的性能比较示例
import time
# 创建大列表和大字典
n = 1000000
my_list = list(range(n))
my_dict = {i: i for i in range(n)}
# 测试列表的查找性能
start = time.time()
for i in range(n):
if i == n - 1:
pass
end = time.time()
print(f"列表查找耗时:{end - start:.6f}秒")
# 测试字典的查找性能
start = time.time()
for i in range(n):
if i in my_dict:
pass
end = time.time()
print(f"字典查找耗时:{end - start:.6f}秒")
七、字典的最佳实践
1. 适用场景
- 需要通过键快速查找值的场景
- 需要存储键值对集合的场景
- 需要表示对象属性的场景
- 需要缓存数据的场景
- 需要存储配置信息的场景
2. 最佳实践
# 最佳实践示例
# 1. 使用有意义的键名
# 不好的做法
user = {"n": "张三", "a": 30, "c": "北京"}
# 好的做法
user = {"name": "张三", "age": 30, "city": "北京"}
# 2. 使用get()方法访问元素(避免KeyError)
# 不好的做法
try:
email = user["email"]
except KeyError:
email = ""
# 好的做法
email = user.get("email", "")
# 3. 使用字典推导式创建字典
# 不好的做法
numbers = [1, 2, 3, 4, 5]
squares = {}
for num in numbers:
squares[num] = num ** 2
# 好的做法
squares = {num: num ** 2 for num in numbers}
# 4. 避免使用可变类型作为键
# 不好的做法
try:
bad_dict = {[1, 2]: "值"}
except TypeError as e:
print(f"错误:{e}") # 错误:unhashable type: 'list'
# 好的做法
good_dict = {(1, 2): "值"} # 使用元组作为键
# 5. 合理使用嵌套字典
# 好的做法
student = {
"name": "李四",
"age": 20,
"scores": {
"数学": 95,
"语文": 90,
"英语": 85
}
}
# 6. 使用zip()函数创建字典
# 好的做法
keys = ["name", "age", "city"]
values = ["王五", 25, "上海"]
person = dict(zip(keys, values))
3. 常见错误
# 常见错误示例
# 错误1:使用可变类型作为键
try:
d = {[1, 2]: "值"}
except TypeError as e:
print(f"错误:{e}") # 错误:unhashable type: 'list'
# 错误2:访问不存在的键
try:
d = {"a": 1, "b": 2}
print(d["c"])
except KeyError as e:
print(f"错误:{e}") # 错误:'c'
# 错误3:修改不可哈希的键
try:
d = {(1, 2): "值"}
d[(1, 2)][0] = 3
except TypeError as e:
print(f"错误:{e}") # 错误:'tuple' object does not support item assignment
# 错误4:混淆字典的键和值
d = {"a": 1, "b": 2}
# 不好的做法
for value in d:
print(value) # 输出键,不是值
# 好的做法
for key in d:
print(d[key]) # 输出值
for value in d.values():
print(value) # 输出值
八、与其他数据结构的比较
| 特性 | 字典 | 列表 | 元组 |
|---|---|---|---|
| 存储方式 | 键值对 | 元素序列 | 元素序列 |
| 访问方式 | 通过键 | 通过索引 | 通过索引 |
| 可变性 | 可变 | 可变 | 不可变 |
| 有序性 | Python 3.7+有序 | 有序 | 有序 |
| 键的唯一性 | 键必须唯一 | 元素可以重复 | 元素可以重复 |
| 可哈希性 | 键必须可哈希 | 不可哈希 | 可哈希 |
| 查找效率 | O(1) | O(n) | O(n) |
| 内存占用 | 较大 | 较小 | 较小 |
| 适用场景 | 键值映射、快速查找 | 有序元素集合、需要频繁修改 | 不可变元素集合、需要作为字典键 |
九、总结
字典是Python中最强大、最灵活的数据结构之一,具有以下特点:
- 高效的键值查找:字典的核心优势是O(1)时间复杂度的键值查找
- 灵活的键值对存储:可以存储任意类型的键值对
- 可变性:可以动态添加、修改、删除键值对
- 丰富的操作方法:提供了大量用于操作字典的方法
- 广泛的应用场景:在日常开发中几乎无处不在
通过掌握Python字典的特性和操作方法,可以编写出更高效、更优雅的代码。在实际开发中,应根据具体需求选择合适的数据结构,充分发挥字典的优势。
发布网站:荣殿教程(zhangrongdian.com)
作者:张荣殿