{"id":"generators-expressions","slug":"generator-expressions","title":"Generator expressions","text":"In part 11 you built lists with list comprehensions. Write the same thing in round brackets instead of square ones, and you get a **generator expression** (also called a generator comprehension): a generator made without writing a function.\n\n```python\nsquares = (n * n for n in range(1, 6))\nprint(next(squares))\nprint(next(squares))\nfor square in squares:\n    print(square)\n```\n\n```output\n1\n4\n9\n16\n25\n```\n\nLike a generator function, it computes nothing in advance: each value is calculated when it's asked for. `next` works, a `for` loop works, and it's used up after one pass. Printing it shows only `<generator object <genexpr> at 0x7f3a2c>`, but `type` tells what it is:\n\n```pycon\n>>> squares = (n * n for n in range(1, 6))\n>>> type(squares)\n<class 'generator'>\n>>> sum(squares)\n55\n>>> sum(squares)\n0\n```\n\nThe second sum is 0 because the first one already used up every value.\n\n### Straight into a function\n\nFunctions such as `sum`, `max`, `min` and the string method `join` accept any series of values, a generator too. When a generator expression is a function's only argument, you can leave out its own brackets. A condition at the end works as it does in list comprehensions:\n\n```python\nwords = [\"generators\", \"are\", \"lazy\", \"and\", \"thrifty\"]\nprint(sum(len(word) for word in words))\nprint(max(len(word) for word in words))\nprint(\" \".join(word.upper() for word in words if len(word) > 3))\n```\n\n```output\n27\n10\nGENERATORS LAZY THRIFTY\n```\n\n### A list or a generator?\n\nA list comprehension builds the whole list at once and keeps it. Choose it when you need the values more than once, need to know how many there are with `len`, or need an item by its index. A generator can't do those things:\n\n```python\nsquares = (n * n for n in range(1, 6))\nprint(squares[0])\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 2, in <module>\n    print(squares[0])\n          ~~~~~~~^^^\nTypeError: 'generator' object is not subscriptable\n```\n\n\"Not subscriptable\" means the value doesn't support `[]`. A generator expression is the better choice when you go through the values just once, especially when there are many: `sum(n * n for n in range(1000000))` adds up a million squares without ever storing a list of a million numbers.\n","task":"Fill in the blank with the value the generator expression gives for each `part`, so that the program adds up the numbers in the text and prints:\n\n```\nTotal: 49\n```\n","kind":"fill","seed":"text = \"12,7,30\"\ntotal = sum([[int(part)]] for part in text.split(\",\"))\nprint(\"Total:\", total)\n","solution":"text = \"12,7,30\"\ntotal = sum(int(part) for part in text.split(\",\"))\nprint(\"Total:\", total)\n","hints":["`text.split(\",\")` gives the strings `\"12\"`, `\"7\"` and `\"30\"`. `sum` needs numbers.","For each `part`, the generator should give the part as a whole number: `int(part)`."],"tests":[{"name":"Output","stdin":"","expect":"Total: 49","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"evens = (n for n in range(10) if n % 2 == 0)\nprint(next(evens))\nprint(next(evens))\nprint(list(evens))\nprint(list(evens))\n","solution":"evens = (n for n in range(10) if n % 2 == 0)\nprint(next(evens))\nprint(next(evens))\nprint(list(evens))\nprint(list(evens))\n","hints":["The generator gives the even numbers 0, 2, 4, 6 and 8, one at a time.","`list` takes all the values that are left, after the two `next` calls.","After that the generator is used up, so the last list is empty."],"tests":[{"name":"Output","stdin":"","expect":"0\n2\n[4, 6, 8]\n[]","hidden":false}],"require":[],"forbid":[],"lines":["0","2","[4, 6, 8]","[]"]},{"task":"Write a function `long_words(text, minimum)` that **returns a generator** giving the words of `text` that have at least `minimum` letters, in capital letters. Make it with a generator expression. For example,\n\n```python\nwords = long_words(\"a lazy generator makes values on demand\", 5)\nprint(next(words))\nprint(next(words))\nprint(list(words))\n```\n\nshould print:\n\n```\nGENERATOR\nMAKES\n['VALUES', 'DEMAND']\n```\n","kind":"code","seed":"def long_words(text, minimum):\n    pass\n\n\nif __name__ == \"__main__\":\n    words = long_words(\"a lazy generator makes values on demand\", 5)\n    print(next(words))\n    print(next(words))\n    print(list(words))\n","solution":"def long_words(text, minimum):\n    return (word.upper() for word in text.split() if len(word) >= minimum)\n\n\nif __name__ == \"__main__\":\n    words = long_words(\"a lazy generator makes values on demand\", 5)\n    print(next(words))\n    print(next(words))\n    print(list(words))\n","hints":["`text.split()` gives the words. A generator expression goes through them: `(... for word in text.split() ...)`.","Add a condition at the end, `if len(word) >= minimum`, and give `word.upper()` for each word that passes.","Return the generator expression itself, in round brackets, not a list."],"tests":[{"name":"Test 1","stdin":"","call":"words = long_words(\"a lazy generator makes values on demand\", 5)\nprint(next(words))\nprint(next(words))\nprint(list(words))\n","expect":"GENERATOR\nMAKES\n['VALUES', 'DEMAND']","hidden":false},{"name":"list(long_words(\"one three five\", 4))","stdin":"","call":"list(long_words(\"one three five\", 4))\n","expect":"['THREE', 'FIVE']","hidden":true,"returns":true},{"name":"Test 3","stdin":"","call":"words = long_words(\"tiny bits\", 9)\nprint(list(words))\nprint(next(long_words(\"Python\", 3)))\n","expect":"[]\nPYTHON","hidden":true}],"require":[],"forbid":[]}]}