Last active
July 9, 2023 06:48
-
-
Save wonderbeyond/fdd874f37d86534f23109f153cb671a2 to your computer and use it in GitHub Desktop.
Safe alternative of min/max in Python (the builtin min/max is evil)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Python's builtin min function is evil | |
>>> min(2, 1) | |
1 | |
>>> min([2, 1]) | |
1 | |
>>> min([2]) | |
2 | |
>>> min([]) | |
Traceback (most recent call last): | |
File "<stdin>", line 1, in <module> | |
ValueError: min() arg is an empty sequence | |
>>> min([None]) | |
>>> min([None, 1]) | |
Traceback (most recent call last): | |
File "<stdin>", line 1, in <module> | |
TypeError: unorderable types: int() < NoneType() | |
>>> min(1) | |
Traceback (most recent call last): | |
File "<stdin>", line 1, in <module> | |
TypeError: 'int' object is not iterable | |
>>> min(1, None) | |
Traceback (most recent call last): | |
File "<stdin>", line 1, in <module> | |
TypeError: unorderable types: NoneType() < int() | |
>>> | |
""" | |
from collections import Iterable | |
def _min_max_ignore_none(agg, it=None, *args, **kwargs): | |
""" | |
>>> min = min_ignore_none | |
>>> max = max_ignore_none | |
>>> min(2, 1), min([2, 1]) | |
(1, 1) | |
>>> min(1, None), min(None, 1), min([1, None]) | |
(1, 1, 1) | |
>>> min(1), min([1]), min(*[1]) | |
(1, 1, 1) | |
>>> min(), min([]), min(*[]) | |
(None, None, None) | |
>>> min(x for x in []) | |
>>> min(None), min([None]) | |
(None, None) | |
>>> max(1, 2), max([1, 2]) | |
(2, 2) | |
""" | |
assert agg in (min, max) | |
if isinstance(it, Iterable) and not args: | |
it = [v for v in it if v is not None] | |
if not len(it): | |
return None | |
if args: | |
it = list(args) + [it] | |
it = [v for v in it if v is not None] | |
if not len(it): | |
return None | |
elif it: | |
it = it if isinstance(it, Iterable) else [it] | |
else: | |
return None | |
return agg(it, **kwargs) | |
def min_ignore_none(*a, **kw): | |
return _min_max_ignore_none(min, *a, **kw) | |
def max_ignore_none(*a, **kw): | |
return _min_max_ignore_none(max, *a, **kw) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Your function is almost like a decorator but not really. I would recommend you looking for example at https://realpython.com/primer-on-python-decorators/
Then you can create a decorator which will create your functions like this: