Header ads

Header ads
» » Generator trong Python

Trong bài viết này, Quantrimang sẽ cùng bạn tìm hiểu cách tạo Iterator bằng cách sử dụng Generator trong Python. Generator khác với iterator và các hàm thông thường như thế nào, tại sao ta nên sử dụng nó? Cùng tìm hiểu tất cả qua các nội dung sau.

Generator trong Python

Để xây dựng một iterator, ta cần phải theo dõi khá nhiều bước ví dụ như: triển khai class với phương thức __iter__()__next__(), theo dõi các tình trạng bên trong, StopIteration xảy ra khi không có giá trị nào được trả về...

Generator được dùng để giải quyết các vấn đề này. Generator là cách đơn giản để tạo ra iterator. 

Nói một cách đơn giản, generator là một hàm trả về một đối tượng (iterator) mà chúng ta có thể lặp lại (một giá trị tại một thời điểm). Chúng cũng tạo ra một đối tượng kiểu danh sách, nhưng bạn chỉ có thể duyệt qua các phần tử của generator một lần duy nhất vì generator không lưu dữ liệu trong bộ nhớ mà cứ mỗi lần lặp thì chúng sẽ tạo phần tử tiếp theo trong dãy và trả về phần tử đó.

Làm thể nào để tạo Generator trong Python

Để tạo generator trong Python, bạn sử dụng từ khóa def giống như khi định nghĩa một hàm. Trong generator, dùng câu lệnh yield để trả về các phần tử thay vì câu lệnh return như bình thường. 

Nếu một hàm chứa ít nhất một yield (có thể có nhiều yield và thêm cả return) thì chắc chắn đây là một hàm generator. Trong trường hợp này, cả yieldreturn sẽ trả về các giá trị từ hàm.

Điều khác biệt ở đây là return sẽ chấm dứt hoàn toàn một hàm, còn yield sẽ chỉ tạm dừng các trạng thái bên trong hàm và sau đó vẫn có thể tiếp tục khi được gọi trong các lần sau.

Ví dụ, khi bạn gọi phương thức __next__() lần thứ nhất, generator thực hiện các công việc tính toán giá trị rồi gặp từ khóa yield nào thì nó sẽ trả về các phần tử tại ví trí đó, khi bạn gọi phương thức __next__() lần thứ hai thì generator không bắt đầu chạy tại vị trí đầu tiên mà bắt đầu ngay phía sau từ khóa yield thứ nhất. Cứ như thế generator tạo ra các phần tử trong dãy, cho đến khi không còn gặp từ khóa yield nào nữa thì giải phóng exception StopIteration.

Sự khác biệt của hàm generator và hàm thông thường

