#35. Máy phát điện

Máy phát điện là chức năng có thể tiếp tục. Một hàm bình thường bắt đầu, chạy và kết thúc với một giá trị trả về. Trình tạo có thể khởi động, tạo ra một giá trị, tạm dừng khung của nó, sau đó tiếp tục từ cùng một vị trí lệnh, tạo ra một giá trị khác và lặp lại cho đến khi kết thúc.

Hàm tạo là bất kỳ phần thân hàm nào có chứayield.

def numbers():
    yield 1
    yield 2
    yield 3
```Việc gọi hàm này không chạy phần thân ngay lập tức.```python id="oyb9ik"
g = numbers()
```Cuộc gọi tạo ra một đối tượng máy phát điện. Phần thân khởi động khi máy phát điện được nối lại:```python id="9sgmxp"
print(next(g))
print(next(g))
print(next(g))
```Đầu ra:```text id="wj3i3f"
1
2
3
```Sau giá trị cuối cùng,  yếu  lịch tiếp theo sẽ tăng`StopIteration`.

## 35.1 Hàm tạo và đối tượng trình tạo

Hàm tạo  hàm  thể gọi được xác định bằng`def`.

Đối tượng trình tạo  trình vòng lặp  thể tiếp tục được trả về khi hàm tạo được gọi.```python id="nckwxg"
def gen():
    yield 1

print(gen)
print(gen())
```Về mặt khái niệm:```text id="hfh6hz"
gen
    function object

gen()
    generator object
        suspended execution state
        code object
        frame or frame-like state
```Điều này khác với một chức năng thông thường:```python id="wsroz3"
def f():
    return 1

f()
```Đang gọi`f`chạy  thể ngay lập tức  trở về`1`.

Đang gọi`gen`trả về một đối tượng  sau này  thể chạy phần thân.

## 35,2`yield`các`yield`biểu thức tạo ra một giá trị cho trình gọi của trình tạo và tạm dừng thực thi.```python id="cwhj6e"
def gen():
    x = 10
    yield x
    x = 20
    yield x
```Trình tự thực hiện:```text id="jvg4tx"
create generator object
resume generator
    x = 10
    yield 10
    suspend

resume generator
    x = 20
    yield 20
    suspend

resume generator
    finish function
    raise StopIteration
```Biến cục bộ`x`tồn tại qua hệ thống treo  trình tạo vẫn giữ trạng thái thực thi.

## 35.3 Generator là Iterator

Đối tượng trình tạo thực hiện giao thức lặp.```python id="mtd1nu"
g = numbers()

print(iter(g) is g)
print(next(g))
```Một máy phát điện :```text id="vlpm43"
__iter__
__next__
send
throw
close
```các`for`vòng lặp hoạt động  các trình tạo  các trình vòng lặp:```python id="9z52dp"
for x in numbers():
    print(x)
```Về mặt khái niệm:```text id="rdvvmh"
it = iter(numbers())

while True:
    try:
        x = next(it)
    except StopIteration:
        break
    print(x)
```## 35.4 Khung máy phát điện

Trình tạo phải duy trì trạng thái thực thi giữa các lần tiếp tục.

Trạng thái đó bao gồm:```text id="9ta9ii"
code object
instruction position
local variables
value stack
exception state
closure cells
running state
finished state
``` dụ:```python id="h463cg"
def gen():
    a = 1
    b = 2
    yield a
    yield b
```Sau lần đầu tiên`yield`, máy phát điện phải nhớ:```text id="oj7swc"
a = 1
b = 2
next instruction is after first yield
```Đây   do tại sao máy phát điện được kết nối chặt chẽ với các khung.

## 35.5 Khung hàm thông thường so với Khung tạo

Khung chức năng bình thường thường biến mất sau khi quay lại.```python id="lzuq79"
def f():
    x = 1
    return x
```Sau đó`f()`trở lại, khung  thể bị xóa.

Khung máy phát điện vẫn tồn tại trong khi bị treo.```python id="6zyz25"
def gen():
    x = 1
    yield x
