Trình tạo điểm dừng Python

Các từ “yield” và “generator” là những khái niệm chính trong Python và cả hai đều cần nỗ lực nhiều hơn để hiểu ý nghĩa của chúng. Trong bài viết này, tôi sẽ cho bạn biết về mục đích của chúng và tại sao chúng lại hữu ích

Khi chúng ta làm việc với các hàm [còn được gọi là “chương trình con”, quá trình thực thi bắt đầu từ dòng đầu tiên và tiếp tục cho đến khi tìm thấy kết quả trả về, ngoại lệ hoặc kết thúc của hàm. Các chương trình con này chỉ trả lại một giá trị trong khi chúng trả về quyền kiểm soát thực thi. Chúng ta phải làm gì nếu muốn trả về một loạt giá trị thay vì chỉ một giá trị?

Trong Python, trình tạo là các hàm có thể tạo ra một loạt giá trị và chúng có thể bị tạm dừng để sau này lấy lại quyền kiểm soát thực thi

Tại sao chúng ta nên sử dụng máy phát điện?

Hãy xem xét một ví dụ. Giả sử chúng ta muốn giải bài toán sau

Cho một số N, trả về tất cả các số nguyên tố nhỏ hơn N

Sau đây sẽ là một nỗ lực ban đầu đơn giản

Nếu N=100, kết quả của việc thực hiện là

Nếu N là một số lớn, giải pháp này không chỉ mất quá nhiều thời gian để trả về kết quả mà còn có thể chiếm hết bộ nhớ khả dụng. Rõ ràng, sử dụng một danh sách để lấy toàn bộ các số nguyên tố không phải là giải pháp phù hợp. Điều gì sẽ xảy ra nếu thay vì sử dụng một hàm chỉ trả về một danh sách, chúng ta lại tạo một hàm trả về số nguyên tố tiếp theo? . Tức là máy phát điện

Máy phát điện và năng suất

Trình tạo là một hàm trả về một giá trị thông qua từ khóa yield thay vì return. Để lấy giá trị tiếp theo của trình tạo, chúng ta sử dụng chức năng tương tự như đối với trình vòng lặp. tiếp theo[]

Mỗi khi chúng ta gọi next[] trên một trình tạo, trình tạo phải chuyển một giá trị và điều khiển thông qua năng suất. Sao có thể như thế được? . Khi chúng ta gọi next[], trình tạo sẽ tiếp tục thực thi theo trạng thái đã lưu. Nếu chúng ta không gọi next[], trạng thái đã lưu sẽ bị loại bỏ

Hãy xem hàm get_first_primes[n] từ ví dụ sẽ trông như thế nào nếu chúng ta biến nó thành một trình tạo

Nếu trình tạo kết thúc định nghĩa của nó hoặc trả về được thực thi, nó sẽ tăng ngoại lệ StopIteration, điều đó có nghĩa là trình tạo đã cạn kiệt. Khi trình tạo đã hết, khi chúng ta gọi next[], nó sẽ báo lỗi vì chúng ta chỉ có thể lặp qua trình tạo một lần

Chúng tôi sẽ nhận được kết quả sau

Nếu chúng ta muốn một trình tạo không bao giờ hết [nghĩa là không bao giờ hết], chúng ta nên sửa đổi thời gian trong hàm get_first_primes để trình tạo của chúng ta là vô hạn

Sơ đồ sau đây cho thấy luồng thực thi cho N = 5

Thưởng. Coroutines thông qua Trình tạo nâng cao

Một coroutine là một chức năng, ngoài khả năng tạm dừng thực thi và sau đó được tiếp tục, còn có thể trao đổi dữ liệu theo cả hai cách. Trong trường hợp này, trình tạo không chỉ trả về các giá trị cho trình gọi của nó mà trình gọi còn gửi các giá trị đến trình tạo thông qua send[]

Để chứng minh nó hoạt động như thế nào, chúng ta sẽ quay lại ví dụ về số nguyên tố. Giả sử rằng, thay vì hiển thị danh sách các số nguyên tố nhỏ hơn N, chúng tôi muốn hiển thị số nguyên tố sau cho từng phần tử trong danh sách, sử dụng lại trình tạo số nguyên tố vô hạn

Do đó, chúng ta có thể thay đổi giá trị thành một giá trị khác mỗi khi trình tạo sử dụng câu lệnh năng suất

Chức năng cơ bản gọi nó sẽ là

Và chúng ta sẽ nhận được kết quả như sau

Điều đó là có thể bởi vì send sẽ gửi một giá trị mới đến trình tạo trong khi trả về giá trị thu được từ trình tạo đó

Được rồi, chúng ta đã đi đến cuối. Đây là phần giới thiệu về máy phát điện. Dưới đây là một số liên kết tham khảo trong trường hợp bạn muốn khám phá chủ đề chi tiết hơn

Ở đây chúng ta sẽ tìm hiểu sâu hơn về các trình tạo Python, bao gồm các biểu thức trình tạo và hàm trình tạo

Biểu thức trình tạo

Sự khác biệt giữa mức độ hiểu danh sách và biểu thức trình tạo đôi khi gây nhầm lẫn;

Danh sách hiểu sử dụng dấu ngoặc vuông, trong khi biểu thức trình tạo sử dụng dấu ngoặc đơn

Đây là một cách hiểu danh sách đại diện

Trong 1]