Đây là một số khác biệt giữa hàm generator và hàm thông thường:

    Dưới đây là một ví dụ để minh họa tất cả các điểm đã nêu ở trên. Chúng ta có một hàm generator có tên my_gen() với một số câu lệnh yield.

    # Hàm generator đơn giản   # Viet boi Quantrimang.com   def my_gen():       n = 1       print('Doan text nay duoc in dau tien')       # Hàm Generator chứa các câu lệnh yield        yield n          n += 1       print('Doan text nay duoc in thu hai')       yield n          n += 1       print('Doan text nay duoc in cuoi cung')       yield n

    Chạy chúng trong Python shell để xem output:

    >>> # Trả về một đối tượng nhưng không bắt đầu thực thi ngay lập tức.   >>> a = my_gen()   >>> # Chúng ta có thể lặp qua các mục bằng cách sử dụng next().   >>> next(a)   Doan text nay duoc in dau tien   1   >>> # Yield sẽ tạm dừng hàm, quyền điều khiển chuyển đến người gọi   >>> # Các biến cục bộ và trạng thái của chúng được ghi nhớ giữa các    lệnh gọi liên tiếp.   >>> next(a)   Doan text nay duoc in thu hai   2   >>> next(a)   Doan text nay duoc in cuoi cung   3   >>> # Cuối cùng, khi hàm kết thúc, StopIteration sẽ xảy ra nếu tiếp    tục gọi hàm.   >>> next(a)   Traceback (most recent call last):   ...   StopIteration   >>> next(a)   Traceback (most recent call last):   ...   StopIteration

    Có thể thấy trong ví dụ trên là giá trị của biến n được ghi nhớ giữa các lần gọi, không giống như các hàm bình thường kết thúc ngay sau mỗi lần gọi.

    Khi bạn gọi phương thức next() lần thứ nhất, generator thực hiện các công việc tính toán giá trị rồi trả về phần tử tại ví trí đó, khi gọi phương thức next() lần thứ hai thì generator không bắt đầu chạy tại vị trí đầu tiên mà bắt đầu ngay phía sau từ khóa yield thứ nhất. Cứ như thế generator tạo ra các phần tử trong dãy, cho đến khi không còn gặp từ khóa yield nào nữa thì giải phóng exception StopIteration.

    Để khởi động lại quá trình, tạo một đối tượng generator khác bằng cách sử dụng đối tượng như a = my_gen().

    Lưu ý: Có thể sử dụng generator trực tiếp cho các vòng lặp for.

    Vòng lặp for lấy một iterator và lặp lại nó bằng hàm next(), tự động kết thúc khi StopIteration xảy ra. 

    # Hàm generator đơn giản   def my_gen():       n = 1       print('Doan text nay duoc in dau tien')       # Hàm Generator chứa câu lệnh yield        yield n          n += 1       print('Doan text nay duoc in thu hai')       yield n          n += 1       print('Doan text nay duoc in cuoi cung')       yield n      # Sử dụng vòng lặp for    for item in my_gen():       print(item)    

    Chạy chương trình, kết quả trả về là:

    Doan text nay duoc in dau tien   1   Doan text nay duoc in thu hai   2   Doan text nay duoc in cuoi cung   3

    Generator với các vòng lặp trong Python

    Ví dụ về generator đảo ngược chuỗi.

    def rev_str(my_str):       length = len(my_str)       for i in range(length - 1,-1,-1):           yield my_str[i]      # Vòng lặp for đảo ngược chuỗi   # Viết bởi Quantrimang.com   # Output:   # o   # l   # l   # e   # h   for char in rev_str("hello"):        print(char)

    Ví dụ này sử dụng hàm range() để lấy chỉ mục theo thứ tự ngược lại trong vòng lặp for.

    Biểu thức generator

    Generator có thể dễ dàng được tạo ra khi sử dụng biểu thức generator.

    Giống như Lambda tạo một hàm vô danh trong Python, generator cũng tạo một biểu thức generator vô danh. Cú pháp tương tự như cú pháp của list comprehension, nhưng dấu ngoặc vuông được thay thế bằng dấu ngoặc tròn.

    List comprehension thì trả về một list, còn biểu thức generator trả về một generator tại một thời điểm khi được yêu cầu. Vì lý do này, biểu thức generator sử dụng ít bộ nhớ hơn, đem lại hiệu quả hiệu suất hơn so với list comprehension tương đương.

    # Khởi tạo danh sách   my_list = [1, 3, 6, 10]      # bình phương mỗi phần tử bằng cách sử dụng list comprehension   # Output: [1, 9, 36, 100]   [x**2 for x in my_list]      # kết quả tương tự khi sử dụng biểu thức generator   # Output: <generator object <genexpr> at 0x0000000002EBDAF8>   (x**2 for x in my_list)

    Có thể thấy ở ví dụ trên, biểu thức generator không tạo ra kết quả cần thiết ngay lập tức mà trả về đối tượng generator, cứ mỗi lần lặp thì chúng sẽ tạo phần tử tiếp theo trong dãy và trả về phần tử đó.

    # Khởi tạo danh sách   my_list = [1, 3, 6, 10]      a = (x**2 for x in my_list)   # Output: 1   print(next(a))      # Output: 9   print(next(a))      # Output: 36   print(next(a))      # Output: 100   print(next(a))      # Output: StopIteration   next(a)

    Biểu thức generator sử dụng bên trong các hàm thì có thể bỏ qua các dấu ngoặc tròn.

    >>> sum(x**2 for x in my_list)   146   >>> max(x**2 for x in my_list)   100

    Tại sao nên sử dụng generator trong Python?

    Việc sử dụng generator sẽ đem lại nhiều tác dụng hấp dẫn.

    1. Đơn giản hóa code, dễ triển khai

    Generator có thể giúp code được triển khai rõ ràng và ngắn gọn hơn so với lớp iterator tương tự. Để minh họa cho việc này, chúng ta sẽ lấy một ví dụ cụ thể.

    class PowTwo:       def __init__(self, max = 0):           self.max = max       def __iter__(self):           self.n = 0           return self       def __next__(self):           if self.n > self.max:               raise StopIteration           result = 2 ** self.n           self.n += 1           return result

    Đoạn code này khá dài. Bây giờ hãy thử sử dụng hàm generator.

    def PowTwoGen(max = 0):       n = 0       while n < max:           yield 2 ** n           n += 1

    Ở đây, generator thực hiện ngắn gọn và gọn gàng hơn nhiều.

    2. Sử dụng ít bộ nhớ

    Một hàm thông thường khi trả về list sẽ lưu toàn bộ list trong bộ nhớ. Trong phần lớn các trường hợp, điều đó là không hay khi phải sử dụng đến dung lượng bộ nhớ lớn đến vậy.

    Generator sẽ sử dụng ít bộ nhớ hơn vì chúng chỉ thực sự tạo kết quả khi được gọi tới, sinh ra một phần tử tại một thời điểm, đem lại hiệu quả nếu chúng ta không có nhu cầu duyệt nó quá nhiều lần.

    3.Tạo ra các list vô hạn

    Generator là phương tiện tuyệt vời để tạo ra một luồng dữ liệu vô hạn. Các luồng vô hạn này không cần lưu trữ toàn bộ trong bộ nhớ vì generator chỉ tạo ra một phần tử tại một thời điểm, nên nó có thể biểu thị luồng dữ liệu vô hạn.

    Ví dụ sau có thể tạo ra tất cả các số chẵn.

    def all_even():       n = 0       while True:           yield n           n += 2

    Nói chung, việc lựa chọn sử dụng generator phụ thuộc nhiều vào thực tế yêu cầu của công việc. Hãy suy nghĩ và lựa chọn cẩn thận để có được lựa chọn tốt nhất cho mình.

    Bài trước: Đối tượng Iterator trong Python

    Bài tiếp: Cách sử dụng Closure trong Python


    Khóa đào tạo Power BI phân tích báo cáo để bán hàng thành công

    Khóa học Lập trình Visual Foxpro 9 - Dành cho nhà quản lý và kế toán

    Khóa học hướng dẫn về Moodle chuyên nghiệp và hay
    Xây dựng hệ thống đào tạo trực tuyến chuyên nghiệp tốt nhất hiện nay.


    Khóa học AutoIt dành cho dân IT và Marketing chuyên nghiệp

    Khóa học hướng dẫn sử dụng Powerpoint từ đơn giản đến phức tạp HIỆU QUẢ
    Khóa học Thiết kế, quản lý dữ liệu dự án chuyên nghiệp cho doanh nghiệp bằng Bizagi
     Khoa hoc hay
    Khóa học Phân tích dữ liệu sử dụng Power Query trong Excel
    Khóa học Phân tích dữ liệu sử dụng TableAU - Chìa khóa thành công!
    Nhấn vào đây để bắt đầu khóa học

    Khóa học "Thiết kế bài giảng điện tử", Video, hoạt hình 
    kiếm tiền Youtube bằng phần mềm Camtasia Studio
    Khóa học HƯỚNG DẪN THIẾT KẾ VIDEO CLIP CHO DÂN MARKETING CHUYÊN NGHIỆP
     Xây dựng website​​​​
    HƯỚNG DẪN THIẾT KẾ QUẢNG CÁO VÀ ĐỒ HỌA CHUYÊN NGHIỆP VỚI CANVA
    Hãy tham gia khóa học để trở thành người chuyên nghiệp. Tuyệt HAY!😲👍
     Khoa hoc hay
    MICROSOFT ACCESS



    GOOGLE SPREADSHEETS phê không tưởng
     Khoa hoc hay
    Khóa hoc lập trình bằng Python tại đây

    Hacker mũ trắng




    Hãy tham gia khóa học để biết mọi thứ

    Để tham gia tất cả các bài học, Bạn nhấn vào đây 
    Khóa học sử dụng Adobe Presenter-Tạo bài giảng điện tử
     Khoa hoc hay

    Khóa học sử dụng Edmodo để dạy và học hiện đại để thành công


    Cập nhật công nghệ từ Youtube tại link: http://congnghe.hocviendaotao.com
    Tham gia nhóm Facebook
    Để tham gia khóa học công nghệ truy cập link: http://thuvien.hocviendaotao.com
    Mọi hỗ trợ về công nghệ email: dinhanhtuan68@gmail.com

    About Học viện đào tạo trực tuyến

    Xinh chào bạn. Tôi là Đinh Anh Tuấn - Thạc sĩ CNTT. Email: dinhanhtuan68@gmail.com .
    - Nhận đào tạo trực tuyến lập trình dành cho nhà quản lý, kế toán bằng Foxpro, Access 2010, Excel, Macro Excel, Macro Word, chứng chỉ MOS cao cấp, IC3, tiếng anh, phần mềm, phần cứng .
    - Nhận thiết kế phần mềm quản lý, Web, Web ứng dụng, quản lý, bán hàng,... Nhận Thiết kế bài giảng điện tử, số hóa tài liệu...
    HỌC VIỆN ĐÀO TẠO TRỰC TUYẾN:TẬN TÂM-CHẤT LƯỢNG.
    «
    Next
    Bài đăng Mới hơn
    »
    Previous
    Bài đăng Cũ hơn