Học bằng cách đọc theo thứ tự

List Comprehension và Dict / Set / Generator Expression — Xây dựng collection trong một dòng

Học comprehension trong Python để dựng list, dict, set và generator expression chỉ trong một dòng code rõ ràng.

Trong bài trước về all() / any(), bạn đã thấy cách phán đoán cả một collection cùng lúc. Lần này, bạn sẽ tiến thêm một bước và tìm hiểu cú pháp mạnh mẽ để xây dựng chính collection đó trong một dòngcomprehension.

Chúng ta sẽ bắt đầu với list comprehension, thêm bộ lọc bằng if, xem các biến thể dictset, rồi kết thúc với generator expression giúp tiết kiệm bộ nhớ.

Cơ bản về List Comprehension — Gói gọn vòng for vào một dòng

Python có cú pháp một dòng để xây dựng list: [biểu_thức for biến in iterable]. Đây gọi là list comprehension.

Nó là lối tắt cho mẫu vòng for bắt đầu từ list rỗng và gọi append() lặp lại, và nó tỏa sáng khi bạn muốn áp dụng cùng một phép biến đổi cho mọi phần tử và tạo ra một list mới.

Luồng của một list comprehension
items =[10, 20, 30][x * 2for x in items][20, 40, 60]với mỗi phần tửlist mới

[biểu_thức for biến in iterable] tạo ra một list mới với mỗi phần tử đã được biến đổi bởi biểu thức. Đây là phiên bản một dòng của việc viết vòng for với append.

# Dùng vòng for
result = []
for price in [100, 250, 480]:
    result.append(int(price * 1.1))
print(result)   # [110, 275, 528]

# Tương tự dưới dạng list comprehension
prices = [100, 250, 480]
tax_included = [int(p * 1.1) for p in prices]
print(tax_included)   # [110, 275, 528]

# Lấy độ dài chuỗi cũng chỉ trong một dòng
names = ["Alice", "Bob", "Charlotte"]
lengths = [len(n) for n in names]
print(lengths)   # [5, 3, 9]

Xây dựng một list mới chứa giá sản phẩm với thuế 10% đã được cộng vào, dùng list comprehension.

① Khai báo prices = [100, 250, 480, 1200].

② Dùng list comprehension [int(p * 1.1) for p in prices] để xây dựng list đã bao gồm thuế và gán cho tax_included.

③ In kết quả với print(tax_included).

(Khi đáp án đúng, phần giải thích sẽ hiện ra.)

Python Editor

Chạy code để xem đầu ra

Lọc với if — Comprehension có điều kiện

Thêm if điều_kiện sau for và chỉ những phần tử thỏa mãn điều kiện mới có mặt trong list mới. Dạng cú pháp là [biểu_thức for biến in iterable if điều_kiện].

Việc viết phép biến đổi và bộ lọc trên cùng một dòng là điều khiến list comprehension trở nên gọn gàng — việc lấy ra "chỉ những phần tử khớp" trở thành một dòng ngắn, dễ đọc.

Cách comprehension có điều kiện phán đoán mỗi phần tử
trong forprices =[80, 250, 120, 480][p for p in pricesif p >= 200]Kết quả[250, 480]p = 8080 >= 200False→ bỏ quap = 250250 >= 200True→ giữ lạip = 120120 >= 200False→ bỏ quap = 480480 >= 200True→ giữ lạiáp dụnghoàn thành
Mỗi phần tử được lấy ra theo thứ tự và phán đoán bằng if p >= 200 từng cái một. Các phần tử True (giữ lại) sẽ vào list mới; các phần tử False (bỏ qua) sẽ bị loại bỏ.
# Lấy ra chỉ những item >= 200
prices = [80, 250, 120, 480, 95]
premium = [p for p in prices if p >= 200]
print(premium)         # [250, 480]

# Lọc và biến đổi cùng lúc
discounted = [int(p * 0.9) for p in prices if p >= 200]
print(discounted)      # [225, 432]   ← giảm 10%, chỉ với item >= 200

# Lọc và biến đổi trên chuỗi
names = ["Alice", "Bob", "Charlotte", "Ed"]
long_names = [n.upper() for n in names if len(n) >= 5]
print(long_names)      # ['ALICE', 'CHARLOTTE']

Từ dữ liệu tồn kho, lấy ra tên sản phẩm còn ít nhất 1 cái trong kho.

① Khai báo stocks = [("táo", 12), ("chuối", 0), ("cam", 5), ("nho", 0), ("kiwi", 3)].

② Dùng [name for name, count in stocks if count > 0] để xây dựng list các tên sản phẩm còn hàng và gán cho available (tuple unpacking cho phép bạn ràng buộc namecount cùng lúc).

③ In kết quả với print(available).

Python Editor

Chạy code để xem đầu ra

Dict Comprehension và Set Comprehension

Đổi dấu ngoặc vuông [ ] của list comprehension sang dấu ngoặc nhọn { } thì bạn có set comprehension.