```Sau đó`next(gen())`đạt tới`yield`, khung không thể bị xóa    thể tiếp tục lại sau đó.

| Tính năng | Chức năng bình thường | Máy phát điện |
|---|---|---|
| Gọi chạy body liền |  | Không |
|  thể đình chỉ | Không |  |
| Giữ người dân địa phương sau khi nhượng bộ | Không |  |
| Trả về một kết quả cuối cùng |  | Kết quả cuối cùng trở thành`StopIteration.value`|
| Triển khai giao thức lặp | Không |  |
| Tuổi thọ khung hình | Thời lượng cuộc gọi thường | Cho đến khi hoàn thành hoặc đóng |

## 35,6`next()`

`next(g)`nối lại một máy phát điện.```python id="07krhu"
def gen():
    yield "a"
    yield "b"

g = gen()

print(next(g))
print(next(g))
```Thực thi:```text id="tuypws"
next(g)
    resume at start
    yield "a"
    return "a" to caller

next(g)
    resume after first yield
    yield "b"
    return "b" to caller
```Đối tượng trình tạo ghi lại vị trí lệnh giữa các cuộc gọi.

## 35.7 Hoàn thành và`StopIteration`Khi một máy phát điện kết thúc, nó sẽ tăng`StopIteration`.

```python id="suekt2"
def gen():
    yield 1

g = gen()
print(next(g))
print(next(g))
```thứ hai`next(g)`tăng lên`StopIteration`.

Một máy phát điện  thể kết thúc bằng cách:```text id="6n5ndu"
falling off the end
executing return
raising an exception
being closed
```Rơi khỏi cuối cùng tương đương với việc quay trở lại`None`.

```python id="51z1x1"
def gen():
    yield 1
```Sau đó`yield 1`, hàm đi đến cuối.  yếu  lịch tiếp theo tăng`StopIteration`.

## 35,8`return`trong máy phát điện

Máy phát điện  thể sử dụng`return value`.

```python id="lbrk4s"
def gen():
    yield 1
    return 99
```Giá trị trả về trở thành`value`thuộc tính của`StopIteration`.

```python id="tyi2fu"
g = gen()

print(next(g))

try:
    next(g)
except StopIteration as exc:
    print(exc.value)
```Đầu ra:```text id="dzo3b2"
1
99
```MỘT`for`vòng lặp bỏ qua trận chung kết`StopIteration.value`.

## 35,9`yield`là một biểu thức`yield`có thể nhận được một giá trị thông qua`send`.

```python id="vpynq0"
def gen():
    x = yield "ready"
    yield x
```Sử dụng:```python id="5cofsb"
g = gen()

print(next(g))
print(g.send(42))
```Thực thi:```text id="fafbmz"
next(g)
    runs until yield "ready"
    returns "ready"

g.send(42)
    resumes generator
    yield expression evaluates to 42
    x = 42
    yield x
``` thế`yield`cả hai đều gửi một giá trị ra   thể nhận lại một giá trị.

## 35.10 Khởi động máy phát điện bằng`send`Trình tạo mới được tạo chưa đạt đến lần đầu tiên`yield`.

 vậy,  yếu  lịch đầu tiên phải sử dụng`next(g)`hoặc`g.send(None)`.

```python id="ltjgnn"
g = gen()
g.send(None)
```Gửi một tin nhắn không phải`None`giá trị cho trình tạo mới khởi động  một lỗi  không  giá trị nào bị treo`yield`biểu hiện để nhận được .```python id="w4yvh2"
g = gen()
g.send(42)
```Điều này làm tăng`TypeError`.

## 35.11`throw`

`throw`tiếp tục một trình tạo bằng cách đưa ra một ngoại lệ tại thời điểm bị treo`yield`.

```python id="1i4m5p"
def gen():
    try:
        yield "ready"
    except ValueError:
        yield "handled"

g = gen()

print(next(g))
print(g.throw(ValueError))
```Thực thi:```text id="h3sq71"
next(g)
    yield "ready"

g.throw(ValueError)
    resume at yield by raising ValueError
    except ValueError catches it
    yield "handled"

throwcho phép người gọi đưa một ngoại lệ vào trình tạo.

35,12close

