Advanced Type Annotations
Generic Types
from typing import TypeVar, Generic, List
T = TypeVar('T')
class Stack(Generic[T]):
def __init__(self):
self.items: List[T] = []
def push(self, item: T) -> None:
self.items.append(item)
def pop(self) -> T:
return self.items.pop()
Type Aliases
from typing import Dict, List, Union
UserID = int
Username = str
UserData = Dict[Username, Union[str, int]]
def process_users(users: Dict[UserID, UserData]) -> None:
pass
Protocol Types
from typing import Protocol, runtime_checkable
@runtime_checkable
class Drawable(Protocol):
def draw(self) -> None:
...
class Circle:
def draw(self) -> None:
print("Drawing circle")
def render(obj: Drawable) -> None:
obj.draw()
Literal Types
from typing import Literal
def set_log_level(level: Literal['DEBUG', 'INFO', 'WARNING', 'ERROR']) -> None:
print(f"Log level set to {level}")
## Valid calls
set_log_level('DEBUG')
set_log_level('INFO')
Type Annotation Techniques
Technique |
Description |
Example |
TypeVar |
Create generic type variables |
T = TypeVar('T') |
Protocols |
Define structural typing |
class Drawable(Protocol) |
Literal Types |
Restrict to specific values |
Literal['red', 'green'] |
Generic Classes |
Create type-flexible classes |
class Stack(Generic[T]) |
Complex Type Compositions
from typing import Callable, List, Optional
def compose(
func1: Callable[[int], str],
func2: Callable[[str], Optional[float]]
) -> Callable[[int], Optional[float]]:
def composed(x: int) -> Optional[float]:
intermediate = func1(x)
return func2(intermediate)
return composed
Conditional Type Hints
flowchart TD
A[Type Annotation] --> B{Complex Type?}
B -->|Yes| C[Use Advanced Typing Techniques]
B -->|No| D[Simple Type Annotation]
Runtime Type Checking
from typing import Any, cast
def safe_convert(value: Any, type_: type) -> Optional[Any]:
try:
return cast(type_, value)
except (TypeError, ValueError):
return None
LabEx Pro Tip
LabEx recommends mastering advanced type annotations to create more robust and self-documenting Python code.
- Type hints are evaluated at definition time
- No runtime performance overhead
- Useful for static type checking
- Improve code readability and maintainability
Advanced Use Cases
- Creating flexible generic data structures
- Implementing type-safe callback systems
- Defining complex type relationships
- Enhancing code documentation
- Supporting static type analysis tools