Skip to content

Instantly share code, notes, and snippets.

@rhettinger
Created November 17, 2021 15:32
Show Gist options
  • Save rhettinger/cc6451b60e8ee7e9b022a6e61227ffd7 to your computer and use it in GitHub Desktop.
Save rhettinger/cc6451b60e8ee7e9b022a6e61227ffd7 to your computer and use it in GitHub Desktop.
Emulate max() as fully as possible in pure Python.
'Emulate max() as fully as possible in pure Python.'
# https://stackoverflow.com/questions/69997857/implementation-of-max-function-in-python/69997876#69997876
from typing import TypeVar, Any, Iterator, Iterable, Optional
from typing import Union, Protocol, Callable, overload
class SupportsGT(Protocol):
def __gt__(self, other: Any) -> bool:
...
T = TypeVar('T', bound=SupportsGT)
D = TypeVar('D')
class Sentinel(object):
pass
sentinel = Sentinel()
def mymax_backend(
first_value: T,
it: Iterator[T],
key: Optional[Callable[[T], Any]],
) -> T:
largest = first_value
if key is None:
for x in it:
if x > largest:
largest = x
return largest
largest_key = key(largest)
for x in it:
kx = key(x)
if kx > largest_key:
largest = x
largest_key = kx
return largest
def mymax_argsonly(*args: T, key: Optional[Callable[[T], Any]] = None) -> T:
if not args:
raise TypeError('max expected at least 1 argument, got 0')
it = iter(args)
largest = next(it)
return mymax_backend(largest, it, key)
def mymax_iterable_only(
iterable: Iterable[T],
/,
*,
default: Union[Sentinel, D] = sentinel,
key: Optional[Callable[[T], Any]] = None,
) -> Union[D, T]:
it = iter(iterable)
largest = next(it, sentinel)
if isinstance(largest, Sentinel):
if not isinstance(default, Sentinel):
return default
raise ValueError('max() arg is an empty sequence')
return mymax_backend(largest, it, key)
@overload
def mymax(
*args: T,
key: Optional[Callable[[T], Any]],
) -> T:
...
@overload
def mymax(
iterable: Iterable[T],
/,
*,
default: Union[Sentinel, D],
key: Optional[Callable[[T], Any]],
) -> Union[D, T]:
...
def mymax(
*args: Union[T, Iterable[T]],
default: Union[Sentinel, D] = sentinel,
key: Optional[Callable[[T], Any]] = None,
) -> Union[D, T]:
"""max(iterable, *[, default=obj, key=func]) -> value
max(arg1, arg2, *args, *[, key=func]) -> value
With a single iterable argument, return its biggest item. The
default keyword-only argument specifies an object to return if
the provided iterable is empty.
With two or more arguments, return the largest argument.
"""
if len(args) == 1:
assert isinstance(args, Iterable)
return mymax_iterable_only(*args, default=default, key=key)
if default is not sentinel:
raise TypeError(
'Cannot specify a default for max() with multiple positional arguments'
)
return mymax_argsonly(*args, key=key)
assert mymax_argsonly('bob', 'adam') == 'bob'
assert mymax_argsonly('adam', 'bob') == 'bob'
assert mymax_argsonly('bob', 'adam', key=len) == 'adam'
assert mymax_argsonly('adam', 'bob', key=len) == 'adam'
assert mymax('bob', 'adam') == 'bob'
assert mymax('adam', 'bob') == 'bob'
assert mymax('bob', 'adam', key=len) == 'adam'
assert mymax('adam', 'bob', key=len) == 'adam'
assert mymax_iterable_only(['bob', 'adam']) == 'bob'
assert mymax_iterable_only(['adam', 'bob']) == 'bob'
assert mymax_iterable_only([], default=10) == 10
assert mymax_iterable_only(['bob', 'adam'], key=len) == 'adam'
assert mymax_iterable_only(['adam', 'bob'], key=len) == 'adam'
assert mymax(['bob', 'adam']) == 'bob'
assert mymax(['adam', 'bob']) == 'bob'
assert mymax([], default=10) == 10
assert mymax(['bob', 'adam'], key=len) == 'adam'
assert mymax(['adam', 'bob'], key=len) == 'adam'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment