Unlock the Power of Typing Extensions for Python Supercharging Your Code with Typing Extensions APIs and Examples

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.

Leave a Reply

Your email address will not be published. Required fields are marked *