
你每天都在写Python代码,但有些技巧你可能从来都没用过。
说实话,80%的Python开发者对列表和字典的理解,还停留在最基础的层面。
就像用手表掐时间,虽然也能用,但每次都要看表、算时间,真的累。
你想过没有,为什么同样的功能,别人写的代码比你快10倍?
今天这篇文章,就把列表和字典的核心技巧一次性讲清楚。从基础到进阶,从常
用到少见,总有一个能让你眼前一亮。
列表是一个有序、可变的集合,可以容纳任意类型的元素。
一种简洁、高效地创建新列表的语法。
# 生成1到10的平方列表
squares = [x**for x inrange(, )]
print(squares) # → [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# 过滤出偶数
numbers = [, , , , , ]
evens = [n for n in numbers if n % == ]
print(evens) # → [2, 4, 6]这种方式一行代码搞定,比传统写法优雅太多了。
通过指定起始、结束和步长来获取列表的子集。
data = ['a', 'b', 'c', 'd', 'e', 'f']
# 获取第2到第4个元素(索引1到3)
print(data[:]) # → ['b', 'c', 'd']
# 反转列表
print(data[::-]) # → ['f', 'e', 'd', 'c', 'b', 'a']
# 获取偶数索引元素
print(data[::]) # → ['a', 'c', 'e']切片的威力远不止这些,灵活运用能省很多代码。
将列表元素分配给多个变量,或处理可变数量参数。
# 基本解包
first, second, *rest = [, , , , ]
print(first, second, rest) # → 1 2 [3, 4, 5]
# 交换变量值
a, b = ,
a, b = b, a# 本质上是元组解包
print(a, b) # → 20 10
# 函数中使用
defprocess_data(first, *args):
print(f"首要数据:{first}, 其他数据:{args}")
process_data(, , , ) # → 首要数据:10, 其他数据:(20, 30, 40)星号表达式就像一个万能容器,能装下所有"剩余"的元素。
在遍历列表时同时获取元素的索引和值。
fruits = ['apple', 'banana', 'cherry']
# 标准用法
for index, fruit inenumerate(fruits):
print(f"索引 {index}: {fruit}")
# → 索引 0: apple
# → 索引 1: banana
# → 索引 2: cherry
# 指定起始索引
for idx, fruit inenumerate(fruits, start=):
print(f"第{idx}个水果是{fruit}")再也不要写 for i in range(len(list)) 这种丑陋的代码了。
将多个可迭代对象"压缩"在一起,并行迭代。
names = ['Alice', 'Bob', 'Charlie']
ages = [, , ]
cities = ['NY', 'LA', 'Chicago']
# 并行遍历多个列表
for name, age, city inzip(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}就像给三列数据按行缝在一起,一目了然。
sorted返回新列表,list.sort原地排序。
nums = [, , , , , ]
# 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']记住,sorted不改变原列表,list.sort会改变。
any检查是否有任意元素为真,all检查是否所有元素为真。
checks = [True, False, True]
print(any(checks)) # → True (至少一个为True)
print(all(checks)) # → False (并非全部为True)
# 实际应用:检查列表中是否有负数
numbers = [, , , -, ]
has_negative = any(n < for n in numbers)
print(has_negative) # → True
# 检查是否全是正数
all_positive = all(n > for n in numbers)
print(all_positive) # → False快速进行集合级别的布尔判断,一行代码搞定。
deque(双端队列)在两端添加/删除元素的时间复杂度为O(1),而列表在头部操作是O(n)。
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=)
for i inrange():
last_three.append(i)
print(last_three)
# → deque([0], maxlen=3)
# → deque([0, 1], maxlen=3)
# → deque([0, 1, 2], maxlen=3)
# → deque([1, 2, 3], maxlen=3)
# → deque([2, 3, 4], maxlen=3)deque比list在双端操作上快10-100倍,数据量大时优势明显。
bisect模块提供了在有序列表中插入元素并保持有序的方法,效率高于先插入再排序。
import bisect
scores = [, , , ]
# 找到插入位置以保持升序
insert_point = bisect.bisect(scores, )
print(insert_point) # → 2 (索引位置)
scores.insert(insert_point, )
print(scores) # → [10, 20, 25, 30, 40]
# 直接插入并排序
sorted_list = [, , ]
bisect.insort(sorted_list, )
bisect.insort(sorted_list, )
print(sorted_list) # → [1, 2, 3, 4, 5]需要持续维护一个有序序列时,这个模块能帮你省不少心。
赋值(=)是引用传递,copy()是浅拷贝,copy.deepcopy()是深拷贝。
import copy
original = [[, ], [, ]]
# 浅拷贝:只拷贝最外层
shallow_copy = original.copy()
shallow_copy[][] =
print(original) # → [[99, 2], [3, 4]] ⚠️ 内部列表被修改了!
original = [[, ], [, ]]
# 深拷贝:完全独立的新对象
deep_copy = copy.deepcopy(original)
deep_copy[][] =
print(original) # → [[1, 2], [3, 4]] ✅ 原数据不受影响嵌套结构一定要用深拷贝,否则修改会影响原数据。
filter()函数用于过滤序列,过滤掉不符合条件的元素。
numbers = [, , , , , ]
# 过滤出偶数
evens = list(filter(lambda x: x % == , numbers))
print(evens) # → [2, 4, 6]
# 过滤出大于3的数
greater_than_3 = list(filter(lambda x: x > , numbers))
print(greater_than_3) # → [4, 5, 6]虽然列表推导式更简洁,但filter在某些场景下更清晰。
map()函数将指定函数应用于可迭代对象的每个元素。
numbers = [, , , , ]
# 计算平方
squares = list(map(lambda x: x**, numbers))
print(squares) # → [1, 4, 9, 16, 25]
# 转换为字符串
strings = list(map(str, numbers))
print(strings) # → ['1', '2', '3', '4', '5']map()的威力在于可以将函数批量应用到所有元素上。
reversed()函数返回一个反转的迭代器。
data = [, , , , ]
# 转换为列表
reversed_data = list(reversed(data))
print(reversed_data) # → [5, 4, 3, 2, 1]
# 在遍历中使用
for item inreversed(data):
print(item) # → 5 4 3 2 1和切片[::-1]效果类似,但reversed()更节省内存。
list()函数可以将可迭代对象转换为列表。
# 从字符串创建
text = "hello"
chars = list(text)
print(chars) # → ['h', 'e', 'l', 'l', 'o']
# 从range创建
numbers = list(range())
print(numbers) # → [0, 1, 2, 3, 4]
# 从元组创建
tup = (, , )
lst = list(tup)
print(lst) # → [1, 2, 3]灵活运用,可以将任何可迭代对象转换为列表。
itertools.chain可以将多个可迭代对象连接起来。
from itertools import chain
nested_list = [[, ], [, ], [, ]]
# 展平嵌套列表
flat_list = list(chain.from_iterable(nested_list))
print(flat_list) # → [1, 2, 3, 4, 5, 6]
# 连接多个列表
list1 = [, ]
list2 = [, ]
list3 = [, ]
combined = list(chain(list1, list2, list3))
print(combined) # → [1, 2, 3, 4, 5, 6]处理嵌套结构时,这个函数特别好用。
字典是一个无序、可变的键值对集合,键必须是可哈希的类型。
安全地访问和设置字典值,避免KeyError。
user = {'name': 'Alice', 'age': }
# 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, )
dept_count[person] +=
print(dept_count) # → {'Alice': 2, 'Bob': 1}这两个方法能帮你省掉大量的if判断。
类似列表推导式,用于简洁地创建字典。
# 列表转字典
keys = ['a', 'b', 'c']
values = [, , ]
mydict = {k: v for k, v inzip(keys, values)}
print(mydict) # → {'a': 1, 'b': 2, 'c': 3}
# 过滤字典项
original = {'a': , 'b': , 'c': , 'd': }
filtered = {k: v for k, v in original.items() if v % == }
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'}一行代码搞定字典的创建、过滤、转换。
Python 3.5+ 提供了多种合并字典的方法。
d1 = {'a': , 'b': }
d2 = {'b': , 'c': } # 注意键'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': , 'b': }
d2 = {'b': , 'c': }
merged = d1 | d2
print(merged) # → {'a': 1, 'b': 3, 'c': 4}选择你喜欢的方式,但要注意键冲突的情况。
提供默认工厂函数,访问不存在的键时自动创建默认值。
from collections import defaultdict
# 分组:按首字母分组单词
words = ['apple', 'bat', 'bar', 'atom', 'book']
grouped = defaultdict(list) # 默认值为空列表
for word in words:
grouped[word[]].append(word)
print(dict(grouped))
# → {'a': ['apple', 'atom'], 'b': ['bat', 'bar', 'book']}
# 计数
counter = defaultdict(int)
for letter in'abracadabra':
counter[letter] +=
print(dict(counter))
# → {'a': 5, 'b': 2, 'r': 2, 'c': 1, 'd': 1}再也不用写 `if key not in dict` 这种冗长的代码了。
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()) # → [('blue', 3), ('red', 2)]
# 更新计数
color_count.update(['red', 'yellow'])
print(color_count['red']) # → 3
# 数学运算
c1 = Counter(a=, b=)
c2 = Counter(a=, b=)
print(c1 + c2) # → Counter({'a': 4, 'b': 3})
print(c1 - c2) # → Counter({'a': 2})统计频率、找最常见元素,Counter是最专业的工具。
返回字典键、值或键值对的动态视图,而非列表。
inventory = {'apple': , 'banana': , 'orange': }
keys_view = inventory.keys()
values_view = inventory.values()
items_view = inventory.items()
print(list(keys_view)) # → ['apple', 'banana', 'orange']
# 视图是动态的
inventory['grape'] =
print('grape'in keys_view) # → True
# 高效迭代
for item, qty in inventory.items():
if qty < :
print(f"低库存:{item} 仅剩{qty}个")
# → 低库存:banana 仅剩5个
# → 低库存:orange 仅剩8个视图对象会随字典更新而变化,节省内存。
popitem()移除并返回最后一对键值(Python 3.7+后为插入顺序),pop(key)移除指定键并返回值。
config = {'host': 'localhost', 'port': , 'debug': True}
# popitem: 移除最后插入的项(LIFO)
key, value = config.popitem()
print(f"移除:{key}={value},剩余:{config}")
# → 移除:debug=True,剩余:{'host': 'localhost', 'port': 8080}
# pop: 移除指定键,可提供默认值
port = config.pop('port')
print(f"端口:{port},剩余:{config}")
# → 端口:8080,剩余:{'host': 'localhost'}
# 安全移除不存在的键
timeout = config.pop('timeout', ) # 键不存在则返回默认值30
print(f"超时设置:{timeout}") # → 超时设置:30安全移除元素并获取其值,比先判断再删除更优雅。
frozenset是不可变的集合,可哈希,因此可以作为字典的键。
# 普通集合不可哈希,不能作为字典键
# invalid_key = {1, 2, 3} # TypeError: unhashable type: 'set'
# frozenset 可以作为键
graph_edges = {}
edge1 = frozenset(['A', 'B'])
edge2 = frozenset(['B', 'C'])
graph_edges[edge1] = # 边AB的权重为5
graph_edges[edge2] = # 边BC的权重为3
print(graph_edges[frozenset(['B', 'A'])]) # → 5 (无序集合,AB和BA相同)需要用集合作为键的场景,frozenset是唯一选择。
字典本身无序,但可按需生成排序后的列表或使用collections.OrderedDict。
scores = {'Alice': , 'Bob': , 'Charlie': , 'Diana': }
# 按键排序
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[], reverse=True))
print(sorted_by_value)
# → {'Charlie': 92, 'Alice': 88, 'Diana': 85, 'Bob': 76}
# 使用OrderedDict保持插入顺序
from collections import OrderedDict
od = OrderedDict()
od['z'] =
od['a'] =
od['m'] =
print(list(od.keys())) # → ['z', 'a', 'm']需要按特定顺序处理字典项时,这些方法很实用。
Python没有switch语句,但可用字典映射实现类似功能。
defhandle_red():
return"停止"
defhandle_green():
return"通行"
defhandle_yellow():
return"谨慎"
defhandle_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'](, )) # → 15比if-elif-elif链更优雅,可读性也更好。
ChainMap将多个字典逻辑上连接在一起,查找时按顺序搜索。
from collections import ChainMap
defaults = {'color': 'red', 'user': 'guest'}
user_prefs = {'user': 'admin', 'page_size': }
config = ChainMap(user_prefs, defaults)
print(config['user']) # → admin (优先从user_prefs查找)
print(config['color']) # → red (user_prefs没有,从defaults查找)
print(config['page_size']) # → 20适合配置管理、参数优先级设置等场景。
fromkeys()方法用指定的键创建一个新字典。
# 创建值相同的字典
keys = ['a', 'b', 'c']
value =
mydict = dict.fromkeys(keys, value)
print(mydict) # → {'a': 0, 'b': 0, 'c': 0}
# 创建空字典(值为None)
empty_dict = dict.fromkeys(keys)
print(empty_dict) # → {'a': None, 'b': None, 'c': None}
# 初始化计数器
counter = dict.fromkeys(range(), )
print(counter) # → {0: 0, 1: 0, 2: 0, 3: 0, 4: 0}初始化字典时特别好用,一行代码搞定。
clear()方法清空字典中的所有项。
data = {'a': , 'b': , 'c': }
print(data) # → {'a': 1, 'b': 2, 'c': 3}
data.clear()
print(data) # → {}
# 注意:和赋值空字典的区别
data = {'a': , 'b': }
new_data = data
data.clear() # 原地清空,new_data也会变为{}
print(new_data) # → {}
data = {'a': , 'b': }
new_data = data
data = {} # 创建新字典,new_data不受影响
print(new_data) # → {'a': 1, 'b': 2}记住原地操作和重新赋值的区别。
检查键是否存在于字典中。
user = {'name': 'Alice', 'age': }
# 检查键是否存在
if'name'in user:
print(f"姓名:{user['name']}") # → 姓名:Alice
if'email'not in user:
print("邮箱信息未提供") # → 邮箱信息未提供
# 结合get()使用
email = user.get('email') if'email'in user else'未提供'
print(email) # → 未提供比使用try-except或key in dict.keys()更高效。
update()方法用另一个字典的键值对更新当前字典。
config = {'host': 'localhost', 'port': }
updates = {'port': , 'debug': True, 'timeout': }
config.update(updates)
print(config)
# → {'host': 'localhost', 'port': 9090, 'debug': True, 'timeout': 30}
# 也可以用关键字参数
config.update(host='192.168.1.1', port=)
print(config)
# → {'host': '192.168.1.1', 'port': 8000, 'debug': True, 'timeout': 30}批量更新字典时最简洁的方法。
看了这么多技巧,你可能有点晕了。
别急,给你一个简单的选择指南:
场景 | 推荐方法 | 原因 |
|---|---|---|
创建新列表 | 列表推导式 | 简洁高效 |
过滤元素 | filter()或推导式 | 可读性好 |
多列表并行处理 | zip() | 一行搞定 |
频繁头尾操作 | deque | 性能最优 |
维护有序列表 | bisect | 效率高于排序 |
字典安全访问 | get()或setdefault() | 避免KeyError |
分组计数 | defaultdict | 自动初始化 |
频率统计 | Counter | 专用工具 |
多字典管理 | ChainMap | 优先级查找 |
模拟switch-case | 字典映射 | 优雅简洁 |
列表和字典是Python数据处理的基石。
列表擅长处理有序序列和同质数据集合,核心是高效的索引、切片和推导式。字
典则专精于键值映射和快速查找,精髓是灵活的键值操作和丰富的内置方法。
但真正的威力来自于组合。
比如,用列表存储字典表示表格数据,或用字典的值存储列表实现一对多映射。
记住:代码不仅要跑得动,更要跑得漂亮。
今天就试试这些技巧吧,评论区告诉我哪个对你最有用!
“无他,惟手熟尔”!有需要的用起来!
本文分享自 Nicholas与Pypi 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!