{"id":"comprehensions-new-lists","slug":"new-lists","title":"A new list from an old one","text":"Many programs take a list and make a new list out of it: prices with tax added, names in capital letters, the length of every word. So far you've done it with a loop that starts from an empty list and appends one item per round:\n\n```python\nwords = [\"tea\", \"coffee\", \"cocoa\", \"water\"]\nlengths = []\nfor word in words:\n    lengths.append(len(word))\nprint(lengths)\n```\n\n```output\n[3, 6, 5, 5]\n```\n\nThat's three lines to say one thing: \"the length of each word\". Python has a shorter way to say it, a **list comprehension**:\n\n```python\nwords = [\"tea\", \"coffee\", \"cocoa\", \"water\"]\nlengths = [len(word) for word in words]\nprint(lengths)\n```\n\n```output\n[3, 6, 5, 5]\n```\n\n### How to read it\n\nA list comprehension has this shape:\n\n```text\n[expression for item in series]\n```\n\n- The square brackets say that the result is a new list.\n- `for word in words` works like the first line of a `for` loop, without the colon. It goes through the series one item at a time.\n- The expression before the `for`, here `len(word)`, says what goes into the new list for each item.\n\nRead it out loud from the left: \"the length of word, for each word in words\". The new list has exactly as many items as the series, in the same order. The original list doesn't change: the comprehension only reads it.\n\n### Any expression will do\n\nThe expression can be a calculation, a method call, a conversion or a call to a function: anything that gives a value. The series can be anything a `for` loop can go through, such as a list or a `range`:\n\n```pycon\n>>> numbers = [4, 7, 10]\n>>> [n * 10 for n in numbers]\n[40, 70, 100]\n>>> [str(n) for n in numbers]\n['4', '7', '10']\n>>> names = [\"ada\", \"linus\", \"grace\"]\n>>> [name.capitalize() for name in names]\n['Ada', 'Linus', 'Grace']\n>>> [n * n for n in range(1, 6)]\n[1, 4, 9, 16, 25]\n```\n\nThe second one shows that the new items don't have to be of the same type as the old ones: numbers went in, strings came out. The third uses the string method `capitalize`, which gives the string with its first letter in capitals and the rest in small letters, so `\"aDA\"` would become `'Ada'` too.\n\nA function can return a comprehension directly. There's no need to store it in a variable first:\n\n```python\ndef lengths_of(words):\n    return [len(word) for word in words]\n```\n\n### The expression comes first\n\nThe order matters. If you write it in the order of a loop, with the `for` first, Python can't read it:\n\n```python\nnumbers = [4, 7, 10]\ndoubled = [for n in numbers: n * 2]\n```\n\n```crash\n  File \"main.py\", line 2\n    doubled = [for n in numbers: n * 2]\n               ^^^\nSyntaxError: invalid syntax\n```\n\nThe fix is `[n * 2 for n in numbers]`: first what you want, then where it comes from.\n","task":"Every order in the shop gets a shipping fee of 5 added to its price. Fill in the blank so the comprehension makes the list of prices with shipping. The program should print:\n\n```\n[17, 45, 9, 25]\n```\n","kind":"fill","seed":"prices = [12, 40, 4, 20]\nwith_shipping = [[[price + 5‖5 + price]] for price in prices]\nprint(with_shipping)\n","solution":"prices = [12, 40, 4, 20]\nwith_shipping = [price + 5 for price in prices]\nprint(with_shipping)\n","hints":["The blank is the expression, what goes into the new list for each `price`.","Each price gets 5 added: the blank is `price + 5`."],"tests":[{"name":"Output","stdin":"","expect":"[17, 45, 9, 25]","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"numbers = [1, 2, 3]\nprint([n * 3 for n in numbers])\nprint([n - 1 for n in numbers])\nprint(numbers)\n","solution":"numbers = [1, 2, 3]\nprint([n * 3 for n in numbers])\nprint([n - 1 for n in numbers])\nprint(numbers)\n","hints":["Each comprehension makes a new list with one item for each item of `numbers`.","The comprehensions only read `numbers`, so the last line prints the list as it was."],"tests":[{"name":"Output","stdin":"","expect":"[3, 6, 9]\n[0, 1, 2]\n[1, 2, 3]","hidden":false}],"require":[],"forbid":[],"lines":["[3, 6, 9]","[0, 1, 2]","[1, 2, 3]"]},{"task":"Write a function `shout(words)` that returns a new list with each word in capital letters and an exclamation mark at the end. Use a list comprehension.\n\nFor example, `shout([\"hi\", \"stop\", \"go\"])` returns `['HI!', 'STOP!', 'GO!']`, so the program in the editor prints:\n\n```\n['HI!', 'STOP!', 'GO!']\n```\n","kind":"code","seed":"def shout(words):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(shout([\"hi\", \"stop\", \"go\"]))\n","solution":"def shout(words):\n    return [word.upper() + \"!\" for word in words]\n\n\nif __name__ == \"__main__\":\n    print(shout([\"hi\", \"stop\", \"go\"]))\n","hints":["The method `upper()` gives a word in capital letters, and `+ \"!\"` adds the exclamation mark.","The function can return the comprehension directly: `return [... for word in words]`.","The expression in front of the `for` is `word.upper() + \"!\"`."],"tests":[{"name":"print(shout([\"hi\", \"stop\", \"go\"]))","stdin":"","call":"print(shout([\"hi\", \"stop\", \"go\"]))\n","expect":"['HI!', 'STOP!', 'GO!']","hidden":false},{"name":"shout([\"Python\", \"now\"])","stdin":"","call":"shout([\"Python\", \"now\"])\n","expect":"['PYTHON!', 'NOW!']","hidden":true,"returns":true},{"name":"shout([])","stdin":"","call":"shout([])\n","expect":"[]","hidden":true,"returns":true}],"require":[{"pattern":"\\[[^\\n]*\\bfor\\b","message":"Build the new list with a list comprehension, `[... for word in words]`."}],"forbid":[{"pattern":"\\.append\\s*\\(","message":"Build the new list with a list comprehension instead of `append`."}]}]}