Exploring Typing Extensions A Comprehensive Guide with Examples

Introduction to Typing Extensions

The typing-extensions Python library offers support for new type-hinting features introduced in more recent versions of Python. These features can be used with older versions of Python, making it a vital tool for developers aiming to maintain compatibility while adopting the latest typing improvements. In this article, we’ll dive into the most useful APIs provided by typing-extensions and demonstrate how you can leverage them with examples.

1. Setup for Typing Extensions

Before we dive into code snippets, ensure you have the library installed. You can add it to your Python environment using:

  pip install typing-extensions

2. Popular APIs in Typing Extensions

Below is a list of useful APIs provided by typing-extensions, along with their explanations and examples:

2.1. Literal

The Literal type is used to explicitly define a set of constant values a variable can hold.

  from typing_extensions import Literal

  def get_status_color(status: Literal["success", "error", "loading"]) -> str:
      if status == "success":
          return "green"
      elif status == "error":
          return "red"
      elif status == "loading":
          return "yellow"
      else:
          raise ValueError("Invalid status")

  print(get_status_color("success"))  # Output: green

2.2. TypedDict

TypedDict is a way to represent dictionaries with a fixed set of keys and defined types.

  from typing_extensions import TypedDict

  class User(TypedDict):
      id: int
      name: str
      is_active: bool

  user: User = {"id": 1, "name": "Alice", "is_active": True}
  print(user["name"])  # Output: Alice

2.3. Protocol

The Protocol type is used for defining structural subtyping.

  from typing_extensions import Protocol

  class Greeter(Protocol):
      def greet(self, name: str) -> str: ...

  class FriendlyGreeter:
      def greet(self, name: str) -> str:
          return f"Hello, {name}!"

  def greet_person(greeter: Greeter, name: str) -> None:
      print(greeter.greet(name))

  friendly = FriendlyGreeter()
  greet_person(friendly, "Alice")  # Output: Hello, Alice!

2.4. Annotated

Annotated allows attaching metadata to types.

  from typing_extensions import Annotated

  def process_data(age: Annotated[int, "Age in years"]) -> None:
      print(f"Processing data for age: {age}")

  process_data(25)  # Output: Processing data for age: 25

2.5. Working with Final

The Final type declares variables that should not be reassigned.

  from typing_extensions import Final

  PI: Final[float] = 3.14159

  def calculate_circumference(radius: float) -> float:
      return 2 * PI * radius

  print(calculate_circumference(5))  # Output: 31.4159

3. Building a Simple Application

Let us now create a simple task tracking application using typing-extensions features.

  from typing_extensions import TypedDict, Literal

  class Task(TypedDict):
      id: int
      description: str
      status: Literal["pending", "in-progress", "completed"]

  def create_task(task_id: int, description: str) -> Task:
      return {"id": task_id, "description": description, "status": "pending"}

  def update_task_status(task: Task, new_status: Literal["pending", "in-progress", "completed"]) -> Task:
      task["status"] = new_status
      return task

  # Create a task
  task = create_task(1, "Write typing-extensions blog post")
  print(task)

  # Update task status
  task = update_task_status(task, "in-progress")
  print(task)

In this app example, we have shown how TypedDict and Literal can help define clear type constraints for tasks.

4. Conclusion

typing-extensions is a must-have library for Python developers embracing type hints and annotations. From Literal to Protocol, it includes practical tools to improve type safety and readability in your codebase.

Leave a Reply

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