{"id":"return-values-type-hints","slug":"type-hints","title":"Argument types and type hints","text":"Every value has a type. These are the ones you know so far:\n\n```pycon\n>>> type(2026)\n<class 'int'>\n>>> type(9.81)\n<class 'float'>\n>>> type(\"hello\")\n<class 'str'>\n>>> type(5 == 5)\n<class 'bool'>\n```\n\n`int` is a whole number, `float` a number with a decimal point, `str` a string and `bool` one of `True` and `False`.\n\nA function works only when its arguments are of a type it can handle. This one multiplies a price by an amount, so it needs two numbers. The second call gets its amount straight from `input`:\n\n```python\ndef total_price(price, amount):\n    print(\"Total:\", price * amount)\n\n\ntotal_price(2.5, 4)\namount = input(\"How many? \")\ntotal_price(2.5, amount)\n```\n\n```input\n3\n```\n\n```output\nTotal: 10.0\nHow many? 3\n```\n\n```crash\nTraceback (most recent call last):\n  File \"main.py\", line 7, in <module>\n    total_price(2.5, amount)\n    ~~~~~~~~~~~^^^^^^^^^^^^^\n  File \"main.py\", line 2, in total_price\n    print(\"Total:\", price * amount)\n                    ~~~~~~^~~~~~~~\nTypeError: can't multiply sequence by non-int of type 'float'\n```\n\n`input` always returns a string, so in the second call `amount` is `\"3\"`, not 3. Inside the function, `price * amount` becomes `2.5 * \"3\"`. A string can only be repeated a whole number of times, and 2.5 isn't one, so Python stops. The error shows up inside the function, but the mistake is in the call: a number the user types must go through `int` (or `float`) before it's passed on. With a whole-number price it would be even sneakier: `2 * \"3\"` is the string `\"33\"`, and the program would print a wrong total without any error at all.\n\n### Type hints\n\nTo tell the people who use your function which types it expects, you can add **type hints**. A hint goes after a parameter, with a colon, and the type of the return value goes after an arrow `->` before the final colon:\n\n```python\ndef shout(text: str, marks: int) -> str:\n    return text.upper() + \"!\" * marks\n\n\nprint(shout(\"hello\", 3))\n```\n\n```output\nHELLO!!!\n```\n\nThis says: `text` should be a string, `marks` a whole number, and the function returns a string. Hints make a function easier to use correctly, and code editors use them to warn about mistakes.\n\nPython itself doesn't check them, though. A hint is only a hint: a call with other types still runs, and the function does whatever its code does with those values:\n\n```python\ndef double(number: int) -> int:\n    return number * 2\n\n\nprint(double(4))\nprint(double(\"ha\"))\nprint(double(1.5))\n```\n\n```output\n8\nhaha\n3.0\n```\n\nFrom now on, the starter code of many tasks has type hints. They tell you what the checks will give your function and what they expect back.\n","task":"The program asks for a price and an amount, and prints the total that `total_price` returns. It crashes, because the amount is passed on as a string. Fix the program so it works:\n\n```\nPrice: 2.5\nAmount: 4\nTotal: 10.0\n```\n","kind":"code","seed":"def total_price(price: float, amount: int) -> float:\n    return price * amount\n\n\nprice = float(input(\"Price: \"))\namount = input(\"Amount: \")\nprint(\"Total:\", total_price(price, amount))\n","solution":"def total_price(price: float, amount: int) -> float:\n    return price * amount\n\n\nprice = float(input(\"Price: \"))\namount = int(input(\"Amount: \"))\nprint(\"Total:\", total_price(price, amount))\n","hints":["`input` always returns a string, but `amount` should be an `int`, as its type hint says.","Wrap the `input(...)` that reads the amount in `int(...)`, the same way the price goes through `float(...)`."],"tests":[{"name":"Test 1","stdin":"2.5\n4\n","expect":"Price: 2.5\nAmount: 4\nTotal: 10.0","hidden":false},{"name":"Test 2","stdin":"0.75\n8\n","expect":"Price: 0.75\nAmount: 8\nTotal: 6.0","hidden":true},{"name":"Test 3","stdin":"3.75\n2\n","expect":"Price: 3.75\nAmount: 2\nTotal: 7.5","hidden":true}],"require":[],"forbid":[],"more":[{"task":"Write the function `time_text(seconds)`, which returns a number of seconds as text in minutes and seconds. Give it type hints: `seconds` is an `int`, and the function returns a `str`. For example, `time_text(125)` returns `'2 min 5 s'`.\n","kind":"code","seed":"def time_text(seconds):\n    pass\n\n\nif __name__ == \"__main__\":\n    print(time_text(125))\n","solution":"def time_text(seconds: int) -> str:\n    return f\"{seconds // 60} min {seconds % 60} s\"\n\n\nif __name__ == \"__main__\":\n    print(time_text(125))\n","hints":["The whole minutes are `seconds // 60`, and the seconds left over are `seconds % 60`.","Build the text with an f-string that has both numbers in it, and return it instead of printing it.","The hints go in the first line: `def time_text(seconds: int) -> str:`."],"tests":[{"name":"time_text(125)","stdin":"","call":"time_text(125)\n","expect":"'2 min 5 s'","hidden":false,"returns":true},{"name":"time_text(59)","stdin":"","call":"time_text(59)\n","expect":"'0 min 59 s'","hidden":true,"returns":true},{"name":"time_text(3600)","stdin":"","call":"time_text(3600)\n","expect":"'60 min 0 s'","hidden":true,"returns":true}],"require":[{"pattern":"seconds\\s*:\\s*int","message":"Give the parameter its type hint: `seconds: int`."},{"pattern":"->\\s*str\\s*:","message":"Give the return value its type hint: `-> str` before the colon."}],"forbid":[]},{"task":"What does this program print? Type each line it prints.\n","kind":"predict","seed":"def combine(a: int, b: int) -> int:\n    return a + b\n\n\nprint(combine(2, 3))\nprint(combine(\"2\", \"3\"))\nprint(type(combine(2.5, 1)))\n","solution":"def combine(a: int, b: int) -> int:\n    return a + b\n\n\nprint(combine(2, 3))\nprint(combine(\"2\", \"3\"))\nprint(type(combine(2.5, 1)))\n","hints":["Type hints aren't checked by Python. The function does whatever `a + b` does with the values it gets.","With two strings, `+` joins them, so `\"2\" + \"3\"` is `\"23\"`.","`2.5 + 1` is a `float`, and `print(type(...))` shows `<class 'float'>`."],"tests":[{"name":"Output","stdin":"","expect":"5\n23\n<class 'float'>","hidden":false}],"require":[],"forbid":[],"lines":["5","23","<class 'float'>"]}]}