2.30. Biểu thức rút gọn

Một biểu thức rút gọn tạo danh sách, tập hợp, từ điển hoặc generator mới từ một iterable hiện có, trong một biểu thức duy nhất. Đây là sự thay thế cho mẫu thông thường bắt đầu bằng một container rỗng và thêm phần tử trong vòng lặp.

2.30.1. Biểu thức rút gọn danh sách

squares = [x * x for x in range(5)]
print(squares)

Kết quả đầu ra:

[0, 1, 4, 9, 16]

Vòng lặp tương đương viết đầy đủ:

squares = []
for x in range(5):
    squares.append(x * x)

Dạng biểu thức rút gọn là một biểu thức duy nhất xây dựng danh sách tại chỗ. Không có squares = [] và không có .append -- kết quả là giá trị của biểu thức rút gọn.

The expression "[f(x) for x in xs if cond]" annotated: the leading expression is the result, the for clause names the loop variable, the if clause filters which items are kept.

Biểu thức đầu tạo ra mỗi phần tử; mệnh đề for đặt tên biến vòng lặp; một mệnh đề if tùy chọn lọc bỏ các phần tử.

2.30.2. Lọc bằng if

Mệnh đề if tùy chọn chỉ giữ lại các phần tử khớp điều kiện:

evens = [x for x in range(10) if x % 2 == 0]
print(evens)

Kết quả đầu ra:

[0, 2, 4, 6, 8]

Bộ lọc chạy trước biểu thức đầu -- x % 2 == 0 được kiểm tra trước; chỉ các giá trị khớp mới đến x để đưa ra kết quả.

2.30.3. Biểu thức rút gọn dict và set

Cùng cấu trúc hoạt động với dict và set literal.

Một biểu thức rút gọn dict có cặp key: value trước for:

squares = {x: x * x for x in range(5)}
print(squares)

Kết quả đầu ra:

{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}

Một biểu thức rút gọn set sử dụng dấu ngoặc nhọn và một biểu thức đơn:

unique_lengths = {len(w) for w in ["a", "bb", "c", "bb"]}
print(unique_lengths)

Kết quả đầu ra:

{1, 2}

2.30.4. Biểu thức generator

Dấu ngoặc tròn tạo ra một biểu thức generator thay vì danh sách. Các giá trị được tính toán từng cái một, theo yêu cầu:

total = sum(x * x for x in range(1000))

Không bao giờ có danh sách một triệu phần tử được tạo ra. Các giá trị chảy từng cái một vào sum(), hàm này cộng chúng và loại bỏ từng cái khi đi qua.

Biểu thức generator là lựa chọn đúng khi đưa các giá trị vào hàm rút gọn (sum(), max(), any(), all()) hoặc bất kỳ mã tiêu thụ iterator nào -- chúng tiết kiệm bộ nhớ mà danh sách tương đương sẽ sử dụng.

2.30.5. Khi nào không nên dùng biểu thức rút gọn

Biểu thức rút gọn súc tích nhưng không phải lúc nào cũng rõ ràng hơn. Hãy dùng vòng lặp for thông thường khi:

  • Thân vòng lặp cần nhiều hơn một câu lệnh (biểu thức rút gọn chỉ chứa vừa đúng một biểu thức).

  • Thân vòng lặp có hiệu ứng phụ (in ra, ghi vào tệp) -- biểu thức rút gọn dùng để xây dựng một tập hợp, không phải để thực hiện các hành động.

  • Bộ lọc hoặc phép biến đổi có quá nhiều phần đến mức biểu thức rút gọn không còn đọc từ trái sang phải nữa.