Skip to content

Instantly share code, notes, and snippets.

@ramalho
Last active May 26, 2020 19:17
Show Gist options
  • Save ramalho/1ed164b65ec8c36716ca9c90780890b8 to your computer and use it in GitHub Desktop.
Save ramalho/1ed164b65ec8c36716ca9c90780890b8 to your computer and use it in GitHub Desktop.
Python `max()` clone, with type hints in 6 overloads
from typing import Protocol, Any, TypeVar, overload, Callable, Iterable, Union
class Comparable(Protocol):
def __lt__(self, other: Any) -> bool:
...
MISSING = object()
EMPTY_MSG = 'max() arg is an empty sequence'
T = TypeVar('T')
C = TypeVar('C', bound=Comparable)
DT = TypeVar('DT')
@overload
def max(__arg1: C, __arg2: C, *_args: C, key: None = ...) -> C:
...
@overload
def max(__arg1: T, __arg2: T, *_args: T, key: Callable[[T], C]) -> T:
...
@overload
def max(__iterable: Iterable[C], *, key: None = ...) -> C:
...
@overload
def max(__iterable: Iterable[T], *, key: Callable[[T], C]) -> T:
...
@overload
def max(__iterable: Iterable[C], *, key: None = ..., default: DT) -> Union[C, DT]:
...
@overload
def max(__iterable: Iterable[T], *, key: Callable[[T], C], default: DT) -> Union[T, DT]:
...
def max(first, *args, key=None, default=MISSING):
if args:
series = args
candidate = first
else:
series = iter(first)
try:
candidate = next(series)
except StopIteration as exc:
if default is not MISSING:
return default
raise ValueError(EMPTY_MSG) from exc
if key is None:
for current in series:
if candidate < current:
candidate = current
else:
candidate_key = key(candidate)
for current in series:
current_key = key(current)
if candidate_key < current_key:
candidate = current
candidate_key = current_key
return candidate
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment