Comprehensive Guide to Python typing-extensions Unlocking Advanced Type Hinting for Better Code

Introduction to typing-extensions

The typing-extensions library is an essential tool for any Python developer looking to harness the full power of type hinting. It provides backports of new type hinting features from later versions of Python that can be used in earlier versions. This makes it easier to maintain modern, type-safe Python code. Below, we explore dozens of useful APIs from the typing-extensions library with helpful code snippets.

Dozens of Useful APIs from typing-extensions

1. TypedDict

TypedDict allows for more precise type hinting for dictionaries.

 from typing_extensions import TypedDict
class Movie(TypedDict):
    title: str
    year: int

movie: Movie = {'title': 'Inception', 'year': 2010} 

2. Literal

The Literal type allows you to specify that a function parameter must be a specific value.

 from typing_extensions import Literal
def get_status(status: Literal['open', 'closed']) -> str:
    return f'Status is {status}'

status = get_status('open') 

3. Final

Final is used to denote that a variable or method should not be overridden.

 from typing_extensions import Final
MAX_ITEMS: Final = 100 

4. TypedDict with Total

You can use the Total argument with TypedDict to indicate whether a dictionary needs to include all keys.

 from typing_extensions import TypedDict
class Movie(TypedDict, total=False):
    title: str
    year: int

movie: Movie = {'title': 'Interstellar'} 

5. Protocol

Protocol is used to define structural subtyping in Python.

 from typing_extensions import Protocol
class Greetable(Protocol):
    def greet(self) -> str:
        ...

class Person:
    def greet(self) -> str:
        return "Hello"

def greet_all(greetables: list[Greetable]) -> None:
    for g in greetables:
        print(g.greet())

people = [Person()] greet_all(people) 

6. runtime_checkable

runtime_checkable decorator can be used to enable isinstance checks against protocols.

 from typing_extensions import Protocol, runtime_checkable
@runtime_checkable class Greetable(Protocol):
    def greet(self) -> str:
        ...

class User:
    def greet(self) -> str:
        return "Hi"

user = User() assert isinstance(user, Greetable) 

7. NewType

NewType allows creating distinct types for better static type checking.

 from typing_extensions import NewType
UserID = NewType('UserID', int)
def get_user_name(user_id: UserID) -> str:
    return f'User_{user_id}'

user_id = UserID(42) user_name = get_user_name(user_id) 

App Example Using typing-extensions

Let’s build a simple user management application using some of the APIs discussed above.

 from typing_extensions import TypedDict, Literal, Final, Protocol, runtime_checkable, NewType
UserID = NewType('UserID', int) MAX_USERS: Final = 100
class User(TypedDict):
    id: UserID
    name: str

class Greetable(Protocol):
    def greet(self) -> str:
        ...

@runtime_checkable class UserGreetable(Greetable, Protocol):
    name: str

def add_user(users: list[User], user: User) -> None:
    if len(users) < MAX_USERS:
        users.append(user)
    else:
        raise ValueError("Max users limit reached")

def greet_user(user: UserGreetable) -> str:
    return f'Hello, {user.name}'

def user_status(user: User, status: Literal['active', 'inactive']) -> str:
    return f'User {user["name"]} is {status}'

existing_users: list[User] = []
new_user: User = {'id': UserID(1), 'name': 'Alice'} add_user(existing_users, new_user)
for user in existing_users:
    print(greet_user(user))
    print(user_status(user, 'active'))

Leave a Reply

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