Introduction:
Python is known for its versatility and dynamic nature, but type hinting has become a cornerstone in improving code readability, debugging, and particularly in working with large-scale projects. Typing-Extensions is an incredible library that extends the capabilities of Python’s built-in typing
module, enabling developers to use cutting-edge type hinting features, even if they aren’t yet available in your specific Python interpreter. Let’s dive into how you can unlock its potential with examples.
What is Typing-Extensions?
The typing-extensions package provides experimental and backported features from the typing
module. It allows developers to use advanced features introduced in recent Python versions while maintaining compatibility with older versions. Here are some tools and functionalities provided by the library:
- Protocol
- TypedDict
- Literal
- Final
- Annotated
- Self
- Concatenate
- NewType
- Custom String Interpolation with IntStr
- And more!
Typing-Extensions API Examples
1. TypedDict
The TypedDict
allows you to define type-safe dictionaries where the key is a string and the value has a specified type.
from typing_extensions import TypedDict class Movie(TypedDict): name: str year: int my_movie: Movie = {"name": "Inception", "year": 2010} print(my_movie["name"]) # Output: Inception
2. Protocol
Protocols define structural subtyping, helping check object compatibility by their methods and properties rather than their class inheritance.
from typing_extensions import Protocol class Flyer(Protocol): def fly(self) -> str: ... class Airplane: def fly(self) -> str: return "Airplane is flying" def test_flyer(flyer: Flyer) -> None: print(flyer.fly()) airplane = Airplane() test_flyer(airplane) # Output: Airplane is flying
3. Literal
You can use the Literal
feature to specify that a variable may only accept certain predefined values.
from typing_extensions import Literal def get_status(status: Literal["active", "inactive"]) -> str: return f"Status is {status}" print(get_status("active")) # Output: Status is active
4. Final
Use @Final
to define constants or methods that shouldn’t be overridden.
from typing_extensions import Final PI: Final = 3.14159 print(PI) # Output: 3.14159
5. Annotated
The Annotated
feature allows attaching metadata to type hints, useful for validation or display purposes.
from typing_extensions import Annotated def calculate_radius(distance: Annotated[float, "Distance in meters"]) -> float: return distance * 3.14 # Simplified formula
6. Concatenate
With Concatenate
, you can bind positional arguments with specific types and methods.
from typing_extensions import Concatenate, Callable def logger(msg: str, *, level: int) -> None: print(f"[LEVEL {level}]: {msg}") def bind_logger(func: Callable[Concatenate[str, None]]) -> Callable: def wrapper(*args) -> None: return func(*args) return wrapper
A Practical Example: Task Management App
Combining these APIs, let’s create a well-typed task management app:
from typing_extensions import TypedDict, Literal, Annotated, Final # Define a constant APP_NAME: Final = "Task Manager" # TypedDict for task representation class Task(TypedDict): id: int title: str status: Literal["pending", "completed"] # Function to create a new task def create_task(task_id: int, title: Annotated[str, "Task title"]) -> Task: return {"id": task_id, "title": title, "status": "pending"} # Function to change the status of a task def update_task_status(task: Task, status: Literal["pending", "completed"]) -> Task: task["status"] = status return task # Main App Simulation print(f"Welcome to {APP_NAME}") task = create_task(1, "Type blog post") print(f"Created Task: {task}") task = update_task_status(task, "completed") print(f"Updated Task: {task}")
By leveraging typing-extensions
, your Python app becomes future-proof, well-typed, and easier to maintain. Dive into the source code and create scalable, type-safe Python projects.