Introduction to typing-extensions
As Python continues to grow as one of the most popular programming languages, maintaining type safety and making codebases more robust has become a priority. Enter the typing-extensions library—a companion to Python’s built-in typing
module. typing-extensions
provides backports of typing features added in newer versions of Python, enabling developers to use these features in older Python versions. Additionally, it introduces experimental features that may be included in future Python versions.
In this blog, we will take a closer look at typing-extensions
by exploring dozens of its powerful APIs, complemented with practical examples and even an app showcasing how to integrate these features effectively.
Dozens of Handy APIs in typing-extensions
1. TypedDict
TypedDict
allows you to define dictionaries with a fixed structure, similar to defining models in a static type system.
from typing_extensions import TypedDict class Movie(TypedDict): title: str year: int rating: float # Example usage my_movie: Movie = {"title": "Inception", "year": 2010, "rating": 8.8}
2. Literal
Use Literal
to define specific literal values that a variable can accept.
from typing_extensions import Literal def set_status(status: Literal["success", "error", "pending"]) -> str: return f"Status set to: {status}" print(set_status("success"))
3. Final
Final
is used to declare constants or methods that should not be overridden or reassigned.
from typing_extensions import Final PI: Final = 3.14159 # Cannot be reassigned class Base: def greet(self) -> str: return "Hello" class Derived(Base): greet: Final = lambda: "Welcome" # Error: Cannot override 'Final' method
4. Annotated
Annotated
allows attaching metadata to types for better clarity or validation purposes.
from typing_extensions import Annotated def calculate_area(radius: Annotated[float, "should be non-negative"]) -> float: return 3.14159 * radius ** 2 print(calculate_area(5.0))
5. Self
The Self
type allows you to annotate methods that return an instance of their class.
from typing_extensions import Self class Builder: def set_option(self) -> Self: # Configure the builder return self def build(self) -> str: return "Object created!" builder = Builder().set_option().build()
6. Required
and NotRequired
These two types fine-tune the requirements for keys in a TypedDict
.
from typing_extensions import TypedDict, Required, NotRequired class Config(TypedDict): host: Required[str] port: Required[int] timeout: NotRequired[int] server_config: Config = {"host": "localhost", "port": 8080}
Practical Example: Task Management App with typing-extensions
Let’s build a simple task management application using some of the features from typing-extensions
:
from typing_extensions import TypedDict, Literal, Final class Task(TypedDict): id: int title: str status: Literal["pending", "in-progress", "completed"] TASK_ID_COUNTER: Final = 1 def create_task(title: str) -> Task: global TASK_ID_COUNTER task: Task = {"id": TASK_ID_COUNTER, "title": title, "status": "pending"} TASK_ID_COUNTER += 1 return task def change_status(task: Task, new_status: Literal["pending", "in-progress", "completed"]) -> Task: task["status"] = new_status return task # Example Usage task1 = create_task("Write blog post about typing-extensions") task1 = change_status(task1, "in-progress") print(task1)
Conclusion
The typing-extensions
library is a powerful companion for Python developers aiming to leverage type annotations effectively. Whether it’s about enforcing type safety or using forward-compatible APIs, typing-extensions
is a crucial tool for any modern Python project. Start integrating it into your project today to write cleaner and more robust code!