closeyêu cầu một máy phát điện chấm dứt.```python id="4p6xj9" def gen(): try: yield 1 finally: print("cleanup")

g = gen() next(g) g.close() ```Đóng tiêmGeneratorExitvào máy phát điện. cácfinallykhối chạy.

Trình tạo không được mang lại giá trị bình thường khi đóng. Nếu đúng như vậy, CPython sẽ tăngRuntimeError.

def bad():
    try:
        yield 1
    finally:
        yield 2
```Đang gọi`close()`sau sản lượng đầu tiên gây ra lỗi do máy phát điện sinh ra trong quá trình đóng.

## 35.13 Trạng thái máy phát điện

Một máy phát điện  thể  một số trạng thái:```text id="spbcno"
created
running
suspended
closed
```sử dụng`inspect`:

```python id="9b2nga"
import inspect

def gen():
    yield 1

g = gen()
print(inspect.getgeneratorstate(g))
next(g)
print(inspect.getgeneratorstate(g))
try:
    next(g)
except StopIteration:
    pass
print(inspect.getgeneratorstate(g))
```Các trạng thái điển hình:```text id="51wa06"
GEN_CREATED
GEN_SUSPENDED
GEN_CLOSED
```Máy phát điện không thể tiếp tục hoạt động khi đang chạy.

## 35.14 Bảo vệ tái truy cập

Máy phát điện không thể được nhập lại.```python id="h0ak06"
def gen():
    yield next(g)

g = gen()
next(g)
```Điều này cố gắng để tiếp tục`g`trong khi`g`đang chạy rồi. CPython gây ra lỗi.

Trình tạo  cờ đang chạy để tránh làm hỏng trạng thái khung của .

Về mặt khái niệm:```text id="lm6k96"
if generator is already executing:
    raise ValueError or RuntimeError depending on context
```Điều này bảo vệ khung treo  ngăn xếp.

## 35.15 Mã byte của trình tạo

Hàm tạo sẽ biên dịch thành đối tượng  được đánh dấu  trình tạo.```python id="af0twx"
def gen():
    yield 1
```Việc gọi hàm sẽ tạo một đối tượng trình tạo thay  thực thi khung để hoàn thành.

Một chuỗi hướng dẫn khái niệm:```text id="n6w1a4"
LOAD_CONST 1
YIELD_VALUE
RESUME
LOAD_CONST None
RETURN_VALUE
``` byte chính xác thay đổi tùy theo phiên bản Python.

Hướng dẫn chính `YIELD_VALUE`, sẽ gửi một giá trị cho người gọi  tạm dừng thực thi.

## 35,16`yield from`

`yield from`ủy quyền cho một trình vòng lặp hoặc trình tạo khác.```python id="uxya55"
def outer():
    yield from inner()
``` gần tương đương với:```python id="37kb2t"
for value in inner():
    yield value
```Nhưng  cũng chuyển tiếp:```text id="hq74n9"
send
throw
close
StopIteration.value
```Điều này làm cho`yield from`mạnh mẽ hơn một vòng lặp đơn giản.

## 35.17 Đoàn Với`yield from`Ví dụ:```python id="9ui4p5"
def inner():
    yield 1
    yield 2
    return 99

def outer():
    result = yield from inner()
    yield result

print(list(outer()))
```Đầu ra:```text id="4ncupl"
[1, 2, 99]
```Giá trị trả về của`inner`trở thành kết quả của`yield from`biểu hiện trong`outer`.

Về mặt khái niệm:```text id="02qghi"
outer delegates to inner
inner yields 1
outer yields 1 to caller

inner yields 2
outer yields 2 to caller

inner returns 99 via StopIteration.value
yield from expression evaluates to 99
outer yields 99
```## 35,18`yield from`Và`send`

`yield from`chuyển tiếp các giá trị được gửi bởi người gọi.```python id="nfxupw"
def inner():
    x = yield "inner ready"
    yield x

def outer():
    yield from inner()

