Computer >> Hướng Dẫn Máy Tính >  >> Lập Trình >> Python

Cách xử lý iterator song song với ZIP trong Python

Giới thiệu

List comprehension giúp dễ dàng tạo danh sách dẫn xuất từ danh sách nguồn bằng cách áp dụng biểu thức. Ví dụ: nhân mỗi phần tử với 5.


a = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
multiply_by_5 = [x * 5 for x in a]
print(multiply_by_5)  # [5, 10, 15, 20, 25, 30, 35, 40, 45, 50]

Xử lý nhiều iterator cùng lúc với zip()

Giả sử có 2 danh sách cần cộng phần tử tương ứng:


list1 = [100, 200, 300, 400]
list2 = [500, 600, 700, 800]

# Cách dùng vòng lặp
list3 = []
for i in range(len(list1)):
    list3.append(list1[i] + list2[i])
# [600, 800, 1000, 1200]

# Cách dùng zip() - gọn nhẹ hơn
list4 = [(a + b) for a, b in zip(list1, list2)]
print(list4)  # [600, 800, 1000, 1200]

zip() ghép các phần tử cùng chỉ số thành tuple, lặp qua chúng đồng thời.

Vấn đề nghiêm trọng: zip() với iterator độ dài khác nhau


list1.append(1000)  # list1 giờ dài hơn list2
print(len(list1), len(list2))  # 5, 4

list5 = [(a + b) for a, b in zip(list1, list2)]
print(list5)  # [600, 800, 1000, 1200] - phần tử thứ 5 bị mất!

zip() dừng lại khi bất kỳ iterator nào hết. Không ném ngoại lệ → dễ gây bug lặng lẽ trong production.

Giải pháp: itertools.zip_longest()

zip_longest tiếp tục lặp cho đến khi tất cả iterator đều hết. Phần tử thiếu được điền bằng None (hoặc giá trị fillvalue tuỳ chỉnh).


from itertools import zip_longest

list6 = []
for a, b in zip_longest(list1, list2):
    if b is None:
        print("  << xử lý khi list2 hết >>")
    elif a is None:
        print("  << xử lý khi list1 hết >>")
    else:
        list6.append(a + b)

print(list6)  # [600, 800, 1000, 1200]

Kết luận

  • zip() rất tiện để lặp song song nhiều iterator.
  • zip() hoạt động khác khi iterator độ dài khác nhau (dừng sớm, không báo lỗi).
  • Cần iterator độ dài khác nhau → dùng zip_longest() từ itertools.