{"id":"more-features-args","slug":"any-number-of-arguments","title":"Any number of arguments","text":"`print` takes any number of arguments: `print(\"a\")`, `print(\"a\", \"b\", \"c\")`, even `print()`. Your own functions can do the same. A star `*` before a parameter's name collects all the remaining arguments of a call into a **tuple**:\n\n```python\ndef total(*numbers):\n    print(\"Got\", len(numbers), \"numbers:\", numbers)\n    return sum(numbers)\n\n\nprint(total(1, 2, 3))\nprint(total(10))\nprint(total())\n```\n\n```output\nGot 3 numbers: (1, 2, 3)\n6\nGot 1 numbers: (10,)\n10\nGot 0 numbers: ()\n0\n```\n\nInside the function, `numbers` is an ordinary tuple: you can loop over it, index it and take its length. (A tuple with one item is printed with a comma, `(10,)`, to tell it apart from a number in parentheses.) When no better name fits, such a parameter is usually called `*args`, short for arguments.\n\n### With ordinary parameters\n\nOrdinary parameters can come before the starred one. They take the first arguments, and the starred one gets all the rest, which may be none at all:\n\n```python\ndef report(title, *scores):\n    print(title)\n    for score in scores:\n        print(\"-\", score)\n\n\nreport(\"Round 1\", 7, 9, 4)\nreport(\"Round 2\")\n```\n\n```output\nRound 1\n- 7\n- 9\n- 4\nRound 2\n```\n\n### A list is one argument\n\nA list given to such a function is still one argument, not many. Here `numbers` becomes a tuple with one item, the list, and `sum` can't add a list to a number:\n\n```python\ndef total(*numbers):\n    return sum(numbers)\n\n\nvalues = [1, 2, 3]\nprint(total(values))\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 6, in <module>\n    print(total(values))\n          ~~~~~^^^^^^^^\n  File \"main.py\", line 2, in total\n    return sum(numbers)\nTypeError: unsupported operand type(s) for +: 'int' and 'list'\n```\n\nA star in the call spreads the list out into separate arguments: `total(*values)` is the same as `total(1, 2, 3)`, and returns 6.\n","task":"Fill in the blank so that `longest` accepts any number of words, and the program prints `giraffe`.\n","kind":"fill","seed":"def longest([[*]]words):\n    best = \"\"\n    for word in words:\n        if len(word) > len(best):\n            best = word\n    return best\n\n\nprint(longest(\"cat\", \"giraffe\", \"dog\"))\n","solution":"def longest(*words):\n    best = \"\"\n    for word in words:\n        if len(word) > len(best):\n            best = word\n    return best\n\n\nprint(longest(\"cat\", \"giraffe\", \"dog\"))\n","hints":["As it is, `words` takes one argument, but the call gives three.","A star before the parameter's name collects all the arguments into a tuple: `*words`."],"tests":[{"name":"Output","stdin":"","expect":"giraffe","hidden":false}],"require":[],"forbid":[],"more":[{"task":"Write a function `average(*numbers)` that returns the mean of any number of numbers, or `0.0` when it gets none. `average(1, 2, 3, 4)` returns `2.5`.\n","kind":"code","seed":"def average():\n    pass\n\n\nif __name__ == \"__main__\":\n    print(average(1, 2, 3, 4))\n    print(average())\n","solution":"def average(*numbers):\n    if len(numbers) == 0:\n        return 0.0\n    return sum(numbers) / len(numbers)\n\n\nif __name__ == \"__main__\":\n    print(average(1, 2, 3, 4))\n    print(average())\n","hints":["Add the starred parameter to the `def` line: `def average(*numbers):`.","The mean is `sum(numbers) / len(numbers)`. Check for zero numbers first, or the division fails."],"tests":[{"name":"average(1, 2, 3, 4)","stdin":"","call":"average(1, 2, 3, 4)\n","expect":"2.5","hidden":false,"returns":true},{"name":"average(7)","stdin":"","call":"average(7)\n","expect":"7.0","hidden":false,"returns":true},{"name":"average()","stdin":"","call":"average()\n","expect":"0.0","hidden":true,"returns":true},{"name":"average(2, 3)","stdin":"","call":"average(2, 3)\n","expect":"2.5","hidden":true,"returns":true},{"name":"average(-1, 1, 6)","stdin":"","call":"average(-1, 1, 6)\n","expect":"2.0","hidden":true,"returns":true}],"require":[],"forbid":[]},{"task":"Write a function `shopping_list(title, *items)` that prints the title with a colon and then the items, numbered from 1. With no items at all, it prints the title and `: nothing to buy` on one line instead. `shopping_list(\"Groceries\", \"milk\", \"eggs\", \"bread\")` prints:\n\n```\nGroceries:\n1. milk\n2. eggs\n3. bread\n```\n","kind":"code","seed":"def shopping_list(title, *items):\n    pass\n\n\nif __name__ == \"__main__\":\n    shopping_list(\"Groceries\", \"milk\", \"eggs\", \"bread\")\n    shopping_list(\"Hardware\")\n","solution":"def shopping_list(title, *items):\n    if len(items) == 0:\n        print(f\"{title}: nothing to buy\")\n        return\n    print(f\"{title}:\")\n    number = 1\n    for item in items:\n        print(f\"{number}. {item}\")\n        number += 1\n\n\nif __name__ == \"__main__\":\n    shopping_list(\"Groceries\", \"milk\", \"eggs\", \"bread\")\n    shopping_list(\"Hardware\")\n","hints":["`items` is a tuple of all the arguments after the title. Check its length first.","Otherwise print the title and a colon, and then each item with a counter that starts at 1: `f\"{number}. {item}\"`."],"tests":[{"name":"shopping_list(\"Groceries\", \"milk\", \"eggs\", \"bread\")","stdin":"","call":"shopping_list(\"Groceries\", \"milk\", \"eggs\", \"bread\")\n","expect":"Groceries:\n1. milk\n2. eggs\n3. bread","hidden":false},{"name":"shopping_list(\"Hardware\")","stdin":"","call":"shopping_list(\"Hardware\")\n","expect":"Hardware: nothing to buy","hidden":true},{"name":"shopping_list(\"Party\", \"balloons\")","stdin":"","call":"shopping_list(\"Party\", \"balloons\")\n","expect":"Party:\n1. balloons","hidden":true},{"name":"Test 4","stdin":"","call":"shopping_list(\"Office\", \"pens\", \"tape\", \"paper\", \"clips\", \"stamps\")\nshopping_list(\"Garden\")\n","expect":"Office:\n1. pens\n2. tape\n3. paper\n4. clips\n5. stamps\nGarden: nothing to buy","hidden":true}],"require":[],"forbid":[]}]}