g = outer()
print(next(g))
print(g.send(42))
```Đầu ra:```text id="9lagzv"
inner ready
42
```các`send(42)`đạt tới mức bị đình chỉ`yield`bên trong`inner`.

## 35,19`yield from`và Ngoại lệ`yield from`chuyển tiếp ngoại lệ quá.```python id="nxzr78"
def inner():
    try:
        yield "ready"
    except ValueError:
        yield "handled"

def outer():
    yield from inner()

g = outer()
print(next(g))
print(g.throw(ValueError))
```Ngoại lệ được ném vào`inner`, không được xử  trực tiếp bởi`outer`, trừ khi việc ủy ​​quyền kết thúc hoặc bên trong thiếu trình xử  thích hợp.

## 35.20 Trình tạo biểu thức

Biểu thức trình tạo tạo ra một đối tượng giống như trình tạo.```python id="gkiij5"
squares = (x * x for x in range(10))
``` lười biếng. Các giá trị được tính toán theo yêu cầu.```python id="ey0d2q"
print(next(squares))
print(next(squares))
```Một biểu thức trình tạo  phạm vi giống như hàm ẩn của riêng .```python id="wkic1b"
x = 100
g = (x for x in range(3))
print(x)
```Bên ngoài`x`còn lại`100`.

## 35.21 Hiểu danh sách và biểu thức trình tạo

Việc hiểu danh sách sẽ xây dựng toàn bộ danh sách ngay lập tức.```python id="h6kqv5"
xs = [x * x for x in range(10)]
```Một biểu thức trình tạo tạo ra các giá trị một cách lười biếng.```python id="j8cabg"
g = (x * x for x in range(10))
```| Tính năng | Danh sách hiểu | Biểu thức máy phát điện |
|---|---|---|
| Đánh giá | Háo hức | Lười biếng |
| Kết quả | Danh sách | Trình lặp giống như máy phát điện |
|  ức | Lưu trữ tất cả kết quả | Lưu trữ trạng thái thực thi |
| Tái sử dụng | , danh sách  thể lặp lại nhiều lần | Không, máy phát điện đã hết |
| Phạm vi | Phạm vi hiểu riêng | Phạm vi máy phát điện riêng |

## 35.22 Lặp lại một lần

Trình tạo  trình lặp một lần.```python id="mj534b"
g = (x for x in range(3))

print(list(g))
print(list(g))
```Đầu ra:```text id="qbh3cb"
[0, 1, 2]
[]
```Sau khi cạn kiệt, máy phát điện vẫn cạn kiệt.

Điều này khác với một vùng chứa như danh sách:```python id="b4xrxl"
xs = [0, 1, 2]
print(list(xs))
print(list(xs))
```Một danh sách sẽ tạo một trình vòng lặp mới mỗi lần. Một trình tạo  trình vòng lặp của chính .

## 35.23 Đánh giá lười biếng

Máy phát điện tính toán các giá trị theo yêu cầu.```python id="c1xawr"
def read_lines(path):
    with open(path) as f:
        for line in f:
            yield line.rstrip("\n")
```Điều này không đọc toàn bộ tập tin vào bộ nhớ.  đọc  cho ra từng dòng một.

Thực thi lười biếng rất hữu ích cho:```text id="dhu35c"
large files
streams
pipelines
infinite sequences
expensive computations
early stopping
``` dụ:```python id="zb1yck"
def count():
    n = 0
    while True:
        yield n
        n += 1
```Trình tạo này đại diện cho một chuỗi  hạn.

## 35.24 Kiểu đường ống

Máy phát điện sáng tác tự nhiên.```python id="j6opqr"
def numbers(path):
    with open(path) as f:
        for line in f:
            yield int(line)

def positive(xs):
    for x in xs:
        if x > 0:
            yield x

def squared(xs):
    for x in xs:
        yield x * x
```Sử dụng:```python id="1rj6pt"
pipeline = squared(positive(numbers("data.txt")))

for x in pipeline:
    print(x)
```Mỗi giai đoạn kéo từ giai đoạn trước. Không cần  danh sách trung gian đầy đủ.

## 35.25 Dọn dẹp máy phát điện

Trình tạo quản  tài nguyên nên sử dụng`try/finally`hoặc người quản  bối cảnh.```python id="8m79yy"
def lines(path):
    f = open(path)
    try:
        for line in f:
            yield line
    finally:
        f.close()
