I do not agree clamp should be restricted to numeric values. I would expect
clamp to be agnostic to the specifics of floats/numbers and like sort
expect it to work for any values as long as they compare (using a dunder).
I think having something like min=-math.inf is hence right out in my mind.
If I got this right, the implementation could be as simple as:
def clamp(value, *, min=None, max=None):
if min is not None and value < min:
return min
if max is not None and max < value:
return max
return value
I think the crucial question here is: does the order of the ifs matter and
is that an issue. The only time (barring side effects, values changing in
between calls et cetera) it would make a difference if max < value < min.
Assuming transitivity (can anybody come up with an example of a
non-transitive order where clamping makes sense?) this means max < min and
so you can work around this by disallowing it:
def clamp_safe(value, * min=None, max=None):
if max < min:
raise SomeException("Something about min < max")
return clamp(value, min=min, max=max)
What I like about both of these is that they only use "<", just like sort.
Going back to nans, I think that would mean:
clamp(nan, min, max) = nan
clamp(value, nan, max) = clamp(value, None, max) = max(value, max)
clamp(value, min, nan) = clamp(value, min, None) = min(value, min)
On Mon, 6 Jul 2020 at 02:55, Christopher Barker
and we can use +inf and -inf for unlimited bounds as well. Yes, they are a bit of a pain to write in Python, but we could do:
def clamp(value, min=-math.inf, max=math.inf): ...
yes, that would make them optional, rather than required, and therefore provide a slight asymmetry between specifying min only or max only, but still be handy. to make it more consistent, but maybe more annoying in the common case, we could make them keyword only.