字典(Dictionary)#

字典(Dictionary)儲存 鍵值對(key-value pair) ,透過 鍵(key) 快速查找對應的 值(value)

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
# 建立字典
person = {
    "name": "Alice",
    "age": 25,
    "city": "Taipei"
}

# 空字典
empty = {}
empty2 = dict()

# 用 dict() 建立
profile = dict(name="Bob", age=30)

字典的特性:

  • 有序 (Python 3.7+ 保留插入順序)
  • 鍵不重複 (重複的鍵會覆蓋前一個值)
  • 鍵必須可雜湊 (字串、數字、元組可以;串列不行)

存取元素#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
person = {"name": "Alice", "age": 25, "city": "Taipei"}

# 用鍵存取值
print(person["name"])  # Alice
print(person["age"])   # 25

# 鍵不存在時會報 KeyError
# print(person["email"])  # ❌ KeyError

# 用 get():鍵不存在時回傳 None 或預設值
print(person.get("email"))          # None
print(person.get("email", "無"))    # 無

修改字典#

新增與修改#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
person = {"name": "Alice", "age": 25}

# 修改既有的值
person["age"] = 26
print(person)  # {'name': 'Alice', 'age': 26}

# 新增鍵值對
person["city"] = "Taipei"
print(person)  # {'name': 'Alice', 'age': 26, 'city': 'Taipei'}

# update():批次更新
person.update({"age": 27, "email": "alice@example.com"})
print(person)
# {'name': 'Alice', 'age': 27, 'city': 'Taipei', 'email': 'alice@example.com'}

刪除#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
person = {"name": "Alice", "age": 25, "city": "Taipei"}

# pop():刪除並回傳值
age = person.pop("age")
print(age)     # 25
print(person)  # {'name': 'Alice', 'city': 'Taipei'}

# pop() 可指定預設值,避免 KeyError
result = person.pop("email", "不存在")
print(result)  # 不存在

# del:直接刪除
del person["city"]
print(person)  # {'name': 'Alice'}

# clear():清空字典
person.clear()
print(person)  # {}

遍歷字典#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
scores = {"Alice": 85, "Bob": 92, "Charlie": 78}

# 遍歷鍵
for name in scores:
    print(name)

# 遍歷值
for score in scores.values():
    print(score)

# 同時遍歷鍵和值(最常用)
for name, score in scores.items():
    print(f"{name}{score} 分")

# 遍歷鍵(明確寫法)
for name in scores.keys():
    print(name)

查詢操作#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
person = {"name": "Alice", "age": 25, "city": "Taipei"}

# 是否存在(預設判斷鍵)
print("name" in person)       # True
print("email" in person)      # False

# 是否存在於值
print(25 in person.values())  # True

# 取得所有鍵、值、鍵值對
print(list(person.keys()))    # ['name', 'age', 'city']
print(list(person.values()))  # ['Alice', 25, 'Taipei']
print(list(person.items()))   # [('name', 'Alice'), ('age', 25), ('city', 'Taipei')]

# 長度
print(len(person))  # 3

setdefault() 與 defaultdict#

setdefault():不存在時設定預設值#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
person = {"name": "Alice"}

# 鍵不存在時設定,並回傳值
email = person.setdefault("email", "unknown@example.com")
print(email)   # unknown@example.com
print(person)  # {'name': 'Alice', 'email': 'unknown@example.com'}

# 鍵已存在時不覆蓋
person.setdefault("name", "Bob")
print(person["name"])  # Alice(未被覆蓋)

計數模式#

1
2
3
4
5
6
7
8
text = "hello world hello python world hello"
word_count = {}

for word in text.split():
    word_count[word] = word_count.get(word, 0) + 1

print(word_count)
# {'hello': 3, 'world': 2, 'python': 1}

字典推導式#

字典推導式(Dict Comprehension)語法與串列推導式類似,差別在於用大括號,且要同時指定,中間用冒號 : 分隔:

