Python基礎(chǔ)指南之字典推導(dǎo)式與字典合并技巧
一、開(kāi)篇:讓字典操作更優(yōu)雅
前面我們學(xué)完了字典的創(chuàng)建、CRUD和遍歷。今天我們要攻克兩個(gè)讓字典操作效率大幅提升的高級(jí)技巧:字典推導(dǎo)式和字典合并。
字典推導(dǎo)式之于字典,就像列表推導(dǎo)式之于列表。它能讓你用一行代碼完成"過(guò)濾+轉(zhuǎn)換+構(gòu)建新字典"的完整操作。而字典合并則是處理多來(lái)源配置、覆蓋默認(rèn)值、聚合數(shù)據(jù)時(shí)不可或缺的能力。
這兩個(gè)技巧在實(shí)際開(kāi)發(fā)中使用頻率極高。掌握了它們,你處理字典數(shù)據(jù)的代碼量通常會(huì)減少一半以上——更重要的是,代碼的意圖表達(dá)會(huì)更清晰。
二、字典推導(dǎo)式基礎(chǔ)
2.1 基本語(yǔ)法
# 語(yǔ)法:{key_expr: value_expr for item in iterable}
# 最簡(jiǎn)單的推導(dǎo)式
squares = {x: x ** 2 for x in range(6)}
print(squares) # {0: 0, 1: 1, 2: 4, 3: 9, 4: 16, 5: 25}
# 等價(jià)于:
squares = {}
for x in range(6):
squares[x] = x ** 2
# 從兩個(gè)列表構(gòu)建字典
keys = ['name', 'age', 'city']
values = ['小明', 25, '北京']
person = {k: v for k, v in zip(keys, values)}
print(person) # {'name': '小明', 'age': 25, 'city': '北京'}
2.2 帶條件的字典推導(dǎo)式
# 過(guò)濾——只保留滿足條件的項(xiàng)
numbers = {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# 只保留值大于2的
filtered = {k: v for k, v in numbers.items() if v > 2}
print(filtered) # {'c': 3, 'd': 4, 'e': 5}
# 只保留鍵以特定前綴開(kāi)頭的
config = {
'DB_HOST': 'localhost',
'DB_PORT': 5432,
'CACHE_HOST': 'redis://localhost',
'CACHE_PORT': 6379,
'APP_NAME': 'MyApp',
}
# 提取所有數(shù)據(jù)庫(kù)相關(guān)配置
db_config = {k: v for k, v in config.items() if k.startswith('DB_')}
print(db_config) # {'DB_HOST': 'localhost', 'DB_PORT': 5432}
# 提取緩存相關(guān)配置并去掉前綴
cache_config = {
k.replace('CACHE_', '').lower(): v
for k, v in config.items()
if k.startswith('CACHE_')
}
print(cache_config) # {'host': 'redis://localhost', 'port': 6379}
2.3 鍵和值的變換
# 變換鍵
original = {'a': 1, 'b': 2, 'c': 3}
uppercase_keys = {k.upper(): v for k, v in original.items()}
print(uppercase_keys) # {'A': 1, 'B': 2, 'C': 3}
# 變換值
prices = {'apple': 10, 'banana': 5, 'orange': 8}
with_tax = {k: v * 1.1 for k, v in prices.items()}
print(with_tax) # {'apple': 11.0, 'banana': 5.5, 'orange': 8.8}
# 同時(shí)變換鍵和值
original = {'user_name': 'xiaoming', 'user_email': 'xm@test.com'}
cleaned = {
k.replace('user_', '').upper(): v.upper()
for k, v in original.items()
}
print(cleaned) # {'NAME': 'XIAOMING', 'EMAIL': 'XM@TEST.COM'}
# 反轉(zhuǎn)字典(鍵值互換)
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'}
# ?? 注意:如果值有重復(fù),后面的會(huì)覆蓋前面的
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'被'c'覆蓋了)
# 處理值重復(fù)的反轉(zhuǎn)
def safe_reverse(d):
"""安全反轉(zhuǎn)——值重復(fù)時(shí)收集所有鍵"""
result = {}
for k, v in d.items():
result.setdefault(v, []).append(k)
return result
print(safe_reverse({'a': 1, 'b': 2, 'c': 1})) # {1: ['a', 'c'], 2: ['b']}
三、字典推導(dǎo)式的高級(jí)用法
3.1 嵌套推導(dǎo)式
# 從嵌套數(shù)據(jù)構(gòu)建字典
# 例:從元組列表構(gòu)建嵌套字典
students = [
('小明', {'math': 85, 'english': 90}),
('小紅', {'math': 92, 'english': 88}),
('小剛', {'math': 78, 'english': 85}),
]
# 找出數(shù)學(xué)成績(jī)大于80的學(xué)生
math_above_80 = {
name: scores
for name, scores in students
if scores['math'] > 80
}
print(math_above_80)
# {'小明': {'math': 85, 'english': 90}, '小紅': {'math': 92, 'english': 88}}
# 從查詢結(jié)果構(gòu)建嵌套字典
products = [
('電子產(chǎn)品', '手機(jī)', 2999),
('電子產(chǎn)品', '電腦', 5999),
('食品', '蘋(píng)果', 5),
('食品', '香蕉', 3),
('服裝', 'T恤', 99),
]
# 構(gòu)建 {類別: {商品: 價(jià)格}}
catalog = {}
for category, item, price in products:
catalog.setdefault(category, {})[item] = price
print(catalog)
# {'電子產(chǎn)品': {'手機(jī)': 2999, '電腦': 5999}, ...}
# 更簡(jiǎn)潔:用字典推導(dǎo)式分組
from collections import defaultdict
catalog2 = defaultdict(dict)
for category, item, price in products:
catalog2[category][item] = price
print(dict(catalog2))
3.2 條件表達(dá)式在推導(dǎo)式中的應(yīng)用
scores = {'小明': 85, '小紅': 92, '小剛': 78, '小李': 95, '小王': 60}
# if-else在鍵或值的表達(dá)式中
# 給及格和不及格的人不同標(biāo)注
graded = {
k: ('優(yōu)秀' if v >= 90 else '良好' if v >= 80 else '及格' if v >= 60 else '不及格')
for k, v in scores.items()
}
print(graded)
# {'小明': '良好', '小紅': '優(yōu)秀', '小剛': '良好', '小李': '優(yōu)秀', '小王': '及格'}
# 鍵和值都加條件變換
transformed = {
k.upper() if v >= 90 else k.lower(): v * 2 if v < 80 else v
for k, v in scores.items()
}
print(transformed)
# 只對(duì)滿足條件的鍵值對(duì)做變換(if在for后面=過(guò)濾)
high_scores = {
k: v for k, v in scores.items() if v >= 80
}
print(high_scores) # {'小明': 85, '小紅': 92, '小李': 95}
3.3 從列表推導(dǎo)式到字典推導(dǎo)式
# 場(chǎng)景:統(tǒng)計(jì)詞頻
text = 'hello world hello python world hello'
# 方式一:普通循環(huán)
word_count = {}
for word in text.split():
word_count[word] = word_count.get(word, 0) + 1
# 方式二:使用Counter(最簡(jiǎn)單)
from collections import Counter
word_count = dict(Counter(text.split()))
# 方式三:字典推導(dǎo)式 + set
unique_words = set(text.split())
word_count = {word: text.split().count(word) for word in unique_words}
# 注意:這種方式效率低(每個(gè)詞都要count一遍全文)
# 場(chǎng)景:構(gòu)建索引
words = ['apple', 'banana', 'cherry', 'date', 'elderberry']
# {首字母: [單詞列表]}
index = {ch: [w for w in words if w.startswith(ch)]
for ch in set(w[0] for w in words)}
print(index)
# {'a': ['apple'], 'b': ['banana'], 'c': ['cherry'], 'd': ['date'], 'e': ['elderberry']}
四、字典合并的四種方式
4.1 | 運(yùn)算符(Python 3.9+,最推薦)
# 合并兩個(gè)字典,返回新字典
defaults = {'host': 'localhost', 'port': 8080, 'debug': False}
overrides = {'port': 9090, 'debug': True, 'timeout': 30}
config = defaults | overrides
print(config)
# {'host': 'localhost', 'port': 9090, 'debug': True, 'timeout': 30}
# 有重復(fù)鍵時(shí),右邊的值覆蓋左邊的
# 鏈?zhǔn)胶喜?
d1 = {'a': 1}
d2 = {'b': 2}
d3 = {'c': 3}
merged = d1 | d2 | d3
print(merged) # {'a': 1, 'b': 2, 'c': 3}
# 注意:| 運(yùn)算符要求兩邊都是dict
# {1: 'a'} | [(2, 'b')] # TypeError
4.2 |= 原地合并(Python 3.9+)
config = {'host': 'localhost', 'port': 8080}
# |= 原地修改現(xiàn)有字典
config |= {'debug': True, 'port': 9090}
print(config)
# {'host': 'localhost', 'port': 9090, 'debug': True}
# 等價(jià)于 config.update({'debug': True, 'port': 9090})
# 可以接受任何可迭代的鍵值對(duì)
config |= [('timeout', 30), ('retries', 3)]
print(config)
# {'host': 'localhost', 'port': 9090, 'debug': True, 'timeout': 30, 'retries': 3}
4.3 ** 解包(Python 3.5+)
d1 = {'a': 1, 'b': 2}
d2 = {'c': 3, 'd': 4}
d3 = {'a': 100, 'e': 5}
# 用 ** 解包合并
merged = {**d1, **d2, **d3}
print(merged) # {'a': 100, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
# 同樣的覆蓋規(guī)則:后面的覆蓋前面的
# d3的'a':100覆蓋了d1的'a':1
# 在合并時(shí)插入額外的鍵
merged = {**d1, 'extra': 'value', **d2}
print(merged) # {'a': 1, 'b': 2, 'extra': 'value', 'c': 3, 'd': 4}
# ** 解包的一個(gè)限制:鍵必須是字符串
# d = {**{1: 'one'}, **{2: 'two'}} # TypeError(Python限制)
# 這種情況下用 | 或 update()
4.4 update()(Python 3.0+)
d = {'a': 1, 'b': 2}
# update() 原地合并,接受多種參數(shù)形式
d.update({'c': 3}) # 字典
d.update(d=4, e=5) # 關(guān)鍵字參數(shù)
d.update([('f', 6)]) # 鍵值對(duì)可迭代對(duì)象
print(d) # {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5, 'f': 6}
# update() 可以和 | 對(duì)比
d1 = {'a': 1, 'b': 2}
d2 = {'b': 20, 'c': 3}
# 方式A:合并+創(chuàng)建新字典(|)
d3 = d1 | d2
# d1不變,d3是新的
# 方式B:合并+原地修改(update)
d1.update(d2)
# d1被修改了
# 選擇:需要保留原字典用 |,不需要保留用 update
五、合并方式的對(duì)比與選擇
方式對(duì)比表
| 方式 | Python版本 | 創(chuàng)建新字典 | 原地修改 | 要求鍵是字符串 |
|---|---|---|---|---|
| 運(yùn)算符 | 3.9+ | 是 | 否 | 否(任意可哈希類型) |
|= 原地合并 | 3.9+ | 否 | 是 | 否(任意可哈希類型) |
** 解包 | 3.5+ | 是 | 否 | 是(僅限字符串鍵) |
update() | 全部 | 否 | 是 | 多種參數(shù)形式 |
選擇建議:
- Python 3.9+、需要新字典 → d1 | d2
- Python 3.9+、原地修改 → d1 |= d2
- Python 3.5-3.8、需要新字典 → {**d1, **d2}
- 任何Python版本、原地修改 → d1.update(d2)
- 需要兼容舊代碼 → update()始終可用
六、實(shí)戰(zhàn):配置管理系統(tǒng)
class Config:
"""多層級(jí)配置管理系統(tǒng)"""
def __init__(self, defaults=None):
self._config = defaults.copy() if defaults else {}
def load(self, **overrides):
"""加載配置——合并并覆蓋"""
# 過(guò)濾掉None值
valid_overrides = {k: v for k, v in overrides.items() if v is not None}
self._config |= valid_overrides
def load_from_file(self, file_config):
"""從文件加載配置"""
# 只加載已知的配置項(xiàng)
known_keys = self._config.keys()
filtered = {k: v for k, v in file_config.items() if k in known_keys}
self._config |= filtered
def get(self, key, default=None):
return self._config.get(key, default)
def to_dict(self):
return self._config.copy()
def clone(self):
"""創(chuàng)建配置副本(用于子組件)"""
return Config(self._config.copy())
# 使用示例
default_config = {
'host': 'localhost',
'port': 8080,
'debug': False,
'log_level': 'INFO',
'max_connections': 100,
'timeout': 30,
}
app_config = Config(default_config)
# 加載環(huán)境特定配置
app_config.load(port=9090, debug=True)
# 加載文件配置
file_config = {
'host': 'prod.server.com',
'port': 443,
'debug': False,
'log_level': 'WARNING',
'unknown_key': 'should_be_ignored',
}
app_config.load_from_file(file_config)
print('最終配置:')
for k, v in app_config.to_dict().items():
print(f' {k}: {v}')
七、字典合并的經(jīng)典模式
# 模式一:默認(rèn)值 + 覆蓋
def create_user(**kwargs):
defaults = {'role': 'user', 'active': True, 'level': 1}
return defaults | kwargs # kwargs覆蓋defaults
print(create_user(name='小明', role='admin'))
# {'role': 'admin', 'active': True, 'level': 1, 'name': '小明'}
# 模式二:層級(jí)配置合并
def merge_deep(base, override):
"""深度合并兩個(gè)字典(嵌套字典遞歸合并)"""
result = base.copy()
for key, value in override.items():
if key in result and isinstance(result[key], dict) and isinstance(value, dict):
result[key] = merge_deep(result[key], value)
else:
result[key] = value
return result
base = {
'database': {'host': 'localhost', 'port': 5432, 'pool': {'min': 1}},
'cache': {'host': 'localhost', 'port': 6379},
}
override = {
'database': {'port': 5433, 'pool': {'max': 20}},
}
merged = merge_deep(base, override)
print(merged)
# {'database': {'host': 'localhost', 'port': 5433, 'pool': {'min': 1, 'max': 20}},
# 'cache': {'host': 'localhost', 'port': 6379}}
# 模式三:多源數(shù)據(jù)聚合
def aggregate_data(*sources):
"""聚合多個(gè)數(shù)據(jù)源——后面的覆蓋前面的"""
result = {}
for source in sources:
if source:
result |= source
return result
user_from_db = {'id': 1, 'name': '小明', 'email': 'xm@test.com'}
user_from_api = {'name': '小明(更新)', 'phone': '13800138000'}
user_from_cache = {'last_login': '2025-06-01'}
final_user = aggregate_data(user_from_db, user_from_api, user_from_cache)
print(final_user)
八、常見(jiàn)陷阱和注意事項(xiàng)
# 陷阱一:| 運(yùn)算符的優(yōu)先級(jí)
# d = {'a': 1} | {'b': 2} if condition else {}
# 上面的代碼可能不是你期望的意思
# 建議加括號(hào)
# d = ({'a': 1} | {'b': 2}) if condition else {}
# 陷阱二:** 解包不能處理非字符串鍵
# d = {**{1: 'a'}, **{2: 'b'}} # TypeError
# 用 | 或 update 代替
d = {1: 'a'} | {2: 'b'}
print(d) # {1: 'a', 2: 'b'}
# 陷阱三:推導(dǎo)式中的變量作用域
# 字典推導(dǎo)式有自己的局部作用域(Python 3+)
# 不會(huì)污染外部命名空間
x = 'outer'
d = {x: x * 3 for x in 'abc'}
print(d) # {'a': 'aaa', 'b': 'bbb', 'c': 'ccc'}
print(x) # 'outer'(外部變量不受影響)
# 陷阱四:空字典的處理
empty = {}
# empty | {} # 這是OK的
# 但注意:None | {} 會(huì)報(bào)TypeError
config = None
# merged = config | {} # TypeError(如果config是None)
# 正確:先檢查
merged = (config or {}) | {}
九、本篇小結(jié)
字典推導(dǎo)式和合并操作是Python字典的兩大高級(jí)利器:
字典推導(dǎo)式:
- 語(yǔ)法:
{key_expr: value_expr for item in iterable if condition} - 適合:過(guò)濾、鍵值轉(zhuǎn)換、反轉(zhuǎn)、構(gòu)建新字典
- 比等價(jià)的for循環(huán)更短、更快、更易讀
字典合并(四種方式):
d1 | d2(Python 3.9+)—— 創(chuàng)建新字典,最推薦d1 |= d2(Python 3.9+)—— 原地修改{**d1, **d2}(Python 3.5+)—— 創(chuàng)建新字典,僅限字符串鍵d1.update(d2)(所有版本)—— 原地修改,最通用
字典推導(dǎo)式和字典合并是日常開(kāi)發(fā)中的高頻操作。熟練掌握它們,你處理字典數(shù)據(jù)的代碼會(huì)更簡(jiǎn)潔、更Pythonic。下一篇我們學(xué)習(xí)collections模塊中的defaultdict和OrderedDict——兩個(gè)在特定場(chǎng)景下比普通字典更好用的字典變體。
以上就是Python基礎(chǔ)指南之字典推導(dǎo)式與字典合并技巧的詳細(xì)內(nèi)容,更多關(guān)于Python字典推導(dǎo)式與合并的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
- 一文深度解析Python中列表與字典推導(dǎo)式
- Python的字典推導(dǎo)式從入門(mén)到精通
- Python推導(dǎo)式之字典推導(dǎo)式和集合推導(dǎo)式使用體驗(yàn)
- Python列表推導(dǎo)式,元組推導(dǎo)式,字典推導(dǎo)式,集合推導(dǎo)式
- Python 列表推導(dǎo)式與字典推導(dǎo)式的實(shí)現(xiàn)
- Python把三個(gè)字典合并成一個(gè)字典的常用方法
- Python中合并兩個(gè)字典的多種方法小結(jié)
- Python實(shí)現(xiàn)合并兩個(gè)字典的8種方法
- python實(shí)現(xiàn)字典合并的五種方法(附示例代碼)
相關(guān)文章
python 還原梯度下降算法實(shí)現(xiàn)一維線性回歸
這篇文章主要介紹了python 還原梯度下降算法實(shí)現(xiàn)一維線性回歸,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10
Pycharm中配置使用Anaconda的虛擬環(huán)境進(jìn)行項(xiàng)目開(kāi)發(fā)的圖文教程
今天在一臺(tái)電腦上跑環(huán)境的時(shí)候,發(fā)現(xiàn)已經(jīng)裝了Pytorch了,但是運(yùn)行沒(méi)有用,提示報(bào)錯(cuò):OSError:?[WinError?126]?找不到指定的模塊,但其實(shí)cmd進(jìn)入虛擬環(huán)境是可以調(diào)用torch的,故本文給大家介紹了Pycharm中配置使用Anaconda的虛擬環(huán)境進(jìn)行項(xiàng)目開(kāi)發(fā)的圖文教程2024-09-09
OpenCV-Python實(shí)現(xiàn)圖像梯度與Sobel濾波器
在實(shí)際應(yīng)用中我們只需要將圖像矩陣與Sobel濾波器卷積就可以得到圖像的梯度矩陣了。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-06-06
Python實(shí)現(xiàn)單例模式的五種寫(xiě)法總結(jié)
單例模式(Singleton Pattern) 是一種常用的軟件設(shè)計(jì)模式,該模式的主要目的是確保某一個(gè)類只有一個(gè)實(shí)例存在。本文為大家整理了五種Python實(shí)現(xiàn)單例模式的寫(xiě)法,需要的可以參考一下2022-08-08
關(guān)于python pycharm中輸出的內(nèi)容不全的解決辦法
這篇文章主要介紹了關(guān)于python pycharm中輸出的內(nèi)容不全的解決辦法,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-01-01
python爬蟲(chóng)之pyppeteer庫(kù)簡(jiǎn)單使用
Puppeteer 是 Google 基于 Node.js 開(kāi)發(fā)的一個(gè)工具,有了它我們可以通過(guò) JavaScript 來(lái)控制 Chrome 瀏覽器的一些操作,當(dāng)然也可以用作網(wǎng)絡(luò)爬蟲(chóng)上,其 API 極其完善,功能非常強(qiáng)大2021-07-07
python析構(gòu)函數(shù)用法及注意事項(xiàng)
在本篇文章里小編給大家整理的是一篇關(guān)于python析構(gòu)函數(shù)用法及注意事項(xiàng),有需要的朋友們可以學(xué)習(xí)參考下。2021-06-06
PyTorch中torch.nn.Linear實(shí)例詳解
torch.nn是包含了構(gòu)筑神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)基本元素的包,在這個(gè)包中可以找到任意的神經(jīng)網(wǎng)絡(luò)層,下面這篇文章主要給大家介紹了關(guān)于PyTorch中torch.nn.Linear的相關(guān)資料,文中通過(guò)實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-06-06