```Nếu máy phát điện bị đóng trước khi cạn kiệt,`finally`khối chạy.

Một hình thức tốt hơn:```python id="yyr3qh"
def lines(path):
    with open(path) as f:
        for line in f:
            yield line
```các`with`câu lệnh được biên dịch thành logic dọn dẹp hoạt động khi đóng trình tạo.

## 35.26 Trình tạo và rò rỉ tài nguyên

Một máy phát điện bị treo  thể giữ cho tài nguyên tồn tại.```python id="2s3f45"
def gen():
    f = open("data.txt")
    yield f.readline()
    f.close()
```Nếu lệnh gọi dừng sau giá trị đầu tiên  không bao giờ đóng trình tạo, tệp  thể vẫn mở cho đến khi trình tạo được thu thập.

Sử dụng`with`hoặc đóng một cách  ràng:```python id="lz764o"
g = gen()
next(g)
g.close()
```Quyền sở hữu tài nguyên phải  ràng trong  trình tạo.

## 35.27 Trình tạo và ngoại lệ trong`finally`Nếu mã dọn dẹp tăng lên, ngoại lệ đó sẽ lan truyền trong quá trình đóng hoặc hoàn thiện trình tạo.```python id="xdp983"
def gen():
    try:
        yield 1
    finally:
        raise RuntimeError("cleanup failed")
```Đang gọi`g.close()`sau khi khởi động máy phát điện tăng`RuntimeError`.

Các ngoại lệ về thời gian quyết toán  thể được báo cáo  không thể xử  được nếu không  ngữ cảnh người gọi thông thường.

## 35.28 Duy trì bộ nhớ máy phát điện

Một trình tạo bị treo giữ cho các biến cục bộ của  tồn tại.```python id="7evyaw"
def gen():
    data = bytearray(100_000_000)
    yield 1
    return len(data)

g = gen()
next(g)
```Sau lần đầu tiên`yield`, `data`vẫn còn sống  máy phát điện  thể tiếp tục  sử dụng .

Chuỗi lưu giữ:```text id="a05d71"
generator object
    suspended frame
        local data
```Để giải phóng bộ nhớ, hãy xả hoặc đóng trình tạo hoặc tránh giữ lại các cục bộ lớn trên sản lượng.

## 35.29 Dọn dẹp các địa phương lớn

Nếu không cần một vật lớn sau khi nhường đường, hãy dọn sạch  trước khi nhường đường hoặc trước khi tạm dừng kéo dài.```python id="mdphyz"
def gen():
    data = bytearray(100_000_000)
    result = process(data)
    data = None
    yield result
```Điều này cho phép vật thể lớn được thả ra trước khi bị treo.

Khung máy phát điện vẫn tồn tại nhưng không còn tham chiếu nữa`data`.

## 35.30 Máy phát điện và`for`Vòng lặp

Một máy phát điện thường xuất hiện bên trong một`for`vòng lặp:```python id="ywz49k"
for value in gen():
    use(value)
```Vòng lặp liên tục gọi`next()`cho đến khi`StopIteration`.

Nếu vòng lặp thoát sớm với`break`, đối tượng trình tạo  thể không thể truy cập được  sau đó bị đóng. Nhưng việc dựa vào quyết toán ngay lập tức  tùy vào từng trường hợp thực hiện cụ thể. Sử dụng trình quản  bối cảnh khi vấn đề về thời gian dọn dẹp.

## 35.31 Trình quản lý bối cảnh dựa trên trình tạo

các`contextlib.contextmanager`trang trí biến trình tạo thành trình quản  bối cảnh.```python id="vtcps7"
from contextlib import contextmanager

@contextmanager
def managed():
    print("enter")
    try:
        yield "value"
    finally:
        print("exit")

with managed() as value:
    print(value)
```Máy phát điện mang lại chính xác một lần.

Về mặt khái niệm:```text id="2vq7qx"
__enter__
    run generator until yield
    return yielded value

__exit__
    resume generator to run cleanup
