List comprehension
Bạn sẽ học được
- Cú pháp comprehension và cách đọc nó thành câu.
- Lọc bằng
if, chọn giá trị bằngif ... else. - Dict comprehension và set comprehension.
- Duyệt nhiều vòng lặp, làm phẳng ma trận.
- Generator expression và giới hạn đọc hiểu.
Khái niệm cốt lõi
Comprehension tạo collection mới từ iterable trong một biểu thức. Dạng cơ bản:
squares = [x * x for x in range(10) if x % 2 == 0]
print(squares)[0, 4, 16, 36, 64]Đọc thành câu: "lấy x * x với mỗi x trong range(10), nếu x chẵn". Ba phần:
| Phần | Trong ví dụ | Vai trò |
|---|---|---|
| Biểu thức | x * x | Giá trị đưa vào list |
| Vòng lặp | for x in range(10) | Nguồn dữ liệu |
| Điều kiện | if x % 2 == 0 | Lọc (tuỳ chọn) |
Tương đương vòng lặp thường:
squares = []
for x in range(10):
if x % 2 == 0:
squares.append(x * x)Comprehension ngắn hơn, nhưng chỉ nên dùng khi biểu thức còn đọc được trong một dòng. Khi có nhiều điều kiện lồng nhau, vòng lặp thường rõ hơn.
if ... else trong biểu thức
Có hai vị trí if khác nhau, rất dễ nhầm:
labels = ["đạt" if s >= 50 else "trượt" for s in [45, 60, 50]]
print(labels)['trượt', 'đạt', 'đạt']if ... else đứng trước for là biểu thức điều kiện — mỗi phần tử luôn được tạo, giá trị phụ thuộc điều kiện. Còn if đứng sau for là bộ lọc — một số phần tử bị bỏ hẳn:
passed = [s for s in [45, 60, 50] if s >= 50]
print(passed)[60, 50]Nếu viết [s if s >= 50 for s in ...] sẽ là SyntaxError: biểu thức ba ngôi cần đủ else. Quy tắc: if sau for thì lọc; if ... else trước for thì chọn giá trị.
Dict và set comprehension
Cùng cú pháp, đổi ngoặc:
rows = [("An", 85), ("Bình", 92)]
print({name: score for name, score in rows}){'An': 85, 'Bình': 92}print(sorted({len(name) for name in ["An", "Bình", "Chi"]}))[2, 3, 4]Dict comprehension cần cặp key: value; khóa trùng sẽ ghi đè, giữ vị trí lần đầu. Set comprehension tự khử trùng, nên đừng dùng nó khi cần đếm số lần.
Nhiều vòng lặp
Có thể lồng nhiều for, đọc từ trái sang phải như vòng ngoài đến vòng trong:
matrix = [[1, 2], [3, 4]]
print([n for row in matrix for n in row])[1, 2, 3, 4]Thêm điều kiện vẫn đặt sau tất cả các for:
matrix = [[1, 2], [3, 4]]
print([n * 2 for row in matrix for n in row if n > 2])[6, 8]Hai for thường vẫn đọc được. Ba for trở lên gần như luôn nên viết thành vòng lặp thường — người đọc phải tự bóc từng lớp.
Generator expression
Đổi [] thành () được generator — không tạo list, sinh từng giá trị khi cần:
print(sum(x * x for x in range(1000)))332833500Generator tiết kiệm bộ nhớ vì không giữ toàn bộ dãy. Khi dùng với sum, max, min, any, all, không cần ngoặc vuông:
numbers = [4, 7, 10, 13]
print(any(n % 2 == 1 for n in numbers))TrueLưu ý generator chỉ duyệt được một lần. Nếu cần dùng lại, tạo list hoặc tạo generator mới.
Hiệu năng và đọc hiểu
Comprehension thường nhanh hơn vòng lặp + append vì chạy trong C, nhưng khác biệt chỉ đáng kể với dữ liệu lớn. Quan trọng hơn là độ rõ:
| Tình huống | Nên dùng |
|---|---|
| Biến đổi đơn giản, một điều kiện | Comprehension |
| Có tác dụng phụ (in, ghi file) | Vòng lặp thường |
| Ba vòng lặp trở lên | Vòng lặp thường |
Cần try/except trong thân | Vòng lặp thường |
| Chỉ tiêu thụ một lần, dữ liệu lớn | Generator expression |
Comprehension không nên chứa tác dụng phụ. [print(x) for x in data] chạy được nhưng tạo list toàn None và bị lint cảnh báo — dùng vòng lặp.
Thực hành
- Tạo list bình phương các số chẵn từ 0 đến 9.
- Tạo nhãn
đạt/trượtbằngif ... elsetrướcfor. - Lọc danh sách điểm từ 50 trở lên bằng
ifsaufor. - Đổi list
(tên, điểm)thành dict. - Làm phẳng ma trận
[[1, 2], [3, 4]]. - Tính tổng bình phương 1000 số đầu bằng generator.
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách sửa |
|---|---|---|
SyntaxError ở if giữa | Thiếu else trong biểu thức ba ngôi | Thêm else hoặc chuyển if ra sau for |
| Kết quả khác mong đợi | Nhầm lọc với chọn giá trị | if sau for lọc; if ... else trước for chọn |
| Dict comprehension lỗi | Thiếu key: value | Viết {k: v for ...} |
| Generator dùng lần hai ra rỗng | Generator chỉ duyệt một lần | Tạo list hoặc generator mới |
| Comprehension quá dài | Nhiều for/if lồng | Chuyển về vòng lặp thường |
List toàn None | Dùng comprehension với print | Dùng vòng lặp cho tác dụng phụ |
NameError trong biểu thức | Biến chỉ có trong vòng lặp | Kiểm tra phạm vi biến |
Tóm tắt
- Comprehension gồm biểu thức +
for+ điều kiện tuỳ chọn. ifsauforđể lọc;if ... elsetrướcforđể chọn giá trị.{}cho dict/set,()cho generator.- Nhiều
forđọc từ ngoài vào trong; quá hai lớp nên dùng vòng lặp. - Generator tiết kiệm bộ nhớ nhưng chỉ dùng một lần.
Use ← → to move between lessons