Welcome to the World of typing-extensions
The typing-extensions
library is a crucial component in Python’s type hints ecosystem. It serves as a backport of typing features introduced in newer versions of Python, giving developers the ability to use these modern features even in older Python environments. In this article, we’ll explore its offerings and demonstrate its powerful APIs through concrete code examples.
What is typing-extensions
?
The typing-extensions
library is an add-on that lets you use forward-compatible typing features. Typically, if a typing-related feature is introduced in Python 3.x, the library allows developers using earlier versions to still take advantage of it.
Key APIs with Examples
1. TypedDict
TypedDict
allows you to define dictionaries with a specific structure.
from typing_extensions import TypedDict class Movie(TypedDict): title: str year: int movie: Movie = {"title": "Inception", "year": 2010}
2. Literal
The Literal
type defines constraints on what values a variable can take.
from typing_extensions import Literal def get_status(status: Literal["success", "failure"]) -> str: return f"Status: {status}" print(get_status("success")) # Correct print(get_status("error")) # Type-checking error
3. Protocol
Protocol
allows you to define structural subtyping by specifying methods and attributes that implementing objects must have.
from typing_extensions import Protocol class Greeter(Protocol): def greet(self) -> str: pass class HelloGreeter: def greet(self) -> str: return "Hello!" def show_greeting(greeter: Greeter) -> None: print(greeter.greet()) greeter = HelloGreeter() show_greeting(greeter) # Output: Hello!
4. Final
The Final
type prevents reassignment of variables.
from typing_extensions import Final PI: Final = 3.14159 PI = 3 # Type-checking error due to reassignment
5. NotRequired
and Required
These types work within TypedDict
classes to mark optional and mandatory fields.
from typing_extensions import TypedDict, NotRequired class User(TypedDict): username: str email: NotRequired[str] user: User = {"username": "johndoe"}
6. Self
The Self
type enables better support for method chaining.
from typing_extensions import Self class Builder: def __init__(self) -> None: self.data = "" def add(self, text: str) -> Self: self.data += text return self def build(self) -> str: return self.data builder = Builder() print(builder.add("Hello, ").add("world!").build()) # Hello, world!
A Mini Application Example
Here’s a Python application demonstrating versatile usage of typing-extensions
APIs.
from typing_extensions import TypedDict, Self, Protocol, Literal, Final # Using Final BASE_URL: Final = "https://api.example.com" # Define a TypedDict class User(TypedDict): username: str email: str age: int # Use Protocol for structural typing class Greeter(Protocol): def greet(self, user: User) -> str: pass # Implementation class WelcomeGreeter: def greet(self, user: User) -> str: return f"Welcome, {user['username']}!" # Builder using Self class APIRequestBuilder: def __init__(self) -> None: self.endpoint = "" self.params = {} def set_endpoint(self, endpoint: str) -> Self: self.endpoint = endpoint return self def add_param(self, key: str, value: str) -> Self: self.params[key] = value return self def build(self) -> str: param_str = "&".join(f"{k}={v}" for k, v in self.params.items()) return f"{BASE_URL}/{self.endpoint}?{param_str}" # Using Literal for constrained values def fetch_status(status: Literal["ok", "error"]) -> str: return f"API returned: {status}" # Example usage greeter = WelcomeGreeter() user: User = {"username": "Alice", "email": "alice@example.com", "age": 25} print(greeter.greet(user)) builder = APIRequestBuilder() url = builder.set_endpoint("users").add_param("id", "123").build() print(url) print(fetch_status("ok"))
Conclusion
typing-extensions
is a treasure trove of modern typing features. From TypedDict
to Protocol
and Literal
, it empowers Python developers to craft more robust, maintainable, and error-free code. Whether you’re working with older Python versions or just love the extra capabilities, integrating this library is a no-brainer.