{"id":"generators-next","slug":"next-and-stopiteration","title":"next and StopIteration","text":"A `for` loop takes every value of a generator. Sometimes you want one value at a time, at different places in your program. The built-in function **`next`** asks a generator for its next value:\n\n```python\ndef ticket_numbers(first):\n    number = first\n    while True:\n        yield number\n        number += 1\n\n\ntickets = ticket_numbers(101)\nprint(\"Your ticket:\", next(tickets))\nprint(\"Your ticket:\", next(tickets))\nprint(\"Now serving\", next(tickets))\n```\n\n```output\nYour ticket: 101\nYour ticket: 102\nNow serving 103\n```\n\nKeep the generator in a variable, as `tickets` above: each `next(tickets)` continues that same generator. Calling `ticket_numbers(101)` again makes a new generator, which starts from 101 again. Two generators made by the same function don't affect each other.\n\n### When the values run out\n\nA generator that has ended has nothing more to give. Then `next` raises a **`StopIteration`** exception:\n\n```python\ndef colors():\n    yield \"red\"\n    yield \"green\"\n\n\npalette = colors()\nprint(next(palette))\nprint(next(palette))\nprint(next(palette))\n```\n\n```output\nred\ngreen\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 9, in <module>\n    print(next(palette))\n          ~~~~^^^^^^^^^\nStopIteration\n```\n\nYou can catch it like any other exception, with `try` and `except`:\n\n```python\ndef colors():\n    yield \"red\"\n    yield \"green\"\n\n\npalette = colors()\ntry:\n    while True:\n        print(next(palette))\nexcept StopIteration:\n    print(\"No more colors\")\n```\n\n```output\nred\ngreen\nNo more colors\n```\n\nThis is also how a `for` loop knows when to stop. It calls `next` again and again and ends quietly at the `StopIteration`. It's the same signal the `__next__` method of your own iterator classes raised in part 10.\n\n### Used up for good\n\nA finished generator stays finished. Going through it a second time gives nothing, and `next` raises `StopIteration` again. To get the values again, make a new generator by calling the function again:\n\n```pycon\n>>> def colors():\n...     yield \"red\"\n...     yield \"green\"\n...\n>>> palette = colors()\n>>> list(palette)\n['red', 'green']\n>>> list(palette)\n[]\n>>> list(colors())\n['red', 'green']\n```\n","task":"The generator `weekdays` gives the names of the work days. Fill in the blanks so that the program takes the first two days one at a time and the rest with a loop, and prints:\n\n```\nFirst: Mon\nSecond: Tue\nWed\nThu\nFri\n```\n","kind":"fill","seed":"def weekdays():\n    for day in [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\"]:\n        yield day\n\n\ndays = weekdays()\nprint(\"First:\", [[next]](days))\nprint(\"Second:\", [[next]](days))\nfor day in days:\n    print(day)\n","solution":"def weekdays():\n    for day in [\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\"]:\n        yield day\n\n\ndays = weekdays()\nprint(\"First:\", next(days))\nprint(\"Second:\", next(days))\nfor day in days:\n    print(day)\n","hints":["The built-in function that asks a generator for one value is in the step's title.","Both blanks are `next`: `next(days)` gives the next day. The loop then carries on from where `next` left off."],"tests":[{"name":"Output","stdin":"","expect":"First: Mon\nSecond: Tue\nWed\nThu\nFri","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Write an endless generator function `fibonacci()` that gives the Fibonacci numbers 1, 1, 2, 3, 5, 8, 13, and so on: after the first two ones, each number is the sum of the two before it. For example,\n\n```python\nnumbers = fibonacci()\nfor i in range(7):\n    print(next(numbers))\n```\n\nshould print:\n\n```\n1\n1\n2\n3\n5\n8\n13\n```\n","kind":"code","seed":"def fibonacci():\n    pass\n\n\nif __name__ == \"__main__\":\n    numbers = fibonacci()\n    for i in range(7):\n        print(next(numbers))\n","solution":"def fibonacci():\n    a = 1\n    b = 1\n    while True:\n        yield a\n        a, b = b, a + b\n\n\nif __name__ == \"__main__\":\n    numbers = fibonacci()\n    for i in range(7):\n        print(next(numbers))\n","hints":["Keep the two latest numbers in two variables, both 1 to begin with.","In an endless `while True` loop, `yield` the first of them, then move both one step forward.","Moving forward: the new first number is the old second one, and the new second is their sum: `a, b = b, a + b`."],"tests":[{"name":"Test 1","stdin":"","call":"numbers = fibonacci()\nfor i in range(7):\n    print(next(numbers))\n","expect":"1\n1\n2\n3\n5\n8\n13","hidden":false},{"name":"Test 2","stdin":"","call":"numbers = fibonacci()\nprint([next(numbers) for i in range(12)])\n","expect":"[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144]","hidden":true},{"name":"Test 3","stdin":"","call":"first = fibonacci()\nsecond = fibonacci()\nnext(first)\nnext(first)\nnext(first)\nprint(next(first), next(second))\n","expect":"3 1","hidden":true}],"require":[],"forbid":[]},{"task":"Write a function `take(generator, count)` that returns a list of the next `count` values of the generator it gets. If the generator runs out before that, the list holds the values there were. It's an ordinary function, not a generator: take the values with `next`, and catch the `StopIteration`. For example,\n\n```python\nnumbers = countdown(5)\nprint(take(numbers, 2))\nprint(take(numbers, 2))\nprint(take(numbers, 9))\n```\n\nshould print:\n\n```\n[5, 4]\n[3, 2]\n[1]\n```\n","kind":"code","seed":"def countdown(start):\n    number = start\n    while number > 0:\n        yield number\n        number -= 1\n\n\ndef take(generator, count):\n    pass\n\n\nif __name__ == \"__main__\":\n    numbers = countdown(5)\n    print(take(numbers, 2))\n    print(take(numbers, 2))\n    print(take(numbers, 9))\n","solution":"def countdown(start):\n    number = start\n    while number > 0:\n        yield number\n        number -= 1\n\n\ndef take(generator, count):\n    values = []\n    try:\n        for i in range(count):\n            values.append(next(generator))\n    except StopIteration:\n        pass\n    return values\n\n\nif __name__ == \"__main__\":\n    numbers = countdown(5)\n    print(take(numbers, 2))\n    print(take(numbers, 2))\n    print(take(numbers, 9))\n","hints":["Start with an empty list and repeat `count` times: append `next(generator)` to it.","Put the loop in a `try` block. When `next` raises `StopIteration`, the `except StopIteration:` block runs, and the loop is over.","Return the list after the `try` and `except`, so it's returned in both cases."],"tests":[{"name":"Test 1","stdin":"","call":"numbers = countdown(5)\nprint(take(numbers, 2))\nprint(take(numbers, 2))\nprint(take(numbers, 9))\n","expect":"[5, 4]\n[3, 2]\n[1]","hidden":false},{"name":"Test 2","stdin":"","call":"def evens():\n    number = 0\n    while True:\n        yield number\n        number += 2\n\n\ngen = evens()\nprint(take(gen, 3))\nprint(take(gen, 4))\nprint(take(evens(), 0))\n","expect":"[0, 2, 4]\n[6, 8, 10, 12]\n[]","hidden":true},{"name":"take(countdown(0), 3)","stdin":"","call":"take(countdown(0), 3)\n","expect":"[]","hidden":true,"returns":true}],"require":[{"pattern":"\\bnext\\s*\\(","message":"Take the values one at a time with `next`."}],"forbid":[]}]}