{"id":"generators-yield","slug":"yield","title":"Generator functions and yield","text":"Some series of values are long, and some never end: all the odd numbers, the next ticket number at a counter, the lines of a huge file. Building the whole series in a list before using it wastes time and memory, and for an endless series it's impossible. A **generator** solves this by producing the values one at a time, only when they're asked for.\n\n### yield\n\nA function that contains the keyword **`yield`** is a **generator function**. `yield` hands out one value, much like `return`, but the function doesn't end there. It pauses, and when the next value is asked for, it continues from the same spot with the same variables. A `for` loop asks for values until the function ends:\n\n```python\ndef countdown(start):\n    number = start\n    while number > 0:\n        yield number\n        number -= 1\n\n\nfor number in countdown(3):\n    print(number)\nprint(\"Liftoff!\")\n```\n\n```output\n3\n2\n1\nLiftoff!\n```\n\n`countdown(3)` doesn't return 3, 2 and 1 at once. It returns a **generator**: an object that produces the values on request. The loop asks it for a value three times. The fourth time, the `while` condition is false, the function ends, and so does the loop.\n\n### Pausing and continuing\n\nA few prints inside a generator function show exactly when its code runs:\n\n```python\ndef steps():\n    print(\"start\")\n    yield \"one\"\n    print(\"after one\")\n    yield \"two\"\n    print(\"done\")\n\n\nfor value in steps():\n    print(\"got\", value)\n```\n\n```output\nstart\ngot one\nafter one\ngot two\ndone\n```\n\nCalling `steps()` runs none of its code yet. When the loop asks for the first value, the function runs up to the first `yield` and pauses there. The loop prints `got one` and asks again, and the function continues right after that `yield`. When the function's code runs out, the generator is finished and the loop ends.\n\nThat's the difference from `return`, which ends the call for good and forgets the function's variables. `yield` keeps them for the next value.\n\n### Endless generators, and lists\n\nA generator doesn't have to end. This one gives odd numbers forever, so the loop needs a `break`, or it would never stop:\n\n```python\ndef odd_numbers():\n    number = 1\n    while True:\n        yield number\n        number += 2\n\n\nfor number in odd_numbers():\n    if number > 7:\n        break\n    print(number)\n```\n\n```output\n1\n3\n5\n7\n```\n\nA generator that does end can be turned into a list with `list()`, which asks for every value. Printing the generator itself shows no values, only something like `<generator object countdown at 0x7f3a2c>`, since the values don't exist yet:\n\n```pycon\n>>> def countdown(start):\n...     number = start\n...     while number > 0:\n...         yield number\n...         number -= 1\n...\n>>> list(countdown(5))\n[5, 4, 3, 2, 1]\n```\n","task":"The generator function `multiples` should give the multiples of `n` up to `limit`. Fill in the blank so that the program prints:\n\n```\n7\n14\n21\n28\n```\n","kind":"fill","seed":"def multiples(n, limit):\n    number = n\n    while number <= limit:\n        [[yield]] number\n        number += n\n\n\nfor value in multiples(7, 30):\n    print(value)\n","solution":"def multiples(n, limit):\n    number = n\n    while number <= limit:\n        yield number\n        number += n\n\n\nfor value in multiples(7, 30):\n    print(value)\n","hints":["The function should hand out `number` and then carry on with the loop, not end.","The keyword that hands out a value and pauses the function is `yield`."],"tests":[{"name":"Output","stdin":"","expect":"7\n14\n21\n28","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"def shout(word):\n    print(\"begin\")\n    for letter in word:\n        yield letter.upper()\n    print(\"end\")\n\n\nfor letter in shout(\"hi\"):\n    print(letter)\n","solution":"def shout(word):\n    print(\"begin\")\n    for letter in word:\n        yield letter.upper()\n    print(\"end\")\n\n\nfor letter in shout(\"hi\"):\n    print(letter)\n","hints":["The function's code doesn't run until the loop asks for the first value. Then it runs up to the first `yield`.","`begin` is printed before the first letter, and `end` only after the last letter, when the loop asks for one more value."],"tests":[{"name":"Output","stdin":"","expect":"begin\nH\nI\nend","hidden":false}],"require":[],"forbid":[],"lines":["begin","H","I","end"]},{"task":"Write a generator function `repeat_each(items, times)` that gives each item of the list `times` times in a row. Use `yield`. For example,\n\n```python\nfor item in repeat_each([\"a\", \"b\"], 3):\n    print(item)\n```\n\nshould print:\n\n```\na\na\na\nb\nb\nb\n```\n","kind":"code","seed":"def repeat_each(items, times):\n    pass\n\n\nif __name__ == \"__main__\":\n    for item in repeat_each([\"a\", \"b\"], 3):\n        print(item)\n","solution":"def repeat_each(items, times):\n    for item in items:\n        for i in range(times):\n            yield item\n\n\nif __name__ == \"__main__\":\n    for item in repeat_each([\"a\", \"b\"], 3):\n        print(item)\n","hints":["Go through the items with a `for` loop, and inside it repeat `times` times with a second loop.","Inside the inner loop, `yield item`. Don't build a list: each `yield` hands out one value."],"tests":[{"name":"Test 1","stdin":"","call":"for item in repeat_each([\"a\", \"b\"], 3):\n    print(item)\n","expect":"a\na\na\nb\nb\nb","hidden":false},{"name":"list(repeat_each([1, 2, 3], 2))","stdin":"","call":"list(repeat_each([1, 2, 3], 2))\n","expect":"[1, 1, 2, 2, 3, 3]","hidden":true,"returns":true},{"name":"list(repeat_each([\"x\", \"y\"], 0))","stdin":"","call":"list(repeat_each([\"x\", \"y\"], 0))\n","expect":"[]","hidden":true,"returns":true}],"require":[{"pattern":"\\byield\\b","message":"Make it a generator function, which hands out its values with `yield`."}],"forbid":[]}]}