[n ** 2 for n in range[12]]

Ra[1]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

Trong khi đây là biểu thức trình tạo đại diện

Trong 2]

[n ** 2 for n in range[12]]

Ra[2]

Lưu ý rằng việc in biểu thức trình tạo không in nội dung;

Trong 3]

G = [n ** 2 for n in range[12]]
list[G]

Ra[3]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

Danh sách là một tập hợp các giá trị, trong khi trình tạo là một công thức để tạo ra các giá trị

Khi bạn tạo một danh sách, bạn thực sự đang xây dựng một tập hợp các giá trị và có một số chi phí bộ nhớ liên quan đến điều đó. Khi bạn tạo một trình tạo, bạn không xây dựng một tập hợp các giá trị mà là một công thức để tạo ra các giá trị đó. Cả hai đều hiển thị cùng một giao diện trình lặp, như chúng ta có thể thấy ở đây

Trong [4]

L = [n ** 2 for n in range[12]]
for val in L:
    print[val, end=' ']

________số 8_______

Trong [5]

G = [n ** 2 for n in range[12]]
for val in G:
    print[val, end=' ']

________số 8_______

Sự khác biệt là một biểu thức trình tạo không thực sự tính toán các giá trị cho đến khi chúng cần thiết. Điều này không chỉ dẫn đến hiệu quả bộ nhớ mà còn cả hiệu quả tính toán. Điều này cũng có nghĩa là mặc dù kích thước của danh sách bị giới hạn bởi bộ nhớ khả dụng, nhưng kích thước của biểu thức trình tạo là không giới hạn

Có thể tạo một ví dụ về biểu thức trình tạo vô hạn bằng cách sử dụng trình vòng lặp

9 được xác định trong 
G = [n ** 2 for n in range[12]]
list[G]
0

Trong [6]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
0

Ra[6]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
1

Trong [7]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
2

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
3

Bộ vòng lặp

9 sẽ tiếp tục vui vẻ đếm mãi cho đến khi bạn yêu cầu nó dừng lại; 

Trong [8]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
4

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
5

Bạn có thể thấy những gì chúng tôi đang nhận được ở đây. nếu chúng ta mở rộng danh sách các thừa số một cách thích hợp, thì cái mà chúng ta sẽ bắt đầu là một trình tạo số nguyên tố, sử dụng thuật toán Sàng của Eratosthenes. Chúng ta sẽ khám phá điều này trong giây lát

Một danh sách có thể được lặp đi lặp lại nhiều lần;

Đây là một trong những vấn đề tiềm năng của các biểu thức trình tạo. Với một danh sách, chúng ta có thể làm điều này một cách đơn giản

Trong [9]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
6

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]
7

Mặt khác, một biểu thức trình tạo được sử dụng hết sau một lần lặp

Trong [10]

G = [n ** 2 for n in range[12]]
list[G]

Ra[10]

[0, 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121]

Trong [11]

[n ** 2 for n in range[12]]
0

Ra[11]

[n ** 2 for n in range[12]]
1

Điều này có thể rất hữu ích vì nó có nghĩa là có thể dừng và bắt đầu lặp lại

Trong [12]

[n ** 2 for n in range[12]]
2

