Skip to content

Type Hints in VS Code

A docstring tells a person what type each argument should be. A type hint says the same thing in a way that VS Code can also read, so the editor can warn you about a wrong type before you run the program. Save the programs from this lab in your Week07 folder, and open your whole CS149 folder in VS Code (not just the file).

Warmup Exercise

Create a file named warmup.py, paste the code below, and run it. When the program asks for a number, enter 5.

def double(n):
    return n * 2


print(double(input("Number: ")))

What did it print, and why? There was no error message, and VS Code didn't underline anything, but the answer is still wrong.

Now change the first line to the following, and look at the last line again.

def double(n: int) -> int:

You should see a red squiggle under input("Number: "). Hover your mouse over it and read the message. If you don't see a squiggle, your workspace settings are missing "python.analysis.typeCheckingMode": "basic". Go back to Step 6 of the VS Code setup before continuing.

What a Type Hint Says

Type hints go in the first line of a function definition. Nothing else about the function changes.

def pizza_cost(diameter: float, toppings: int, delivery: bool) -> float:
  • A colon after a parameter names the type that parameter expects. Read diameter: float as "diameter is a float."
  • An arrow -> before the final colon names the type the function returns.
  • Five types cover almost everything you will write for a while: int, float, str, bool, and None.
  • A function that only prints, and has no return statement, returns None, so its hint is -> None.

The most important thing to know about type hints is that Python ignores them. Your program runs exactly the same with or without them, and a wrong type still crashes (or silently does the wrong thing) when the program runs. The hints are for the people reading your code, and for VS Code, which checks every call while you type.

Where to read the messages

Hover over a red squiggle to see one message. To see all of them at once, open the Problems panel with Ctrl+Shift+M. A file with problems also turns red in the Explorer, which helps when the problem is in a file you aren't looking at.

Predict the Squiggles

Create a file named pizza.py and paste the code below. It should have no squiggles yet.

pizza.py
"""Compute the cost of ordering a pizza."""


def pizza_cost(diameter: float, toppings: int, delivery: bool) -> float:
    """Compute the cost of one pizza.

    Args:
        diameter: Size of the pizza in inches.
        toppings: Number of toppings.
        delivery: Whether the pizza is delivered.

    Returns:
        The cost in dollars, rounded to two places.
    """
    cost = 8.00 + 0.50 * diameter + 1.25 * toppings
    if delivery:
        cost = cost + 3.00
    return round(cost, 2)


def show_receipt(cost: float) -> None:
    """Print the total cost of an order.

    Args:
        cost: The total cost in dollars.
    """
    print(f"Total: ${cost:.2f}")


if __name__ == "__main__":
    print(pizza_cost(12, 2, True))

Each example below is code you could add under if __name__ == "__main__":. Predict whether VS Code will underline anything in each one. Then add them one at a time, and hover over each squiggle to read why.

Example 1
print(pizza_cost(12.5, 2, False))
Example 2
print(pizza_cost(12, 2.0, True))
Example 3
print(pizza_cost("12", 2, True))
Example 4
print(pizza_cost(12, 2, "no"))
Example 5
print(pizza_cost(12, 2))
Example 6
print(pizza_cost(12, True, True))
Example 7
size = input("Diameter: ")
print(pizza_cost(size, 2, True))
Example 8
print(pizza_cost(12, 2, True).upper())
Example 9
show_receipt(pizza_cost(12, 2, True))
Example 10
tip = show_receipt(19.50) * 0.20
Check your predictions

Every example gets a squiggle except three: Examples 1, 6, and 9.

Five observations worth pulling out of that table:

  • An int is allowed where a float is expected, because every whole number is also a number with a decimal point. The reverse is not allowed. What would it mean to order 2.5 toppings?
  • True is allowed where an int is expected, which surprises most people. In Python, True and False are a kind of integer (1 and 0), so VS Code can't catch this mistake.
  • "no" is caught, and it's worth running that line to see why it matters. Python treats every non-empty string as true, so this call quietly charges you for delivery. Without the hint, nothing would warn you.
  • input() always returns a str, even when the user types digits. That's the warmup bug again, and it's the type error you are most likely to make this semester.
  • VS Code knows what every function returns, so it can check what you do with the result. A float has no .upper(), and show_receipt returns None, which you can't multiply. If you wanted the cost, the function needed return, not print.

Leaving out an argument (pizza_cost(12, 2)) is caught even without type hints. Remove the hints from pizza_cost for a minute, and see which of the other squiggles disappear.

Bugs Inside a Function

VS Code also checks the body of a function against its -> hint. Each of these functions has one bug. Predict what VS Code will say about each one, then paste them into pizza.py to check.

def price_tag(cost: float) -> str:
    """Format a cost for the menu board.

    Args:
        cost: The cost in dollars.

    Returns:
        The cost with a dollar sign and two decimal places.
    """
    return round(cost, 2)


def slices(diameter: float) -> int:
    """Decide how many slices to cut.

    Args:
        diameter: Size of the pizza in inches.

    Returns:
        The number of slices.
    """
    if diameter < 10:
        return 6
    elif diameter < 14:
        return 8
Check your answers

price_tag says it returns a str, but round() returns a float. The fix is an f-string, such as return f"${cost:.2f}".

slices doesn't return anything when diameter is 14 or more, so it would return None instead of an int. VS Code says that the function "must return value on all code paths." The fix is an else with its own return.

Add Hints to Your Code

Open the functions you wrote for Quiz 2. If you don't have a copy, use one of your practice programs from Week 5.

  1. Decide on the type of each parameter and each return value. Your test calls under if __name__ == "__main__": are the best evidence. If any call passes a number with a decimal point, the parameter is a float.
  2. Add the hints to each def line, and make sure your file has no squiggles. If a squiggle appears, decide whether the hint is wrong or the code is.
  3. Break your code on purpose, three different ways:

    • Call one of your functions with a string.
    • Make one branch return the wrong type, such as "one" instead of 1.
    • Delete one return (or the else before it).

    Each time, read VS Code's message before you run the program. Then run it anyway. Does the program crash, print the wrong answer, or seem to work?

Type hints from now on

Starting in Week 7, the code in this course will include type hints, and you should write them in your programs too. VS Code will check them for you, and Thonny will simply ignore them.