Iterators

Python SELF VI
Mức độ, Bài học
Có sẵn

5.1 Iterable và Iterator

Như bạn đã biết, iterators là các đối tượng thực hiện giao thức của iterator, cho phép lần lượt nhận các phần tử từ một tập hợp. Iterators được sử dụng rộng rãi trong Python để duyệt qua các phần tử của các chuỗi như danh sách, tuple và chuỗi.

Xem cách iterator hoạt động và cách sử dụng chúng.

Đối tượng có thể lặp (Iterable)

Để một đối tượng có thể được duyệt qua bằng vòng lặp for, nó phải là một đối tượng có thể lặp – Iterable. Điều này có nghĩa là đối tượng của chúng ta phải thực thi phương thức __iter__(), trả về một đối tượng-iterator.

Đối tượng-iterator (Iterator)

Đây là một đối tượng đặc biệt, có hàm __next__() để trả về phần tử tiếp theo trong chuỗi. Khi hết các phần tử, phương thức __next__() sẽ gọi ra ngoại lệ StopIteration để ngừng việc lặp.

Iterator cũng phải thực thi phương thức __iter__(), trả về chính iterator.

Ví dụ sử dụng các hàm tích hợp của Python

Trong ví dụ này, danh sách numbers là một đối tượng có thể lặp. Chúng ta nhận được iterator bằng cách dùng hàm iter() và sử dụng hàm next() để duyệt qua các phần tử cho đến khi ngoại lệ StopIteration được gọi ra.


# Đối tượng có thể lặp
numbers = [1, 2, 3, 4, 5]
            
# Nhận iterator từ đối tượng có thể lặp
iterator = iter(numbers)
            
# Sử dụng iterator để duyệt qua các phần tử
try:
    while True:
        number = next(iterator)
        print(number)
except StopIteration:
    pass
        

Đây là những gì xảy ra khi bạn viết code kiểu:


# Đối tượng có thể lặp
numbers = [1, 2, 3, 4, 5]
            
for number in numbers:
    print(number)
        

5.2 Bản chất của iterator

Iterator là một đối tượng giúp chúng ta lần lượt duyệt qua một nhóm các phần tử. Cách thực hiện của nó có thể rất khác nhau. Hãy viết một class của mình, trong đó thực hiện tất cả các yêu cầu dành cho iterator.

Bước 1. Bắt đầu tạo class của mình

Để nó lần lượt trả về các số từ start đến end


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        

Bước 2. Hỗ trợ hàm __iter__

Bây giờ chúng ta cần thêm hàm __iter__, sẽ trả về đối tượng-iterator, trong đó sẽ gọi hàm __next__(). Chúng ta sẽ trả về tham chiếu đến chính đối tượng của mình - điều này không bị cấm.


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        

Bước 3. Hỗ trợ hàm __next__

Bây giờ cần thêm vào đối tượng iterator của chúng ta hàm __next__, hàm sẽ trả về phần tử tiếp theo trong danh sách của chúng ta. Chúng ta chỉ cần sử dụng biến current:


def __next__(self):
    current = self.current
    self.current += 1
    return current
        

Bước 4. Dừng iterator

Nếu iterator đã trả về hết các giá trị dự kiến, nó phải ném ra ngoại lệ StopIteration. Hãy sửa một chút hàm cuối cùng của chúng ta:


def __next__(self):
    if self.current >= self.end: raise StopIteration
    current = self.current
    self.current += 1
    return current
        

Tuyệt. Bây giờ có thể sử dụng iterator của chúng ta. Đây là ví dụ của toàn bộ mã của chúng ta:


class MyIterator:
    def __init__(self, start, end):
        self.current = start
        self.end = end
        
    def __iter__(self):
        return self
        
    def __next__(self):
        if self.current >= self.end:
            raise StopIteration
        current = self.current
        self.current += 1
        return current
        
# Tạo một instance của iterator tùy chỉnh
my_iter = MyIterator(1, 5)
        
# Sử dụng iterator để duyệt qua các phần tử
for num in my_iter:
    print(num)

5.3 Iterator chính xác

Iterator từ ví dụ trước không tốt ở đâu? Đúng, nó là một iterator, nó hoạt động, nhưng nó quá đơn giản. Không thể đồng thời duyệt qua một tập hợp các phần tử bằng nhiều iterators khác nhau.

Đúng hơn là viết mã trả về không phải tham chiếu đến chính nó trong phương thức __iter__, mà là một đối tượng riêng biệt, sẽ trả về chính xác tất cả các phần tử.

Ví dụ:


class MyIterable:
    def __init__(self, data):
        self.data = data
    
    def __iter__(self):
        return MyIterator(self.data)
    
class MyIterator:
    def __init__(self, data):
        self.data = data
        self.index = 0
    
    def __iter__(self):
        return self
    
    def __next__(self):
        if self.index >= len(self.data):
            raise StopIteration
        item = self.data[self.index]
        self.index += 1
        return item
    
# Sử dụng
my_iterable = MyIterable([1, 2, 3, 4])
for item in my_iterable:
    print(item)
    

Trong ví dụ này, chúng ta có hai lớp — lớp đầu tiên truyền một tập hợp, mà chúng ta sẽ duyệt qua iterator. Còn lớp thứ hai — chính là iterator, trả về các phần tử của tập hợp trong phương thức next(). Nó cũng khá đơn giản, nhưng đây là cách đúng để thêm iterator vào trong các lớp của bạn.

2
Nhiệm vụ
Python SELF VI, mức độ, bài học
Đã khóa
Tạo một iterator đơn giản
Tạo một iterator đơn giản
2
Nhiệm vụ
Python SELF VI, mức độ, bài học
Đã khóa
Bộ lặp cho collection
Bộ lặp cho collection
1
Khảo sát/đố vui
, cấp độ , bài học
Không có sẵn
Module và package
Module và package
Bình luận
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION