Skip to main content

Python Typing for New Developers

A beginner‑friendly guide to adding type hints in Python.

Note: This tutorial assumes you understand some basic Python syntax, but are new to programming or type hints. To learn more about Python, see the Python Tutorial and Getting Started Guide

1. What is a Type Hint in Python?

A type hint in Python is a way to indicate the expected data type of a variable, function parameter, or return value. It's a hint to other developers (and to tools like type checkers and IDEs) about what type of data should be used with a particular piece of code.

Type hints are not enforced at runtime by Python itself, but they can be used by third-party tools (like Pyrefly) to catch type-related errors before your code runs. They also serve as documentation, making it easier for others to understand how to use your code. Here's an example of a simple function with type hints:

def greet(name: str) -> None:
print(f"Hello, {name}!")

2. Why Bother with Type Hints?

Python is a dynamically typed language, which means you can write code without declaring types. However, this can lead to bugs or ambiguity in your code.

TL;DR

  • Catch bugs before running the code.
  • Improve editor autocomplete & refactors.
  • Turn your code into living documentation.
# Without hints – is "times" a str, int, or list? def repeat(text, times): return text * times # With hints – intent is crystal clear. def repeat(text: str, times: int) -> str: return text * times

Can you spot the bug?

class Rectangle:
width: int
height: int

def __init__(self, width: int, height: int) -> None:
self.width = width
self.height = height

rect = Rectangle(width=100, height=50)

area = rect.width * rect.hieght

print(area)

Spelling is hard! Let's add the dataclass decorator to our class definition. This will generate a constructor for us, and also add a few other useful methods.

#Pyrefly will catch this spelling error before you run the code from dataclasses import dataclass @dataclass class Rectangle: width: int height: int rect = Rectangle(width=100, height=50) area = rect.width * rect.hieght

3. Primitive Types

Since Python 3.9 you can use all the primitive types directly as annotations.

age: int = 30 height: float = 1.85 name: str = "Tyler Typer" is_admin: bool = False

You can also specify a parameter as optional by using Optional type, or now with the | None syntax.

# Optional typing example from typing import Optional middle_name: Optional[str] = None # classic nickname: str | None = None # 3.10+ shorthand

4. Collections

Syntax Examples

  • List of numbers list[int] scores: list[int] = [98, 87, 91]
  • Tuple of two floats tuple[float, float] point: tuple[float, float] = (3.0, 4.0)
  • Dict of str -> int dict[str, int] inventory: dict[str, int] = {"apples": 5}
  • Set of strings set[str] authors: set[str] = {"Bob", "Eve"}

Since Python 3.9 you can subscript built‑ins directly—no need for from typing import List.

5. Functions

# Simple function def add(a: int, b: int) -> int: return a + b

Default values keep their annotation:

# Function with default value def greet(name: str, polite: bool = True) -> str: return "Hello!" if polite else f"Yo {name}"

Variable‑length arguments:

# Variable length functions from collections.abc import Callable Logger = Callable[[str], None] def debug(*msgs: str, log: Logger | None = print) -> None: for m in msgs: if log is not None: log(m) else: print(m)

6. Get Type Hint Signals Directly in Your Editor

You can download the Pyrefly extension for VSCode to get type hint signals directly in your IDE.

Next, install Pyrefly and check some code:

# Fast, zero‑config
pip install pyrefly

pyrefly check ./my_sample.py

# Check whole directories
pyrefly check app/ tests/

Create a pyrefly.toml file to configure your project. Instructions here.