Hàm sinh Python: Đây là gì?

By khoanc, at: 11:02 Ngày 03 tháng 11 năm 2023

Thời gian đọc ước tính: __READING_TIME__ minutes

Python Generator: What is this?
Python Generator: What is this?

1. Generator là gì?

 

Một generator trong Python là một loại iterable đặc biệt cho phép bạn lặp qua một chuỗi các phần tử tiềm năng rất lớn mà không cần lưu giữ toàn bộ chuỗi trong bộ nhớ. Không giống như danh sách hoặc bộ tuple, generator không lưu trữ tất cả các giá trị của chúng cùng một lúc. Thay vào đó, chúng tạo ra các giá trị khi bạn lặp qua chúng. Generator được định nghĩa bằng các hàm có từ khóa yield.

 

2. Tại sao Generator lại quan trọng?

 

Generator rất cần thiết vì một số lý do:
 

  • Hiệu quả bộ nhớ: Generator hiệu quả về bộ nhớ vì chúng không tải toàn bộ chuỗi vào bộ nhớ. Điều này rất quan trọng khi làm việc với các tập dữ liệu lớn.
     

  • Đánh giá lười: Chúng hỗ trợ đánh giá lười, có nghĩa là các giá trị chỉ được tạo ra khi cần thiết, giảm thời gian tính toán và sử dụng tài nguyên.
     

  • Các chuỗi vô hạn: Generator có thể biểu diễn các chuỗi vô hạn, cho phép bạn làm việc với các luồng dữ liệu không có điểm cuối xác định.
     

  • Đơn giản hóa mã: Chúng làm cho mã ngắn gọn và dễ đọc hơn bằng cách tách logic tạo dữ liệu khỏi logic lặp.
     

Một trường hợp sử dụng quan trọng của generator là khi bạn đọc một tệp lớn từng dòng một. 

Cách tiếp cận bình thường sẽ là

 

with open(filename) as file:
    lines = [line.rstrip() for line in file]


điều này rất chậm và có thể gây ra sự cố bộ nhớ. Thay vào đó, chúng ta nên sử dụng phương pháp hiệu năng cao hơn bên dưới

 

def read_in_chunks(file_object, chunk_size=1024):
    """Hàm lười (generator) để đọc tệp từng phần.
    Kích thước phần mặc định: 1k."""
    while True:
        data = file_object.read(chunk_size)
        if not data:
            break
        yield data

with open('really_big_file.dat') as f:
    for piece in read_in_chunks(f):
        process_data(piece)

 

3. Cách sử dụng Generator

 

Để tạo và sử dụng một generator:
 

  • Định nghĩa một hàm chứa từ khóa yield.
     
  • Khi hàm được gọi, nó không thực thi ngay lập tức mà trả về một đối tượng generator.
     
  • Các giá trị được tạo ra bằng từ khóa yield bên trong hàm, và trạng thái của hàm được giữ lại giữa các lần gọi.

 

def number_generator(n):
    for i in range(n):
        yield i

gen = number_generator(5)
for num in gen:
    print(num)  # Output: 0, 1, 2, 3, 4

 

4. Vấn đề với Generator

 

Mặc dù generator cung cấp hiệu quả bộ nhớ, nhưng chúng có thể gây ra các vấn đề về hiệu năng:

 

  • Truy cập chậm hơn: Truy cập các phần tử trong một generator có thể chậm hơn so với truy cập các phần tử trong một danh sách vì mỗi giá trị được tạo động.
     

  • Lặp lại một lần: Generator thường chỉ sử dụng một lần. Sau khi generator đã được dùng hết, bạn không thể tua lại nó, không giống như danh sách mà bạn có thể lặp lại nhiều lần.
     

  • Quản lý trạng thái: Quản lý trạng thái của một generator và hiểu khi nào nó được dùng hết có thể khó khăn.
     

  • Trường hợp sử dụng hạn chế: Generator phù hợp nhất với dữ liệu tuần tự, làm cho chúng ít phù hợp hơn với các tác vụ truy cập ngẫu nhiên hoặc thao tác dữ liệu phức tạp.
     

 

5. Các thư viện sử dụng Generator rộng rãi để tăng hiệu năng

 

  • Thư viện chuẩn Python: Thư viện chuẩn của Python bao gồm một số hàm và mô-đun tích hợp trả về generator, chẳng hạn như range(), zip()enumerate().
     

  • Các thư viện của bên thứ ba: Các thư viện như itertools, asyncioDask sử dụng generator rộng rãi để cung cấp khả năng xử lý dữ liệu hiệu năng cao và khả năng lập trình không đồng bộ.

 

6. Sự khác biệt giữa Iterator và Generator

 

Generator là một loại iterator, nhưng có những điểm khác biệt chính:
 

  • Iterator: Iterator là một khái niệm tổng quát hơn và có thể là một đối tượng tuân theo giao thức iterator (với các phương thức __iter__()__next__()). Iterator có thể được tạo bằng các lớp và không nhất thiết phải liên quan đến đánh giá lười.
     

  • Generator: Generator là một loại iterator cụ thể được tạo bằng các hàm có từ khóa yield. Chúng được thiết kế rõ ràng để đánh giá lười và thường hiệu quả hơn về bộ nhớ.
     

Ví dụ về Iterator

class MyIterator:
    def __init__(self, max_val):
        self.max_val = max_val
        self.current = 0

    def __iter__(self):
        return self

    def __next__(self):
        if self.current < self.max_val:
            result = self.current
            self.current += 1
            return result
        else:
            raise StopIteration

my_iter = MyIterator(5)
for num in my_iter:
    print(num)  # Output: 0, 1, 2, 3, 4

 

Ví dụ về Generator

def number_generator(n):
    for i in range(n):
        yield i

gen = number_generator(5)
for num in gen:
    print(num)  # Output: 0, 1, 2, 3, 4

 

Tóm lại, generator là một dạng chuyên biệt của iterator, được thiết kế để hiệu quả về bộ nhớ và đánh giá lười, làm cho chúng lý tưởng cho dữ liệu tuần tự và các tập dữ liệu lớn.

Tag list:
- Python
- Yield
- Performance Optimization
- Generator
- Lazy Evaluation
- Memory Efficiency

Theo dõi

Theo dõi bản tin của chúng tôi và không bao giờ bỏ lỡ những tin tức mới nhất.