Enhance Your Python Projects with Typing Extensions

Unlock the Power of Typing Extensions in Python

The typing-extensions package is a foundational tool for Python developers who work with type hints, especially for backward compatibility with older Python versions. It provides access to new typing features introduced in the latest versions of Python, even if you’re working with earlier versions. In this blog, we’ll explore the key APIs offered by typing-extensions and demonstrate their use in practical examples.

Understanding typing-extensions: A Game-Changer for Static Typing

As Python type hints evolve, features like Literal, TypedDict, and Protocol are now essential for robust type checking. However, developers maintaining compatibility with older Python releases often face challenges accessing these features. The typing-extensions module bridges this gap by offering backported and experimental typing capabilities.

Key APIs in typing-extensions

Literal

The Literal type allows you to specify exact values that a variable can take.

  from typing_extensions import Literal

  def greet(status: Literal["success", "error"]) -> str:
      if status == "success":
          return "Operation succeeded!"
      elif status == "error":
          return "Operation failed!"
      raise ValueError("Invalid status")

  print(greet("success"))  # Output: Operation succeeded!

TypedDict

The TypedDict API provides a way to define structured dictionaries with fixed keys and their value types.

  from typing_extensions import TypedDict

  class User(TypedDict):
      name: str
      age: int

  user: User = {"name": "Alice", "age": 25}
  print(user["name"])  # Output: Alice

Protocol

The Protocol API provides structural subtyping, enabling the definition of interfaces in Python.

  from typing_extensions import Protocol

  class Flyer(Protocol):
      def fly(self) -> str: ...

  class Bird:
      def fly(self) -> str:
          return "I am flying!"

  def make_fly(flyer: Flyer) -> str:
      return flyer.fly()

  print(make_fly(Bird()))  # Output: I am flying!

Annotated

Annotated adds context-specific metadata to your type hints.

  from typing_extensions import Annotated

  def process(data: Annotated[str, "user input"]) -> str:
      return data.lower()

  print(process("Hello World"))  # Output: hello world

Self

Introduced in Python 3.11 and backported in typing-extensions, the Self annotation allows you to annotate methods that return the type of their class.

  from typing_extensions import Self

  class FluentString:
      def __init__(self, value: str) -> None:
          self.value = value

      def append(self, text: str) -> Self:
          self.value += text
          return self

      def __str__(self) -> str:
          return self.value

  fluent = FluentString("Hello").append(", ").append("World!")
  print(fluent)  # Output: Hello, World!

Unpack

The Unpack API is a powerful feature for unpacking types in variance scenarios.

  from typing_extensions import Unpack
  from typing import Tuple

  Vector = Tuple[int, int, int]

  def scale(*args: Unpack[Vector]) -> Vector:
      return tuple(x * 2 for x in args)

  print(scale(1, 2, 3))  # Output: (2, 4, 6)

Building a Mini-App with typing-extensions

Let’s create a simple Python application using typing-extensions.

  from typing_extensions import Protocol, Literal, TypedDict


  class Vehicle(Protocol):
      def drive(self, mode: Literal["economy", "sport"]) -> str:
          ...


  class Car:
      def drive(self, mode: Literal["economy", "sport"]) -> str:
          if mode == "economy":
              return "Driving in economy mode."
          elif mode == "sport":
              return "Zooming in sport mode!"
          raise ValueError("Unknown mode")


  class Driver(TypedDict):
      name: str
      age: int


  def assign_driver(vehicle: Vehicle, driver: Driver) -> str:
      return (f"{driver['name']} is driving. {vehicle.drive('sport')}")


  car = Car()
  driver: Driver = {"name": "Alice", "age": 30}
  print(assign_driver(car, driver))
  # Output: Alice is driving. Zooming in sport mode!

Conclusion

The typing-extensions module is essential for Python developers who aim to leverage the latest typing features while maintaining compatibility. Its rich set of APIs unlocks incredible opportunities for type safety, code clarity, and better debugging, which makes it an indispensable tool for the Python ecosystem.

Leave a Reply

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