```Nếu phần thân tăng lên, ngoại lệ sẽ được ném vào trình tạo tại`yield`.

## 35.32 Các phương thức giao thức của trình tạo

Các đối tượng trình tạo hỗ trợ các phương thức quan trọng sau:

| Phương pháp | Ý nghĩa |
|---|---|
|`__next__()`| Tiếp tục  gửi`None` |
| `send(value)`| Tiếp tục  gửi giá trị vào hiện tại`yield` |
| `throw(exc)`| Tiếp tục bằng cách nâng cao ngoại lệ hiện tại`yield` |
| `close()`| tiêm`GeneratorExit` đóng |
|`__iter__()`| Tự quay về |`next(g)`cuộc gọi`g.__next__()`.

`g.__next__()`tương đương với`g.send(None)`đối với máy phát điện treo.

## 35.33 Thuộc tính của Trình tạo

Các đối tượng trình tạo hiển thị các thuộc tính hữu ích.```python id="yu9p0l"
def gen():
    yield 1

g = gen()

print(g.gi_code)
print(g.gi_frame)
print(g.gi_running)
```Các thuộc tính chung bao gồm:

| Thuộc tính | Ý nghĩa |
|---|---|
|`gi_code`| Đối tượng  |
|`gi_frame`| khung hoặc`None`khi đóng cửa |
|`gi_running`| Cho  hiện đang thực thi |
|`gi_yieldfrom`| Trình lặp được ủy quyền hiện tại cho`yield from`, nếu  |

Đây  các móc nội quan cấp CPython   thể tiết lộ chi tiết triển khai.

## 35.34 Trình tạo và truy nguyên

Nếu trình tạo đưa ra một ngoại lệ, thì truy nguyên sẽ bao gồm khung trình tạo.```python id="u2d2xz"
def gen():
    yield 1
    1 / 0

g = gen()
next(g)
next(g)
```thứ hai`next(g)`tiếp tục bên trong máy phát điện  tăng lên`ZeroDivisionError`.

Truy nguyên trỏ đến dòng bị lỗi bên trong`gen`.

Khung trình tạo  một phần của truy nguyên giống như bất kỳ khung Python nào khác.

## 35.35 Máy phát điện và`StopIteration`Chuyển đổi

Bên trong máy phát điện,  tình`StopIteration` nguy hiểm.```python id="mmdpxy"
def gen():
    next(iter([]))
    yield 1
```nội bộ`next(iter([]))`tăng lên`StopIteration`.

Python hiện đại biến điều này thành`RuntimeError`khi  thoát ra khỏi thân máy phát điện. Điều này ngăn chặn việc chấm dứt ngẫu nhiên trông giống như việc hoàn thành trình tạo bình thường.

 đúng sẽ nắm bắt  ràng nếu được mong đợi:```python id="tmjsqq"
def gen():
    try:
        value = next(iter([]))
    except StopIteration:
        return
    yield value
```## 35.36 Trình tạo và Async

Trình tạo  liên quan nhưng khác với trình tạo coroutine  trình tạo không đồng bộ.

| Xây dựng | Từ khóa | Sản xuất |
|---|---|---|
| Máy phát điện |`def`với`yield`| Đối tượng máy phát điện |
| Coroutine |`async def`| Đối tượng Coroutine |
| Trình tạo không đồng bộ |`async def`với`yield`| Đối tượng trình tạo không đồng bộ |

Một máy phát điện bình thường sử dụng`next`, `send`, `throw`, `close`.

Một coroutine sử dụng`await` lập kế hoạch vòng lặp sự kiện.

Trình tạo không đồng bộ sử dụng`async for``anext`.

Họ chia sẻ ý tưởng về việc thực hiện  thể tiếp tục nhưng khác nhau về giao thức.

## 35.37 Mô hình thực thi CPython

 cấp độ CPython, trình tạo  một đối tượng heap sở hữu trạng thái thực thi bị treo.

Về mặt khái niệm:```text id="y0j37u"
PyGenObject
    code object
    frame or interpreter frame state
    name and qualname
    exception state
    running flag
    weakrefs
    yield-from target
