r/learnpython • • 1d ago

Confusing code min() max()

I'm debugging some code and I found this function

   import math

       def Clamp(n, smallest, largest):
           return max(smallest, min(n, largest))

surely that code is just wrong? and needs to be max([smallest, min([n, largest])) by passing a list not unnamed args for default and key? I need a sanity check here.

0 Upvotes

16 comments sorted by

14

u/NewbornMuse 1d ago

You can sanity check this yourself!

If you open an interactive python session, does max(3, 6, 10, -2) generate an error or does it return something? If so, what?

What kind of error would you expect if you call something with wrong arguments? Are you seeing anything like that, or is it something completely different?

What does the python documentation say about max and min?

1

u/khosrua 1d ago

I assume the function is defined with a variable length positional argument? So it gets converted to a list regardless.

-6

u/zaphodikus 1d ago

I must be much more tired than most folk, hence the question :-)

4

u/Langdon_St_Ives 22h ago

I love how hours after the correct answer has already been given, people still respond with explanations what this clamp() function is meant to do, when it's clear OP knows full well what it does... 😂

1

u/zaphodikus 20h ago

I had not had much sleep at all, it was to help guear a line of code throwing a divide by zero. Now if only I had as many people looking at the other question I had about windows firewalls.... which is no longer urgent, that issue annoyingly stopped reproducing, so back to the drawing board, or, get more sleep.

Flipping between C#, C++ and Python is not good Karma I suspect. Sleep first Dave.

7

u/lfdfq 1d ago

Let's look at the documentation for min and max.

https://docs.python.org/3/builtins/functions.html#min https://docs.python.org/3/builtins/functions.html#max

min(iterable, /, *, key=None)¶
min(iterable, /, *, default, key=None)
min(arg1, arg2, /, *args, key=None)

So it has multiple signatures, one that takes an iterable and a default, another takes multiple (at least 2) args. The / separates the positional-only (on left) from positional-or-keyword (on the right), the * means all parameters after that are keyword-only. So default must be passed by keyword.

The text in the doc makes this clearer:

If two or more positional arguments are provided, the largest of the positional arguments is returned.

3

u/zaphodikus 1d ago

Ah I did suspect it was relying on positional parameter magic and that default and key were named args , forgot all about what that / does, panic for me is over. I still need to find why the Font in question is tripping me on divide by zero for a size, but that's on me.

2

u/ExpertSentence4171 20h ago

Capitalized function name. Eww

1

u/zaphodikus 20h ago

yeah, that's why it hurt my eyes, but it's not my code I ,,, well that's not true, he left, it's mine now.

14

u/TheBB 1d ago
In [1]: max?
Docstring:
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.

max(x, y) is perfectly fine. Same for min obviously.

key and default can only be given as keyword arguments.

5

u/tea-drinker 1d ago

The functions are implemented so they can accept either a list or multiple arguments.

https://github.com/python/cpython/blob/da20d7401de97b425897d3069f71f77b039eb16f/Python/bltinmodule.c#L1718 for the source code where it checks what you passed to it.

0

u/Wise-Emu-225 1d ago

Look at the docs and see if they need a list as an argument. Min an max can probably have an arbitrary nr of args. Sometimes both is possible. I guess the code is fine.

Edit: unless it doesn’t do what was meant. Which is difficult to judge with no context.

0

u/t92k 22h ago

It looks like it is a kind of absolute function — if n is between smallest and largest you get n back; if n is above largest you get largest back, if n is below smallest you get smallest back. Are you expecting it to do something different?

-1

u/JamzTyson 1d ago

Try plugging some values in, and figure out what happens.

Example:

largest = 10
smallest = 5

Now consider values of n from 1 to 12.

Try figuring out the results in your head, then run the code to check your answers.

-1

u/deanominecraft 1d ago

python allows functions to take an arbitrary amount of arguments as a list, using a * in the function signature (calling it args is just a convention), try experiment with this code:

def mean(*args):
    total=0
    for i in args:
        total+=i
    return total
print(mean(5,194, 28,8,69) #prints the mean

you can also do this with a dictionary by using ** (once again kwargs is just a convention, it can be called whatever you want) eg:

def hello(**kwargs):
    try:
        print(f"hi {kwargs["name"]}")
    except:
        print("hi, you didnt tell me your name")
print(myfunc(name="john")) # prints hi john
print(myfunc(john="name")) # prints hi, you didnt tell me your name

min and max have some extra logic to do with types so that you can also pass in a list, but for functions like mine that dont do that, you can unpack the arguments from a list or dictionary like this:

mean(*mylist)
hello(**mydict)

-1

u/deadeye_82_1 23h ago

Yes, that's very confusing.

In this combination:
min is the largest value, or n
max is the smallest value, or the value of min