Write a TypeGuard for a two-item coordinate
Also published in our Blogger archive.
Write a TypeGuard for a two-item coordinate
Data arriving as object cannot safely be treated as a coordinate merely because it is iterable. A TypeGuard lets one predicate both perform concrete runtime checks and tell a static type checker what is true on the successful branch. Here, is_coordinate accepts only a tuple of length two whose members are actual float instances. That intentionally rejects lists, integer pairs, and booleans; the last distinction matters because bool is an int subclass, although this particular predicate asks for floats.
The valid input (3.5, -2.0) reaches format_coordinate, which destructures it and produces the exact output. The assertions also make the rejected shapes visible in the executable example. TypeGuard does not make arbitrary inputs valid at runtime, and its annotation does not test values by itself: correctness depends on the predicate remaining aligned with the promised type. A false result also does not generally narrow the type for static analysis. typing.TypeGuard was added in Python 3.10.
See the official typing TypeGuard documentation. AI assistance disclosure: this article was drafted with AI assistance and checked using a synthetic example.
from typing import TypeGuard
def is_coordinate(value: object) -> TypeGuard[tuple[float, float]]:
return (
isinstance(value, tuple)
and len(value) == 2
and all(isinstance(part, float) for part in value)
)
def format_coordinate(point: tuple[float, float]) -> str:
x, y = point
return f"x={x:.1f}, y={y:.1f}"
candidate: object = (3.5, -2.0)
assert is_coordinate(candidate)
assert not is_coordinate([3.5, -2.0])
assert not is_coordinate((3.5, 2))
print(format_coordinate(candidate))
x=3.5, y=-2.0