{"id":"comprehensions-if-else","slug":"if-else","title":"Choosing a value with if and else","text":"In part 7 you met the **conditional expression**, an `if` and `else` on one line that gives one of two values:\n\n```pycon\n>>> age = 15\n>>> \"adult\" if age >= 18 else \"minor\"\n'minor'\n```\n\nIt reads like a sentence: the value is `\"adult\"` if the condition is true, else it's `\"minor\"`.\n\nA conditional expression can be the expression of a list comprehension. Then it chooses a value for each item separately, and every item gets into the new list in one form or the other:\n\n```python\nscores = [72, 45, 90, 38]\nresults = [\"pass\" if score >= 50 else \"fail\" for score in scores]\nprint(results)\n```\n\n```output\n['pass', 'fail', 'pass', 'fail']\n```\n\nThe shape is:\n\n```text\n[value1 if condition else value2 for item in series]\n```\n\nEither value can use the item. Here negative readings from a broken sensor are replaced with zero, and the other readings are kept as they are:\n\n```python\nreadings = [12, -3, 7, -1, 5]\ncleaned = [r if r >= 0 else 0 for r in readings]\nprint(cleaned)\n```\n\n```output\n[12, 0, 7, 0, 5]\n```\n\n### Two different ifs\n\nThere are now two places for an `if` in a comprehension, and they do different jobs:\n\n- An `if` at the end, after the series, is a **filter**. It decides which items get into the new list at all, so the list can get shorter.\n- An `if` with an `else`, before the `for`, is part of the expression. It decides what each item becomes, and the new list has as many items as the original.\n\n```pycon\n>>> numbers = [4, -2, 9, -5]\n>>> [n for n in numbers if n > 0]\n[4, 9]\n>>> [n if n > 0 else 0 for n in numbers]\n[4, 0, 9, 0]\n```\n\nIf you put the `else` at the end, Python can't read it. A filter has no `else`: an item either passes or it doesn't.\n\n```python\nnumbers = [4, -2, 9, -5]\nfixed = [n for n in numbers if n > 0 else 0]\n```\n\n```crash\n  File \"main.py\", line 2\n    fixed = [n for n in numbers if n > 0 else 0]\n                                         ^^^^\nSyntaxError: invalid syntax\n```\n\nPython points at the `else`: where it is, it makes no sense. Move the whole `n if n > 0 else 0` to the front.\n","task":"Fill in the blank with the condition, so that every negative reading becomes 0 and the others stay as they are. The program should print:\n\n```\n[12, 0, 7, 0, 0, 5]\n```\n","kind":"fill","seed":"readings = [12, -3, 7, -1, 0, 5]\ncleaned = [r if [[r >= 0‖r > 0‖0 <= r‖0 < r]] else 0 for r in readings]\nprint(cleaned)\n","solution":"readings = [12, -3, 7, -1, 0, 5]\ncleaned = [r if r >= 0 else 0 for r in readings]\nprint(cleaned)\n","hints":["The value before `if` is used when the condition is true: the reading `r` itself, for a reading that is fine.","A reading is fine when it isn't negative: the condition is `r >= 0`."],"tests":[{"name":"Output","stdin":"","expect":"[12, 0, 7, 0, 0, 5]","hidden":false}],"require":[],"forbid":[],"more":[{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"numbers = [3, -1, 8, -6]\nprint([n for n in numbers if n < 0])\nprint([n if n < 0 else 1 for n in numbers])\nprint([\"big\" if n > 5 else \"small\" for n in numbers])\n","solution":"numbers = [3, -1, 8, -6]\nprint([n for n in numbers if n < 0])\nprint([n if n < 0 else 1 for n in numbers])\nprint([\"big\" if n > 5 else \"small\" for n in numbers])\n","hints":["The first comprehension has an `if` at the end, so it's a filter. Only some numbers get through.","The other two have an `if` and an `else` before the `for`, so every number gives one item.","In the last one, only 8 is greater than 5."],"tests":[{"name":"Output","stdin":"","expect":"[-1, -6]\n[1, -1, 1, -6]\n['small', 'small', 'big', 'small']","hidden":false}],"require":[],"forbid":[],"lines":["[-1, -6]","[1, -1, 1, -6]","['small', 'small', 'big', 'small']"]},{"task":"A chat program hides words that aren't allowed. Write a function `censor(words, banned)` that returns a new list where every word that is in the list `banned` is replaced with `\"***\"`, and the other words stay as they are. Use a list comprehension.\n\nFor example, this call:\n\n```python\nprint(censor([\"you\", \"silly\", \"goose\"], [\"silly\", \"dumb\"]))\n```\n\nprints:\n\n```\n['you', '***', 'goose']\n```\n","kind":"code","seed":"def censor(words, banned):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(censor([\"you\", \"silly\", \"goose\"], [\"silly\", \"dumb\"]))\n","solution":"def censor(words, banned):\n    return [\"***\" if word in banned else word for word in words]\n\n\nif __name__ == \"__main__\":\n    print(censor([\"you\", \"silly\", \"goose\"], [\"silly\", \"dumb\"]))\n","hints":["Every word gives one item in the new list, so you need an `if` and an `else` before the `for`, not a filter at the end.","`word in banned` is `True` when the word is one of the banned words.","The expression is `\"***\" if word in banned else word`."],"tests":[{"name":"print(censor([\"you\", \"silly\", \"goose\"], [\"silly\", \"dumb\"]))","stdin":"","call":"print(censor([\"you\", \"silly\", \"goose\"], [\"silly\", \"dumb\"]))\n","expect":"['you', '***', 'goose']","hidden":false},{"name":"censor([\"dumb\", \"and\", \"dumb\"], [\"dumb\"])","stdin":"","call":"censor([\"dumb\", \"and\", \"dumb\"], [\"dumb\"])\n","expect":"['***', 'and', '***']","hidden":true,"returns":true},{"name":"censor([\"all\", \"fine\"], [])","stdin":"","call":"censor([\"all\", \"fine\"], [])\n","expect":"['all', 'fine']","hidden":true,"returns":true}],"require":[{"pattern":"\\[[^\\n]*\\bfor\\b","message":"Build the new list with a list comprehension."}],"forbid":[{"pattern":"\\.append\\s*\\(","message":"Build the new list with a list comprehension instead of `append`."}]}]}