Dict
Bạn sẽ học được
- Dict lưu cặp khóa–giá trị và tra cứu theo khóa.
[]khácget()ở chỗ nào.- Duyệt
keys,values,itemsvà thứ tự chèn. - Mẫu đếm và nhóm dữ liệu bằng
get/setdefault. - Vì sao khóa phải bất biến và cách tránh
KeyError.
Khái niệm cốt lõi
Dict là bảng ánh xạ từ khóa sang giá trị. Thay vì tìm theo vị trí như list, bạn tìm theo tên:
user = {"name": "An", "age": 28}
print(user["name"])
print(user.get("email"))
print(user.get("email", "chưa có"))An
None
chưa cóBa cách đọc khác nhau rất quan trọng:
| Cách đọc | Khi khóa có | Khi khóa không có |
|---|---|---|
user["email"] | Trả giá trị | Ném KeyError |
user.get("email") | Trả giá trị | Trả None |
user.get("email", "chưa có") | Trả giá trị | Trả giá trị mặc định |
Dùng [] khi khóa bắt buộc phải có — lỗi sớm giúp phát hiện dữ liệu hỏng. Dùng get() khi khóa có thể thiếu và bạn có cách xử lý. Đừng bọc mọi truy cập trong try/except KeyError; get rõ ý hơn.
Tra cứu theo khóa trung bình là O(1) nhờ bảng băm, nhanh hơn nhiều so với tìm trong list O(n).
Thêm, sửa, xoá
user = {"name": "An", "age": 28}
user["age"] = 29
user["city"] = "Hà Nội"
print(user){'name': 'An', 'age': 29, 'city': 'Hà Nội'}Gán vào khóa đã có là sửa; khóa mới là thêm. Dict giữ thứ tự chèn từ Python 3.7: sửa age không đổi vị trí của nó.
user = {"name": "An", "age": 28}
print(list(user))
print("age" in user, "email" in user)
print(len(user))['name', 'age']
True False
2in kiểm tra khóa, không kiểm tra giá trị. Muốn kiểm tra giá trị, dùng "An" in user.values() — O(n).
Xoá bằng del hoặc pop:
user = {"name": "An", "age": 28, "city": "Hà Nội"}
age = user.pop("age")
print(age, user)
del user["city"]
print(user)28 {'name': 'An', 'city': 'Hà Nội'}
{'name': 'An'}pop trả giá trị bị xoá và nhận mặc định: user.pop("phone", None) không ném lỗi. del ném KeyError nếu khóa không tồn tại.
Duyệt dict
user = {"name": "An", "age": 29, "city": "Hà Nội"}
for key, value in user.items():
print(key, "=", value)name = An
age = 29
city = Hà Nội| Cách duyệt | Nhận được |
|---|---|
for k in user | Khóa |
for v in user.values() | Giá trị |
for k, v in user.items() | Cả hai |
items() là cách chuẩn khi cần cả khóa và giá trị. Không nên for k in user: print(k, user[k]) — chậm hơn và dài hơn.
Giống list, không sửa dict đang duyệt. Thêm/xoá khóa trong lúc lặp ném RuntimeError: dictionary changed size during iteration. Tạo danh sách khóa trước (for k in list(user):) hoặc xây dict mới.
Mẫu đếm
Đây là ứng dụng phổ biến nhất của dict trong phân tích dữ liệu:
votes = ["A", "B", "A", "C", "A"]
counts = {}
for v in votes:
counts[v] = counts.get(v, 0) + 1
print(counts){'A': 3, 'B': 1, 'C': 1}counts.get(v, 0) trả 0 khi chưa có khóa, nên lần đầu gặp v sẽ gán 1. Đây là lý do get có mặc định quan trọng: nếu viết counts[v] += 1, lần đầu sẽ ném KeyError.
Trong thư viện chuẩn có collections.Counter làm đúng việc này:
from collections import Counter
print(Counter(votes))Counter({'A': 3, 'B': 1, 'C': 1})Khi học, viết tay bằng get để hiểu cơ chế; trong dự án thật, Counter ngắn và tối ưu hơn.
Mẫu nhóm
setdefault(key, default) trả giá trị hiện có; nếu khóa chưa có thì gán default rồi trả nó. Kết hợp với append cho mẫu nhóm:
rows = [("An", "SQL"), ("Bình", "Python"), ("An", "Python")]
by_name = {}
for name, skill in rows:
by_name.setdefault(name, []).append(skill)
print(by_name){'An': ['SQL', 'Python'], 'Bình': ['Python']}Cùng kết quả có thể viết bằng defaultdict(list):
from collections import defaultdict
by_name = defaultdict(list)
for name, skill in rows:
by_name[name].append(skill)Khác biệt: defaultdict tự tạo list khi truy cập khóa thiếu, kể cả khi chỉ đọc. Điều này tiện nhưng có thể âm thầm thêm khóa rỗng — cẩn thận khi kiểm tra len.
Khóa phải bất biến
Khóa dict phải hashable: số, chuỗi, tuple chỉ chứa giá trị bất biến. List thì không:
{["a"]: 1}TypeError: unhashable type: 'list'Muốn dùng cặp giá trị làm khóa, dùng tuple: {(10.5, 106.7): "Hà Nội"}. Nếu cần khóa phức tạp hơn, chuyển sang chuỗi hoặc frozenset.
Thực hành
- Tạo dict thông tin một người, đọc bằng
[],get()vàget()có mặc định. - Thêm khóa mới, sửa khóa cũ, kiểm tra thứ tự bằng
list(d). - Duyệt bằng
items()và inkey = value. - Đếm số lần xuất hiện trong một list bằng
get(v, 0) + 1. - Nhóm
(tên, kỹ năng)bằngsetdefault. - Thử dùng list làm khóa và đọc
TypeError.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
KeyError: 'email' | Khóa không tồn tại | Dùng get hoặc kiểm tra in |
TypeError: unhashable type | Dùng list làm khóa | Đổi sang tuple/chuỗi |
RuntimeError: dictionary changed size | Thêm/xoá khi đang duyệt | Duyệt trên list(d) hoặc tạo dict mới |
in không tìm thấy giá trị | in kiểm tra khóa | Dùng in d.values() |
Đếm ra KeyError | Dùng d[k] += 1 lần đầu | d[k] = d.get(k, 0) + 1 |
| Dict không giữ thứ tự | Python cũ (< 3.7) | Nâng phiên bản; hiện đại đã giữ |
pop lỗi khóa thiếu | Không truyền mặc định | d.pop(k, None) |
Tóm tắt
- Dict ánh xạ khóa → giá trị; tra cứu O(1) theo khóa.
[]némKeyError;gettrảNonehoặc mặc định.items()để duyệt cả khóa và giá trị; thứ tự chèn được giữ.get(v, 0) + 1để đếm,setdefaultđể nhóm.- Khóa phải hashable; không sửa dict khi đang duyệt.
Use ← → to move between lessons