Python bài 17: Iterable, iterator, generator và yield
- 18-10-2026
- Toanngo92
- 0 Comments
Giáo trình Python miễn phí · Chương 9/12: Iterator, generator và decorator · Bài 17/24.
Mục lục
Mục tiêu bài học
Phân biệt đối tượng có thể duyệt, bộ duyệt và generator; chọn cách xử lý dữ liệu phù hợp bộ nhớ.
Ba khái niệm có liên quan nhưng khác nhau
Iterable là đối tượng có thể lấy iterator từ nó, ví dụ list, tuple hoặc chuỗi. Iterator giữ trạng thái duyệt, cung cấp phần tử tiếp theo qua next() và phát sinh StopIteration khi hết. Vòng for sử dụng cơ chế này để duyệt và tự dừng.
Hàm có yield là generator function. Gọi nó tạo generator iterator, chưa thực thi toàn bộ thân hàm ngay. Mỗi lần yêu cầu phần tử tiếp theo, hàm tiếp tục từ chỗ tạm dừng. Đây khác với việc return một list đã chứa toàn bộ kết quả.
bo_duyet = iter(["An", "Bình"])
print(next(bo_duyet))
print(next(bo_duyet))
print(next(bo_duyet, "Đã hết"))
def dem_nguoc(n):
while n > 0:
yield n
n -= 1
g = dem_nguoc(3)
print(next(g))
print(list(g))
print(list(g))
Kết quả:
An Bình Đã hết 3 [2, 1] []
Duyệt một lần và tính toán lười
Generator ở ví dụ trên đã cạn sau khi chuyển phần còn lại thành list. Muốn duyệt lại, tạo generator mới. Đừng vô tình gọi list(g) để in debug rồi mong g vẫn còn nguyên cho bước xử lý sau.
Generator hữu ích khi tạo hoặc đọc từng phần dữ liệu lớn và không cần giữ tất cả kết quả cùng lúc. Nó không tự làm mọi phép tính nhanh hơn. Nếu cuối cùng vẫn list() toàn bộ thì lợi ích tiết kiệm bộ nhớ ở đầu ra có thể không còn.
def diem_dat(ds):
for diem in ds:
if diem >= 5:
yield diem
print(sum(diem_dat([4, 8, 6, 3])))
binh_phuong = (n * n for n in range(1, 5))
print(list(binh_phuong))
Kết quả:
14 [1, 4, 9, 16]
Tự định nghĩa iterator
Một lớp có __iter__ trả về chính nó và __next__ trả từng giá trị có thể là iterator mà không sử dụng yield. Khi hết dữ liệu, __next__ phải raise StopIteration. Cách này hữu ích khi cần nhiều trạng thái hoặc hành vi; với một dãy giá trị đơn giản, generator function thường ngắn và dễ đọc hơn.
Khi xử lý tệp bằng generator, cần chú ý vòng đời tài nguyên: tệp phải còn mở trong lúc đọc. Nếu bỏ dở generator đang giữ tài nguyên, hãy thiết kế cách đóng rõ ràng; không dựa hoàn toàn vào lúc trình thu gom rác hoạt động.
Lỗi thường gặp và lưu ý
- Generator expression dùng ngoặc tròn, list comprehension dùng ngoặc vuông.
- Không coi iterator đã duyệt hết như một collection có thể duyệt lại tùy ý.
Ghi nhớ
Iterable cung cấp bộ duyệt; iterator giữ tiến độ; generator là cách tạo iterator bằng yield. Lựa chọn theo nhu cầu duyệt lại và lượng dữ liệu cần giữ.
