
图:Python标志
在Python中,列表(List)和字典(Dict)是使用频率最高的两种内置数据结构。它们简洁而强大,能够应对从数据清洗、转换到复杂业务逻辑构建的绝大多数场景。本文将深入探讨这两种数据结构的20个核心技巧,涵盖使用说明、适用场景及清晰的代码示例,帮助你提升编码效率与代码质量。
一、列表(List)的10个核心技巧
列表是一个有序、可变的集合,可以容纳任意类型的元素。
技巧1:列表推导式(List Comprehension)
说明:一种简洁、高效地创建新列表的语法。
场景:数据过滤、转换、生成序列。
示例:
# 生成1到10的平方列表
squares = [x**2 for x in range(1, 11)]
print(squares) # 输出:[1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 过滤出偶数
numbers = [1, 2, 3, 4, 5, 6]
evens = [n for n in numbers if n % 2 == 0]
print(evens) # 输出:[2, 4, 6]
技巧2:切片操作(Slicing)
说明:通过指定起始、结束和步长来获取列表的子集。
场景:分页、反转列表、获取部分数据。
示例:
data = ['a', 'b', 'c', 'd', 'e', 'f']
# 获取第2到第4个元素(索引1到3)
print(data[1:4]) # 输出:['b', 'c', 'd']
# 反转列表
print(data[::-1]) # 输出:['f', 'e', 'd', 'c', 'b', 'a']
# 获取偶数索引元素
print(data[::2]) # 输出:['a', 'c', 'e']
技巧3:解包与星号表达式(Unpacking)
说明:将列表元素分配给多个变量,或处理可变数量参数。
场景:函数参数传递、交换变量值、处理剩余元素。
示例:
# 基本解包
first, second, *rest = [1, 2, 3, 4, 5]
print(first, second, rest) # 输出:1 2 [3, 4, 5]
# 交换变量值
a, b = 10, 20
a, b = b, a # 本质上是元组解包
print(a, b) # 输出:20 10
# 函数中使用
def process_data(first, *args):
print(f"首要数据:{first}, 其他数据:{args}")
process_data(10, 20, 30, 40) # 输出:首要数据:10, 其他数据:(20, 30, 40)
技巧4: enumerate 获取索引与值
说明:在遍历列表时同时获取元素的索引和值。
场景:需要索引进行操作的循环。
示例:
fruits = ['apple', 'banana', 'cherry']
for index, fruit in enumerate(fruits):
print(f"索引 {index}: {fruit}")
# 输出:
# 索引 0: apple
# 索引 1: banana
# 索引 2: cherry
# 可以指定起始索引
for idx, fruit in enumerate(fruits, start=1):
print(f"第{idx}个水果是{fruit}")
技巧5: zip 并行迭代多个列表
说明:将多个可迭代对象“压缩”在一起,并行迭代。
场景:同时处理多组相关联的数据。
示例:
names = ['Alice', 'Bob', 'Charlie']
ages = [25, 30, 35]
cities = ['NY', 'LA', 'Chicago']
for name, age, city in zip(names, ages, cities):
print(f"{name} ({age}岁) 来自{city}")
# 输出:
# Alice (25岁) 来自NY
# Bob (30岁) 来自LA
# Charlie (35岁) 来自Chicago
# 使用zip创建字典
info_dict = dict(zip(names, ages))
print(info_dict)
# 输出:{'Alice': 25, 'Bob': 30, 'Charlie': 35}
技巧6: sorted 与 list.sort 排序
说明: sorted 返回新列表, list.sort 原地排序。
场景:数据按特定规则排序。
示例:
nums = [3, 1, 4, 1, 5, 9]
# sorted 返回新列表
ascending = sorted(nums)
descending = sorted(nums, reverse=True)
print(ascending, descending) # 输出:[1, 1, 3, 4, 5, 9] [9, 5, 4, 3, 1, 1]
# list.sort 原地修改
nums.sort()
print(nums) # 输出:[1, 1, 3, 4, 5, 9]
# 复杂排序:按字符串长度
words = ['cat', 'window', 'defenestrate']
words.sort(key=len)
print(words) # 输出:['cat', 'window', 'defenestrate']
技巧7: any 与 all 条件判断
说明: any 检查是否有任意元素为真, all 检查是否所有元素为真。
场景:快速进行集合级别的布尔判断。
示例:
checks = [True, False, True]
print(any(checks))
# 输出:True (至少一个为True)
print(all(checks))
# 输出:False (并非全部为True)
# 实际应用:检查列表中是否有负数
numbers = [1, 2, 3, -4, 5]
has_negative = any(n < 0 for n in numbers)
print(has_negative) # 输出:True
# 检查是否全是正数
all_positive = all(n > 0 for n in numbers)
print(all_positive) # 输出:False
技巧8:使用 collections.deque 实现高效队列
说明: deque (双端队列)在两端添加/删除元素的时间复杂度为 O(1),而列表在头部操作是 O(n)。
场景:实现队列(FIFO)、栈(LIFO)或需要频繁在两端操作的数据流。
示例:
from collections import deque
# 作为队列使用(先进先出)
queue = deque(['Alice', 'Bob'])
queue.append('Charlie') # 入队
print(queue.popleft()) # 出队,输出:Alice
print(queue) # 输出:deque(['Bob', 'Charlie'])
# 作为栈使用(后进先出)
stack = deque()
stack.append('task1')
stack.append('task2')
print(stack.pop()) # 输出:task2
# 固定长度队列,自动丢弃旧数据
last_three = deque(maxlen=3)
for i in range(5):
last_three.append(i)
print(last_three)
# 最终输出:deque([2, 3, 4], maxlen=3)
技巧9:使用 bisect 维护有序列表
说明: bisect 模块提供了在有序列表中插入元素并保持有序的方法,效率高于先插入再排序。
场景:需要持续维护一个有序序列,如排行榜、时间线。
示例:
import bisect
scores = [10, 20, 30, 40]
# 找到插入位置以保持升序
insert_point = bisect.bisect(scores, 25)
print(insert_point) # 输出:2 (索引位置)
scores.insert(insert_point, 25)
print(scores) # 输出:[10, 20, 25, 30, 40]
# 直接插入并排序
sorted_list = [1, 3, 5]
bisect.insort(sorted_list, 4)
bisect.insort(sorted_list, 2)
print(sorted_list) # 输出:[1, 2, 3, 4, 5]
技巧10:列表的浅拷贝与深拷贝
说明:赋值( = )是引用传递, copy() 是浅拷贝, copy.deepcopy() 是深拷贝。
场景:需要复制列表数据而不影响原数据,尤其是嵌套结构。
示例:
import copy
original = [[1, 2], [3, 4]]
# 浅拷贝:只拷贝最外层
shallow_copy = original.copy()
shallow_copy[0][0] = 99
print(original) # 输出:[[99, 2], [3, 4]] !内部列表被修改了
original = [[1, 2], [3, 4]]
# 深拷贝:完全独立的新对象
deep_copy = copy.deepcopy(original)
deep_copy[0][0] = 99
print(original) # 输出:[[1, 2], [3, 4]] ✓ 原数据不受影响
二、字典(Dict)的10个核心技巧
字典是一个无序、可变的键值对集合,键必须是可哈希的类型。
技巧11: dict.get() 与 dict.setdefault()
说明:安全地访问和设置字典值,避免 KeyError 。
场景:处理可能缺失的键,或需要初始化默认值。
示例:
user = {'name': 'Alice', 'age': 30}
# get: 安全访问,键不存在返回None或指定默认值
city = user.get('city') # 返回 None
city = user.get('city', 'Unknown') # 返回 'Unknown'
print(city)
# setdefault: 键不存在时设置默认值并返回,存在则直接返回值
dept_count = {}
for person in ['Alice', 'Bob', 'Alice']:
dept_count.setdefault(person, 0)
dept_count[person] += 1
print(dept_count) # 输出:{'Alice': 2, 'Bob': 1}
技巧12:字典推导式(Dict Comprehension)
说明:类似列表推导式,用于简洁地创建字典。
场景:从其他数据结构转换生成字典。
示例:
# 列表转字典
keys = ['a', 'b', 'c']
values = [1, 2, 3]
mydict = {k: v for k, v in zip(keys, values)}
print(mydict) # 输出:{'a': 1, 'b': 2, 'c': 3}
# 过滤字典项
original = {'a': 1, 'b': 2, 'c': 3, 'd': 4}
filtered = {k: v for k, v in original.items() if v % 2 == 0}
print(filtered) # 输出:{'b': 2, 'd': 4}
# 键值交换(值必须可哈希)
swapped = {v: k for k, v in original.items()}
print(swapped) # 输出:{1: 'a', 2: 'b', 3: 'c', 4: 'd'}
技巧13:合并字典
说明:Python 3.5+ 提供了多种合并字典的方法。
场景:合并配置、更新数据。
示例:
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4} # 注意键'b'重复
# 方法1:解包操作符 (Python 3.5+)
merged = {**d1, **d2} # 后面的字典覆盖前面的
print(merged) # 输出:{'a': 1, 'b': 3, 'c': 4}
# 方法2:update方法 (原地修改)
d1.update(d2)
print(d1) # 输出:{'a': 1, 'b': 3, 'c': 4}
# 方法3:Python 3.9+ 的合并运算符
d1 = {'a': 1, 'b': 2}
d2 = {'b': 3, 'c': 4}
merged = d1 | d2
print(merged) # 输出:{'a': 1, 'b': 3, 'c': 4}
技巧14:使用 collections.defaultdict
说明:提供默认工厂函数,访问不存在的键时自动创建默认值。
场景:分组、计数、构建复杂嵌套结构。
示例:
from collections import defaultdict
# 分组:按首字母分组单词
words = ['apple', 'bat', 'bar', 'atom', 'book']
grouped = defaultdict(list) # 默认值为空列表
for word in words:
grouped[word[0]].append(word)
print(dict(grouped)) # 输出:{'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}
# 计数
counter = defaultdict(int)
for letter in 'abracadabra':
counter[letter] += 1
print(dict(counter)) # 输出:{'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}
技巧15:使用 collections.Counter 计数
说明: Counter 是 dict 的子类,专门用于计数可哈希对象。
场景:统计频率、找最常见元素。
示例:
from collections import Counter
# 基础计数
words = ['red', 'blue', 'red', 'green', 'blue', 'blue']
color_count = Counter(words)
print(color_count) # 输出:Counter({'blue': 3, 'red': 2, 'green': 1})
# 获取最常见元素
print(color_count.most_common(2)) # 输出:[('blue', 3), ('red', 2)]
# 更新计数
color_count.update(['red', 'yellow'])
print(color_count['red']) # 输出:3
# 数学运算
c1 = Counter(a=3, b=1)
c2 = Counter(a=1, b=2)
print(c1 + c2) # 输出:Counter({'a': 4, 'b': 3})
print(c1 - c2) # 输出:Counter({'a': 2})
技巧16:字典视图对象: keys() , values() , items()
说明:返回字典键、值或键值对的动态视图,而非列表。
场景:高效迭代、检查成员关系,且视图会随字典更新。
示例:
inventory = {'apple': 10, 'banana': 5, 'orange': 8}
keys_view = inventory.keys()
values_view = inventory.values()
items_view = inventory.items()
print(list(keys_view)) # 输出:['apple', 'banana', 'orange']
# 视图是动态的
inventory['grape'] = 12
print('grape' in keys_view) # 输出:True
# 高效迭代
for item, qty in inventory.items():
if qty < 10:
print(f"低库存:{item} 仅剩{qty}个")
技巧17:使用 dict.popitem() 与 dict.pop()
说明: popitem() 移除并返回最后一对键值(Python 3.7+ 后为插入顺序), pop(key) 移除指定键并返回值。
场景:安全移除元素并获取其值。
示例:
config = {'host': 'localhost', 'port': 8080, 'debug': True}
# popitem: 移除最后插入的项(LIFO)
key, value = config.popitem()
print(f"移除:{key}={value},剩余:{config}")
# pop: 移除指定键,可提供默认值
port = config.pop('port')
print(f"端口:{port},剩余:{config}")
# 安全移除不存在的键
timeout = config.pop('timeout', 30) # 键不存在则返回默认值30
print(f"超时设置:{timeout}")
技巧18:使用 frozenset 作为字典键
说明: frozenset 是不可变的集合,可哈希,因此可以作为字典的键。
场景:需要用集合作为键的场景,如存储图的关系、状态组合。
示例:
# 普通集合不可哈希,不能作为字典键
# invalid_key = {1, 2, 3} # TypeError: unhashable type: 'set'
# frozenset 可以作为键
graph_edges = {}
edge1 = frozenset(['A', 'B'])
edge2 = frozenset(['B', 'C'])
graph_edges[edge1] = 5 # 边AB的权重为5
graph_edges[edge2] = 3 # 边BC的权重为3
print(graph_edges[frozenset(['B', 'A'])]) # 输出:5 (无序集合,AB和BA相同)
技巧19:字典排序
说明:字典本身无序,但可按需生成排序后的列表或使用 collections.OrderedDict 。
场景:需要按特定顺序处理字典项。
示例:
scores = {'Alice': 88, 'Bob': 76, 'Charlie': 92, 'Diana': 85}
# 按键排序
sorted_by_key = dict(sorted(scores.items()))
print(sorted_by_key) # 输出:{'Alice': 88, 'Bob': 76, 'Charlie': 92, 'Diana': 85}
# 按值排序(降序)
sorted_by_value = dict(sorted(scores.items(), key=lambda item: item[1], reverse=True))
print(sorted_by_value) # 输出:{'Charlie': 92, 'Alice': 88, 'Diana': 85, 'Bob': 76}
# 使用OrderedDict保持插入顺序(Python 3.7+后普通dict已有序,但OrderedDict有额外方法)
from collections import OrderedDict
od = OrderedDict()
od['z'] = 1
od['a'] = 2
od['m'] = 3
print(list(od.keys())) # 输出:['z', 'a', 'm']
技巧20:使用字典模拟Switch-Case语句
说明:Python中没有 switch 语句,但可用字典映射实现类似功能。
场景:根据不同的输入值执行不同的函数或操作。
示例:
def handle_red():
return "停止"
def handle_green():
return "通行"
def handle_yellow():
return "谨慎"
def handle_default():
return "未知信号"
# 映射字典
traffic_light_actions = {
'red': handle_red,
'green': handle_green,
'yellow': handle_yellow
}
# 使用
signal = 'green'
action_func = traffic_light_actions.get(signal, handle_default)
result = action_func()
print(result) # 输出:通行
# 更简洁的写法(如果操作很简单)
actions = {
'add': lambda x, y: x + y,
'subtract': lambda x, y: x - y,
'multiply': lambda x, y: x * y
}
print(actions['multiply'](5, 3)) # 输出:15
总结与思考
列表和字典是Python数据处理的基石。列表擅长处理有序序列和同质数据集合,其核心在于高效的索引、切片和列表推导式等操作。字典则专精于键值映射和快速查找,其精髓在于灵活的键值操作和丰富的内置方法。
真正的精通来自于灵活组合这些技巧。例如,用列表存储字典以表示表格数据,或用字典的值存储列表以实现一对多的映射。在实践中不断尝试和组合,就能将这两种基础结构的力量发挥到极致,优雅地解决绝大多数数据处理难题。
掌握这些技巧,你可以在实际编程中:
- 更高效地处理数据:利用推导式、切片、视图对象减少循环和冗余代码。
- 写出更安全的代码:通过
get() 、 setdefault() 、拷贝机制避免常见错误。
- 解决更复杂的问题:结合
collections 模块中的专用容器,例如使用bisect模块维护有序列表以应对特定场景。
- 提升代码可读性:用字典模拟分支逻辑、用
zip 和 enumerate 简化迭代。
熟练掌握列表和字典的方方面面,是通往Python高效编程的必经之路。如果在学习过程中有更多心得或疑问,欢迎在云栈社区与更多开发者交流探讨。
“无他,惟手熟尔”!有需要的就用起来吧!
