{"id":"tuples-basics","slug":"basics","title":"What a tuple is","text":"A **tuple** is a lot like a list: an ordered group of values that you can index, slice, loop over and measure with `len`. There are two differences. You write a tuple with parentheses `( )` instead of square brackets, and a tuple can't change after it's made.\n\n```python\npoint = (3, 7)\nprint(point)\nprint(\"x:\", point[0])\nprint(\"y:\", point[1])\n\ncolors = (\"red\", \"green\", \"blue\")\nprint(len(colors), colors[-1])\nprint(\"green\" in colors)\nfor color in colors[1:]:\n    print(color)\n```\n\n```output\n(3, 7)\nx: 3\ny: 7\n3 blue\nTrue\ngreen\nblue\n```\n\nPython shows a tuple in parentheses, and a slice of a tuple is a tuple too.\n\n### A tuple can't change\n\nTuples are immutable, like strings and numbers. Assigning to an index stops the program:\n\n```python\npoint = (3, 7)\npoint[0] = 4\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 2, in <module>\n    point[0] = 4\n    ~~~~~^^^\nTypeError: 'tuple' object does not support item assignment\n```\n\nA tuple has none of the methods that change a list either: no `append`, `remove` or `sort`.\n\n```pycon\n>>> colors = (\"red\", \"green\")\n>>> colors.append(\"blue\")\nTraceback (most recent call last):\n  File \"<stdin>\", line 1, in <module>\nAttributeError: 'tuple' object has no attribute 'append'\n```\n\nFunctions that only read work fine: `len`, `min`, `max`, `sum` and `sorted` (which returns a new list). When a tuple needs to be different, make a new tuple and give it to the variable:\n\n```pycon\n>>> point = (3, 7)\n>>> point = (4, point[1])\n>>> point\n(4, 7)\n```\n\n### Lists of tuples\n\nA tuple suits a small record whose parts belong together, such as a name and a year. A list can hold many such tuples:\n\n```python\npioneers = [(\"Ada\", 1815), (\"Alan\", 1912), (\"Grace\", 1906)]\nfor pioneer in pioneers:\n    print(f\"{pioneer[0]} was born in {pioneer[1]}\")\n```\n\n```output\nAda was born in 1815\nAlan was born in 1912\nGrace was born in 1906\n```\n\nThe list can grow and shrink as people are added or removed, but each record stays the way it was made.\n","task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"sizes = (\"S\", \"M\", \"L\", \"XL\")\nprint(sizes[1])\nprint(len(sizes))\nprint(sizes[-2:])\nprint(\"XS\" in sizes)\n","solution":"sizes = (\"S\", \"M\", \"L\", \"XL\")\nprint(sizes[1])\nprint(len(sizes))\nprint(sizes[-2:])\nprint(\"XS\" in sizes)\n","hints":["Indexing, `len` and `in` work on a tuple just as on a list.","`sizes[-2:]` is a slice of the last two items. A slice of a tuple is a tuple, so Python shows it in parentheses.","`in` on a tuple compares whole items, and none of the four items is `\"XS\"`."],"tests":[{"name":"Output","stdin":"","expect":"M\n4\n('L', 'XL')\nFalse","hidden":false}],"require":[],"forbid":[],"lines":["M","4","('L', 'XL')","False"],"more":[{"task":"The shop now closes at 18, but the program stops with a `TypeError`. A tuple can't change, so give the variable a new tuple instead of changing the old one. The program should print:\n\n```\nOpen from 9 to 18\n```\n","kind":"code","seed":"opening_hours = (9, 17)\nopening_hours[1] = 18\nprint(f\"Open from {opening_hours[0]} to {opening_hours[1]}\")\n","solution":"opening_hours = (9, 17)\nopening_hours = (opening_hours[0], 18)\nprint(f\"Open from {opening_hours[0]} to {opening_hours[1]}\")\n","hints":["`opening_hours[1] = 18` tries to change an item of the tuple, which Python doesn't allow.","Make a new tuple with the old opening hour and the new closing hour: `opening_hours = (opening_hours[0], 18)`. (`(9, 18)` works too.)"],"tests":[{"name":"Output","stdin":"","expect":"Open from 9 to 18","hidden":false}],"require":[{"pattern":"\\bopening_hours\\s*=\\s*\\(","min":2,"message":"Keep the first line, and give `opening_hours` a new tuple on the second line."}],"forbid":[]},{"task":"The lengths of some videos are stored as tuples of hours and minutes: `(1, 30)` is one hour and 30 minutes. Write a function `total_minutes(durations)` that takes a list of such tuples and returns their total length in minutes.\n\nFor example, `total_minutes([(1, 30), (0, 45), (2, 0)])` returns `255`.\n","kind":"code","seed":"def total_minutes(durations: list) -> int:\n    pass\n\n\nif __name__ == \"__main__\":\n    print(total_minutes([(1, 30), (0, 45), (2, 0)]))\n","solution":"def total_minutes(durations: list) -> int:\n    total = 0\n    for duration in durations:\n        total += duration[0] * 60 + duration[1]\n    return total\n\n\nif __name__ == \"__main__\":\n    print(total_minutes([(1, 30), (0, 45), (2, 0)]))\n","hints":["Go through the list with a `for` loop. On each round the loop variable is one tuple, such as `(1, 30)`.","The hours are at index 0 and the minutes at index 1. In minutes, one tuple is `duration[0] * 60 + duration[1]`.","Add each one to a total that starts at 0, and return it after the loop."],"tests":[{"name":"total_minutes([(1, 30), (0, 45), (2, 0)])","stdin":"","call":"total_minutes([(1, 30), (0, 45), (2, 0)])\n","expect":"255","hidden":false,"returns":true},{"name":"total_minutes([(0, 5)])","stdin":"","call":"total_minutes([(0, 5)])\n","expect":"5","hidden":true,"returns":true},{"name":"total_minutes([(3, 15), (1, 59), (0, 1)])","stdin":"","call":"total_minutes([(3, 15), (1, 59), (0, 1)])\n","expect":"315","hidden":true,"returns":true},{"name":"total_minutes([])","stdin":"","call":"total_minutes([])\n","expect":"0","hidden":true,"returns":true}],"require":[],"forbid":[]}]}