{鍵運算式: 值運算式 for 變數 in 可迭代物件}
{鍵運算式: 值運算式 for 變數 in 可迭代物件 if 條件}

基本形式:從序列建立字典#

傳統寫法:

1
2
3
4
squares = {}
for x in range(1, 6):
    squares[x] = x ** 2
print(squares)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

用字典推導式改寫:

1
2
squares = {x: x ** 2 for x in range(1, 6)}
print(squares)  # {1: 1, 2: 4, 3: 9, 4: 16, 5: 25}

加入條件:只保留符合條件的項目#

1
2
3
4
5
6
7
8
# 只保留偶數的平方
even_squares = {x: x ** 2 for x in range(1, 11) if x % 2 == 0}
print(even_squares)  # {2: 4, 4: 16, 6: 36, 8: 64, 10: 100}

# 過濾掉分數不及格的學生
scores = {"Alice": 85, "Bob": 55, "Charlie": 92, "David": 48}
passed = {name: score for name, score in scores.items() if score >= 60}
print(passed)  # {'Alice': 85, 'Charlie': 92}

兩個串列合併成字典#

配合 zip() 把名稱串列和數值串列對應成字典:

1
2
3
4
5
names  = ["Alice", "Bob", "Charlie"]
scores = [85, 92, 78]

score_map = {name: score for name, score in zip(names, scores)}
print(score_map)  # {'Alice': 85, 'Bob': 92, 'Charlie': 78}

轉換現有字典的值#

對字典的每個值做運算,鍵保持不變:

1
2
3
4
5
prices = {"apple": 30, "banana": 15, "cherry": 25}

# 所有價格打八折
discounted = {item: price * 0.8 for item, price in prices.items()}
print(discounted)  # {'apple': 24.0, 'banana': 12.0, 'cherry': 20.0}

反轉字典(鍵值互換)#

1
2
3
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'}

⚠️ 反轉時,原始字典的值必須是可雜湊(hashable)的型別(如整數、字串)才能當新鍵;若值有重複,後面的鍵會覆蓋前面的。


巢狀字典#

字典的值可以是另一個字典:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
students = {
    "Alice": {"age": 20, "score": 85, "city": "Taipei"},
    "Bob":   {"age": 22, "score": 92, "city": "Kaohsiung"},
    "Charlie": {"age": 21, "score": 78, "city": "Taichung"},
}

# 存取巢狀值
print(students["Alice"]["score"])  # 85

# 遍歷
for name, info in students.items():
    print(f"{name}{info['city']}):{info['score']} 分")

合併字典(Python 3.9+)#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
defaults = {"color": "blue", "size": "M", "quantity": 1}
custom = {"color": "red", "quantity": 5}

# 合併(custom 的值覆蓋 defaults)
merged = defaults | custom
print(merged)
# {'color': 'red', 'size': 'M', 'quantity': 5}

# 原地更新
defaults |= custom
print(defaults)
# {'color': 'red', 'size': 'M', 'quantity': 5}

實戰範例#

統計選票#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
votes = ["Alice", "Bob", "Alice", "Charlie", "Bob", "Alice", "Bob"]

tally = {}
for vote in votes:
    tally[vote] = tally.get(vote, 0) + 1

winner = max(tally, key=tally.get)
print(f"得票統計:{tally}")
print(f"勝選者:{winner}")
# 得票統計:{'Alice': 3, 'Bob': 3, 'Charlie': 1}

分組資料#

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
students = [
    {"name": "Alice", "city": "Taipei"},
    {"name": "Bob", "city": "Kaohsiung"},
    {"name": "Charlie", "city": "Taipei"},
    {"name": "David", "city": "Kaohsiung"},
]

by_city = {}
for s in students:
    city = s["city"]
    by_city.setdefault(city, []).append(s["name"])

for city, names in by_city.items():
    print(f"{city}{', '.join(names)}")
# Taipei:Alice, Charlie
# Kaohsiung:Bob, David