What does the "yield" keyword do?

In Python, the yield keyword is used in the body of a function like a return statement, but instead of returning a value and terminating the function, it yields a value and suspends the function's execution. The function can then be resumed later on from where it left off, allowing it to produce a series of values over time rather than computing them all at once and returning them to a list. This is known as the generator function.

Here's an example of a generator function that yields the squares of the numbers from 1 to 10:

def squares():
    for i in range(1, 11):
        yield i ** 2

for square in squares():
    print(square)

# Output:
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81
# 100

Generator functions can be useful when you want to iterate over a large sequence of values, but you don't want to store all of them in memory at the same time. Instead, the generator function produces the values one at a time as they are needed, which can save memory and improve performance.

You can also use the yield from syntax to delegate to another generator function or iterable from within a generator function. This allows you to write more concise and modular generator functions.

def squares(n):
    for i in range(1, n + 1):
        yield i ** 2

def nested_squares(n):
    yield from squares(n)

for square in nested_squares(10):
    print(square)

# Output:
# 1
# 4
# 9
# 16
# 25
# 36
# 49
# 64
# 81
# 100