[n ** 2 for n in range[12]]
3

Một nơi tôi thấy điều này hữu ích là khi làm việc với các tập hợp tệp dữ liệu trên đĩa;

Chức năng máy phát điện. Sử dụng
G = [n ** 2 for n in range[12]]
list[G]
2

Chúng ta đã thấy trong phần trước rằng khả năng hiểu danh sách được sử dụng tốt nhất để tạo các danh sách tương đối đơn giản, trong khi sử dụng vòng lặp

G = [n ** 2 for n in range[12]]
list[G]
3 bình thường có thể tốt hơn trong các tình huống phức tạp hơn. Điều này cũng đúng với các biểu thức trình tạo. chúng ta có thể tạo các trình tạo phức tạp hơn bằng cách sử dụng các hàm tạo, sử dụng câu lệnh
G = [n ** 2 for n in range[12]]
list[G]
2

Ở đây chúng ta có hai cách để xây dựng cùng một danh sách

Trong [13]

[n ** 2 for n in range[12]]
4

[n ** 2 for n in range[12]]
5

Tương tự như vậy, ở đây chúng ta có hai cách để xây dựng các máy phát điện tương đương

Trong [14]

[n ** 2 for n in range[12]]
6

[n ** 2 for n in range[12]]
7

Hàm tạo là một hàm, thay vì sử dụng

G = [n ** 2 for n in range[12]]
list[G]
5 để trả về một giá trị một lần, sử dụng
G = [n ** 2 for n in range[12]]
list[G]
2 để tạo ra một chuỗi giá trị [có thể là vô hạn]. Giống như trong các biểu thức trình tạo, trạng thái của trình tạo được giữ nguyên giữa các lần lặp lại một phần, nhưng nếu chúng ta muốn có một bản sao mới của trình tạo, chúng ta chỉ cần gọi lại hàm

Thí dụ. Trình tạo số nguyên tố

Ở đây tôi sẽ đưa ra ví dụ yêu thích của tôi về hàm tạo. một chức năng để tạo ra một loạt các số nguyên tố không giới hạn. Một thuật toán cổ điển cho việc này là Sàng Eratosthenes, hoạt động giống như thế này

Trong [15]

[n ** 2 for n in range[12]]
8

[n ** 2 for n in range[12]]
9

Trong [16]

0

1

Trong [17]

2

3

Trong [18]

4

5

Nếu chúng ta lặp lại quy trình này đủ số lần trên một danh sách đủ lớn, chúng ta có thể tạo bao nhiêu số nguyên tố tùy thích

Hãy đóng gói logic này trong một hàm tạo

Trong 19]

6

7

Thats tất cả để có nó. Mặc dù đây chắc chắn không phải là cách triển khai hiệu quả nhất về mặt tính toán của Sàng Eratosthenes, nhưng nó minh họa cú pháp hàm trình tạo có thể thuận tiện như thế nào để xây dựng các chuỗi phức tạp hơn

Lối ra của trình tạo trong Python là gì?

Khi đối tượng trình tạo được thu gom rác ở cuối chương trình của bạn, phương thức close[] của nó được gọi và điều này làm tăng ngoại lệ GeneratorExit bên trong trình tạo . Thông thường, điều này không bị bắt và khiến trình tạo thoát ra.

Năng suất có dừng cho vòng lặp Python không?

yield trong Python có thể được sử dụng giống như câu lệnh return trong một hàm. Khi làm như vậy, hàm thay vì trả về đầu ra, nó trả về một trình tạo có thể được lặp lại khi. Sau đó, bạn có thể lặp qua trình tạo để trích xuất các mục. Việc lặp lại được thực hiện bằng vòng lặp for hoặc đơn giản là sử dụng hàm next[] .

Năng suất có tăng StopIteration không?

Đã đạt đến điểm năng suất và giá trị năng suất được trả về. Khung được trả về từ; . StopIteration is raised.

Trình tạo Python có lười không?

Điểm chính. động lực và sử dụng đằng sau máy phát điện . Máy phát điện lười biếng . họ chỉ mang lại giá trị khi được hỏi rõ ràng. Bạn có thể cung cấp đầu ra của một trình tạo cho đầu vào của một trình tạo khác để tạo thành các đường dẫn dữ liệu.

Chủ Đề