```Cấu trúc chính xác thay đổi giữa các phiên bản, nhưng các trường khái niệm vẫn còn.

Khi được tiếp tục:```text id="zrin3w"
check generator is not closed
check generator is not already running
mark running
enter evaluation loop with saved frame
run until yield, return, or exception
save frame state if yielded
clear frame state if completed
mark not running
return yielded value or propagate exception
```## 35,38`YIELD_VALUE`các`YIELD_VALUE`hướng dẫn là hoạt động mã byte chính.

Về mặt khái niệm:```text id="bpj8tu"
value = pop stack
save current frame position
return value to generator caller
mark generator suspended
```Khi được tiếp tục, việc thực thi tiếp tục sau lệnh lợi nhuận.

Giá trị mang lại không phải  giá trị trả về cuối cùng của hàm.   kết quả trung gian được cung cấp bởi giao thức lặp.

## 35,39`SEND`và Phái đoàn

 byte hiện đại  hỗ trợ cụ thể để gửi giá trị vào trình tạo, coroutine  đường dẫn ủy nhiệm.

Về mặt khái niệm, một hoạt động gửi:```text id="z95s95"
resume suspended iterator/coroutine
send value or None
receive yielded value, return value, or exception

yield fromawaitcả hai đều phụ thuộc vào việc gửi vào một đối tượng có thể tiếp tục khác.

Đây là cách kết nối các phép tính có thể tiếp tục lồng nhau mà không cần viết vòng lặp đầy đủ theo cách thủ công.

35.40 Những hiểu lầm phổ biến

Hiểu lầm Đúng mẫu
Gọi một hàm tạo sẽ chạy nó Nó tạo ra một đối tượng máy phát điện
yieldcũng giống nhưreturn yieldđình chỉ;returnhoàn thành
Một máy phát điện có thể được tái sử dụng sau khi cạn kiệt Đó là một lần
Trình tạo lưu trữ tất cả các giá trị Nó lưu trữ trạng thái thực thi và tính toán một cách lười biếng
yield fromchỉ là cú pháp cho một vòng lặp Nó cũng chuyển tiếp giá trị gửi, ném, đóng và trả về
Máy phát điện giải phóng người dân địa phương sau mỗi lần sản lượng Người dân địa phương vẫn còn sống trong khi bị đình chỉ
MỘTforvòng lặp nhìn thấyStopIteration.value Nó bỏ qua giá trị
close()chỉ là xóa Nó tiêmGeneratorExitvà chạy dọn dẹp

35.41 Chiến lược đọc

Bắt đầu với một máy phát điện nhỏ:python id="wby2x2" def gen(): x = 1 yield x x = 2 yield x Thanh tra:```python id="hvaeen" import dis import inspect

g = gen()

print(inspect.getgeneratorstate(g)) dis.dis(gen)

print(next(g)) print(inspect.getgeneratorstate(g)) print(g.gi_frame.f_locals)

print(next(g)) print(inspect.getgeneratorstate(g)) print(g.gi_frame.f_locals) Sau đó nghiên cứu:text id="tf7v1e" return value send throw close yield from try/finally generator expressions contextlib.contextmanager Đối với mỗi trường hợp, theo dõi:text id="a4iald" when the body starts where execution suspends which locals remain alive what resumes execution what exception or value crosses the boundary when the frame is cleared


Trình to là các hàm có th tiếp tc được trin khai dưới dng đối tượng trình vòng lp vi trng thái thc thi đã lưu. Lnh gi hàm to s to mt đối tượng trình to. Thân máy ch chy khi máy phát đin được ni li bng cách`next`, `send`, `throw`, hoc`close`.

Mô hình ct lõi là:```text id="4a89xx"
generator function call
    
create generator object with suspended frame
    
next/send resumes frame
    
yield returns value and suspends frame
    
resume later from same point
    
return or end raises StopIteration
```Trình to kết ni vic thc thi mã byte, khung, x lý ngoi l, lp li, đánh giá lười biếng, tui th b nh và ng nghĩa dn dp.

Chúng là mt trong nhng ví d rõ ràng nht v vic CPython coi trng thái thc thi là mt đối tượng.