字典(Dictionary)是Python中最强大的内置数据类型之一,它采用键值对(key-value)的存储方式,提供了近乎常数时间复杂度的数据查询能力。与列表和元组不同,字典中的元素是通过键来访问的,而不是通过偏移量。
字典的典型特征包括:
python复制# 字典创建示例
empty_dict = {}
student = {'name': 'Alice', 'age': 20, 'courses': ['Math', 'Physics']}
注意:字典键必须是不可变类型(如字符串、数字、元组),而值可以是任意Python对象
创建字典的多种方式:
python复制# 直接赋值创建
person = {'name': 'Bob', 'age': 25}
# 使用dict构造函数
person = dict(name='Bob', age=25)
# 从键值对序列创建
person = dict([('name', 'Bob'), ('age', 25)])
# 字典推导式
squares = {x: x*x for x in range(5)}
访问元素的正确姿势:
python复制# 基本访问方式
name = person['name'] # 键不存在会引发KeyError
# 安全访问方式
age = person.get('age') # 返回None如果键不存在
age = person.get('age', 0) # 提供默认值
# 检查键是否存在
if 'name' in person:
print(person['name'])
更新字典的多种方法:
python复制# 直接赋值更新
person['age'] = 26
# 批量更新
person.update({'age': 26, 'gender': 'male'})
# 合并字典(Python 3.9+)
new_person = person | {'city': 'New York'}
字典视图对象:
python复制keys = person.keys() # 键视图
values = person.values() # 值视图
items = person.items() # 键值对视图
# 视图是动态的,会反映字典的变化
person['email'] = 'bob@example.com'
print('email' in keys) # True
字典解包操作:
python复制def greet(name, age):
print(f"Hello {name}, you are {age} years old")
greet(**person) # 等同于 greet(name='Bob', age=25)
字典排序技巧:
python复制# 按键排序
sorted_by_key = dict(sorted(person.items()))
# 按值排序
sorted_by_value = dict(sorted(person.items(), key=lambda item: item[1]))
Python字典基于哈希表实现,其平均时间复杂度为O(1)。了解其内部机制有助于编写高效代码:
python复制# 查看对象哈希值
print(hash('name')) # 输出一个整数
重要提示:自定义对象作为键时,必须正确实现__hash__和__eq__方法
使用__slots__减少内存占用:
python复制class Point:
__slots__ = ['x', 'y'] # 固定属性列表
def __init__(self, x, y):
self.x = x
self.y = y
字典压缩存储:
python复制# 对于值相同的字典,可以使用共享键
keys = ['name', 'age', 'gender']
people = [
dict(zip(keys, ['Alice', 20, 'female'])),
dict(zip(keys, ['Bob', 25, 'male']))
]
python复制class Config:
def __init__(self):
self._data = {}
def load(self, filepath):
with open(filepath) as f:
self._data.update(json.load(f))
def get(self, key, default=None):
return self._data.get(key, default)
# 使用示例
config = Config()
config.load('settings.json')
db_host = config.get('database.host', 'localhost')
python复制from collections import defaultdict
def count_words(text):
word_counts = defaultdict(int)
for word in text.split():
word_counts[word.lower()] += 1
return word_counts
# 更简洁的Counter实现
from collections import Counter
word_counts = Counter(text.lower().split())
python复制def transform_data(input_data, mapping_rules):
output = {}
for output_key, (input_key, transform_fn) in mapping_rules.items():
if input_key in input_data:
output[output_key] = transform_fn(input_data[input_key])
return output
# 使用示例
data = {'first_name': 'John', 'last_name': 'Doe', 'age': '30'}
rules = {
'full_name': ('first_name', lambda x: f"{x} Doe"),
'age': ('age', int)
}
transformed = transform_data(data, rules)
问题1:可变对象作为键
python复制# 错误示例
d = {['a', 'b']: 'value'} # TypeError: unhashable type: 'list'
# 解决方案:使用元组代替
d = {('a', 'b'): 'value'}
问题2:遍历时修改字典
python复制# 错误示例
d = {'a': 1, 'b': 2}
for k in d:
d[k*2] = d[k] # RuntimeError: dictionary changed size during iteration
# 解决方案:先复制键
for k in list(d.keys()):
d[k*2] = d[k]
Q:何时该使用字典而非列表?
A:当需要:
Q:超大字典如何优化内存?
A:考虑:
zict实现磁盘存储| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| KeyError | 键不存在 | 使用get()方法或提前检查 |
| 性能下降 | 哈希冲突严重 | 检查键的哈希质量,考虑使用更分散的键 |
| 内存占用高 | 大量小字典 | 考虑使用元组或namedtuple |
| 顺序不一致 | Python版本<3.7 | 升级Python或使用OrderedDict |
链式字典(ChainMap):
python复制from collections import ChainMap
defaults = {'color': 'red', 'size': 'medium'}
user_prefs = {'size': 'large'}
combined = ChainMap(user_prefs, defaults)
print(combined['color']) # 输出'red'
只读字典(MappingProxyType):
python复制from types import MappingProxyType
writable = {'a': 1, 'b': 2}
read_only = MappingProxyType(writable)
read_only['a'] # 可以访问
read_only['c'] = 3 # TypeError
动态属性访问:
python复制class DictProxy:
def __init__(self, data):
self._data = data
def __getattr__(self, name):
try:
return self._data[name]
except KeyError:
raise AttributeError(name)
person = DictProxy({'name': 'Alice'})
print(person.name) # 输出'Alice'
字典协议实现:
python复制class CustomDict:
def __init__(self):
self._data = {}
def __getitem__(self, key):
return self._data[key]
def __setitem__(self, key, value):
self._data[key] = value.upper()
def __iter__(self):
return iter(self._data)
d = CustomDict()
d['name'] = 'Alice'
print(d['name']) # 输出'ALICE'
python复制from typing import Dict, TypedDict
class Person(TypedDict):
name: str
age: int
def process_data(data: Dict[str, Person]) -> None:
...
python复制def clean_dict(data: dict, schema: dict) -> dict:
"""
schema示例: {'name': {'type': str, 'required': True}}
"""
result = {}
for key, config in schema.items():
if config['required'] and key not in data:
raise ValueError(f"Missing required key: {key}")
if key in data and isinstance(data[key], config['type']):
result[key] = data[key]
return result
python复制import time
from functools import wraps
def profile_dict_ops(func):
@wraps(func)
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
elapsed = time.perf_counter() - start
print(f"{func.__name__} executed in {elapsed:.6f}s")
return result
return wrapper
@profile_dict_ops
def process_large_dict(data):
return {k: v*2 for k, v in data.items()}