Python code can be annotated with type hints that indicate the intended data type of a variable or function. Here's an example:
class Message:
def send(self, text: str, recipients: list[str]) -> bool:
try:
messaging_service.send(text, recipients)
return True
except MessageSendError:
return False
We see that the Message.send
method expects text, which should be a string, and recipients, which should be a list of strings. The send method returns a boolean value to indicate success or failure.
Type hints have several benefits:
- Help prevent errors caused by mismatched data types
- Document usage for other developers
- Enhance code editor functionality
- Help AI understand your code
Over the years maintaining Python code, I've seen a lot of type-related errors appear in deployed systems. Usually, they are easy enough to fix, but type hints combined with running a type checker would have caught these problems before they shipped.
Since not all of the libraries I regularly work with have full support for types, I don't validate types for an entire project. Rather, I run the type checker in my editor for instant feedback.
When working with unfamiliar code, it is never fun to see a function with a signature like def update_address(self, address):
. Is the address a string? A dict? An object? While I can determine the answer from reading the code, I'd rather not have to mentally execute code (sometimes several layers deep) to know how to call a function.
When type hints are used appropriately, they boost the efficiency of your editor. You can hover over a function call and see its signature. You can jump to the definition of an object or function with a keypress. Readability and efficiency matter since code is read more often than it is written.
Another editor benefit is refactoring. If you rename an attribute of a class using an LSP, it will only rename usages of that attribute if the usage is typed. An example clarifies:
# Refactor name -> full_name
class Person:
name: str
# Untyped. This function will not automatically be refactored to use person.full_name
def set_name(person, name):
person.name = name
# Typed. This function will automatically be refactored to use person.full_name
def set_name(person: Person, name: str):
person.name = name
Additionally, static types can make it easier for AI coding tools to understand your code, and by extension, to generate more-correct code. For example, if a function argument has a type annotation, an AI tool can use RAG to locate the type definition and add it to its context automatically.
Given the benefits for developers, it makes sense to add type hints to a codebase where feasible.