Tiến thêm một bước với {key: value for ...} và dấu hai chấm biến nó thành dict comprehension. Cú pháp for ... in ... là giống hệt — chỉ có hình dạng của collection đầu ra thay đổi, và sự linh hoạt đó là điều khiến comprehension trở nên hữu dụng đến vậy.

Luồng của một dict comprehension
pairs =[("táo", 120), ("cam", 80)]{name: pricefor name, pricein pairs}{"táo": 120, "cam": 80}unpackdict mới

{key: value for ...} xây dựng một dict các cặp. Từ một list các tuple (tên, giá) bạn có thể xây dựng một bảng tra cứu "tên → giá" trong một dòng.

# Dict comprehension: xây dựng bảng tra cứu tên → giá
pairs = [("táo", 120), ("cam", 80), ("chuối", 60)]
price_lookup = {name: price for name, price in pairs}
print(price_lookup)
# {'táo': 120, 'cam': 80, 'chuối': 60}

# Xây dựng lại dict với giá đã bao gồm thuế
tax_included = {name: int(price * 1.1) for name, price in pairs}
print(tax_included)
# {'táo': 132, 'cam': 88, 'chuối': 66}

# Set comprehension: lấy ra các tag duy nhất (không trùng lặp)
tags = ["sale", "new", "sale", "limited", "new"]
unique = {t for t in tags}
print(unique)   # {'sale', 'new', 'limited'} (thứ tự phụ thuộc vào cài đặt)

Kết hợp zip() với dict comprehension

Khi bạn có hai list song song như namesprices và muốn một dict, {n: p for n, p in zip(names, prices)} là cách rất gọn. zip() đi qua các list đồng bộ với nhau nên bạn có thể xây dựng key và value cùng lúc.

Từ một list các tuple (tên, giá), xây dựng một dict sản phẩm → giá đã bao gồm thuế trong một dòng.

① Khai báo pairs = [("táo", 120), ("cam", 80), ("chuối", 60), ("kiwi", 200)].

② Dùng dict comprehension {name: int(price * 1.1) for name, price in pairs} để xây dựng bảng tra cứu đã bao gồm thuế và gán cho tax_lookup.

③ In kết quả với print(tax_lookup).

Python Editor

Chạy code để xem đầu ra

Generator Expression — Đổi dấu ngoặc vuông sang ngoặc đơn

Đổi dấu ngoặc vuông [ ] của list comprehension sang dấu ngoặc đơn ( ) thì bạn có generator expression. Khác với list, nó không vật chất hóa toàn bộ phần tử trong bộ nhớ — nó tính toán chỉ những gì bạn cần, khi bạn cần (lazy evaluation).

Bạn có thể truyền nó trực tiếp cho sum() / max() / min() / any() v.v., điều này giữ mức sử dụng bộ nhớ thấp khi tổng hợp dữ liệu lớn. Phần đi sâu đầy đủ nằm trong bài về hàm generator ở phía sau.

Cú phápKiểu kết quảĐặc điểm
[x for x in items]listGiữ toàn bộ trong bộ nhớ
{x for x in items}setKhông trùng lặp, giữ toàn bộ
{k: v for k, v in items}dictCặp khóa: giá trị, giữ toàn bộ
(x for x in items)generatorChỉ phần tử hiện tại, lazy
# Dấu ngoặc đơn tạo ra generator expression
prices = [100, 250, 480, 1200]
gen = (int(p * 1.1) for p in prices)
print(type(gen))   # <class 'generator'>

# Truyền thẳng cho sum() (có thể bỏ dấu ngoặc đơn ngoài cùng)
total_tax = sum(int(p * 1.1) for p in prices)
print(total_tax)   # 2233

# Mẹo tương tự với max() / min()
max_tax = max(int(p * 1.1) for p in prices)
print(max_tax)     # 1320

Chọn theo trường hợp sử dụng: "toàn bộ cùng lúc?" hay "từng cái một?"

Nếu bạn muốn có toàn bộ trong tay dưới dạng list, dùng [ ] (list comprehension). Nếu bạn chỉ truyền nó cho sum() / max() để tổng hợp, ( ) (generator expression) là lựa chọn thân thiện với bộ nhớ hơn. Ở quy mô một triệu phần tử, sự khác biệt là rất lớn — generator expression chỉ dùng vài trăm byte.

Cho một list giá sản phẩm, tính tổng giá đã bao gồm thuế bằng cách kết hợp generator expression với sum().

① Khai báo prices = [100, 250, 480, 1200].

② Tính tổng đã bao gồm thuế với sum(int(p * 1.1) for p in prices) và gán cho total (bạn có thể bỏ generator expression trực tiếp vào trong dấu ngoặc đơn của sum()).

③ In kết quả với print(total).

Python Editor

Chạy code để xem đầu ra
QUIZ

Kiểm tra kiến thức

Hãy trả lời từng câu hỏi một.

Câu 1Code này in ra gì?
nums = [1, 2, 3, 4]
result = [n * 10 for n in nums]
print(result)

Câu 2Code này in ra gì?
nums = [1, 2, 3, 4, 5]
result = [n for n in nums if n % 2 == 0]
print(result)

Câu 3Cái nào sau đây tạo ra một dict?