There are limits to anyone arguing for designs to be the way they want or 
expect and Roel has explained this one below.

When it comes to designing a function, lots of rules people expect are beyond 
irrelevant. Many functions can be implemented truly hundreds of ways with 
varying numbers of arguments and defaults and other effects. I can make a 
function that raises the first argument to a power specified in the second 
argument with no defaults and you get a syntax error for calling it with one 
argument or more than two arguments. Or I can make the second argument use a 
keyword with a default of 1, or 2 or whatever I wish and it can now be called 
with one argument to get the default or two but not more. Or, I can have the 
function absorb all additional arguments and ignore them or even use them as 
additional powers to be raised to so pow(2, 3, 4, 5) returns a tuple or list of 
8, 16, 32.  Or maybe not and it would return ((2^3)^4)^5 or any other nonsense 
you design.

There IS NO CONSISTENCY possible in many cases unless you make a family of 
similarly named functions and add some thing to each name to make it clear.

Python arguably is harder than some languages in this regard as it allows way 
more flexibility. If a function accepts an iterator, and another does not, the 
call may superficially looks the same but is not. 

So, yes, max() could have been designed differently and you can even design 
your own mymax() and mysum() to check the arguments they receive and re-arrange 
them in a way that lets you call the original max/sum functions potentially in 
the same ways. 

But as a general rule, when using a function, don't GUESS what it does or infer 
what it does and then complain when someone says you should have read the 
manual. There are too many design choices, often done by different programmers 
and often motivated by ideas like efficiency. You likely can not guess many of 
them.

And lots of python functions you write can make use of all kinds of features 
such as caching results of previous computations or holding on to variables 
such as what you asked for last time so it can be used as a default. If I write 
a function like go(direction=something, distance=something) then perhaps my 
design will remember the last time it was invoked and if you call it again with 
no arguments, it may repeat the same action, or if only one is given, the other 
is repeated. But on a first call, it may fail as it has no memory yet of what 
you did. That may be intuitive to some and not others, but would it make as 
much sense for another function to be designed the same way so it tolerates 
being called with no arguments when this makes less sense? Do I often want to 
call for sin(x) and later for just sin() and expect it to mean that it be 
repeated?

But back to the original question about max/sum it gets weirder. Although max() 
takes any number of arguments, it really doesn't. There is no way to get the 
maximum of a single argument as in max(5) because it is designed to EITHER take 
one iterable OR more than one regular argument. 

So one case that normally fails is max([]) or any empty iterable and you can 
keep it from failing with something like max([], default=0) .

In your own code, you may want to either design your own functions, or use them 
as documented or perhaps create your own wrapper functions that carefully 
examine what you ask them to do and re-arrange as needed to call the 
function(s) you want as needed or return their own values or better error 
messages.  As a silly example, this fails:

max(1, "hello")

Max expects all arguments to be of compatible types. You could write your own 
function called charMax() that converts all arguments to be of type str before 
calling max() or maybe call max(... , key=mycompare) where compare as a 
function handles this case well.

The key point is that you need to adapt yourself to what some function you want 
to use offers, not expect the language to flip around at this point and start 
doing it your way and probably breaking many existing programs.

Yes, consistency is a good goal. Reality is a better goal.




-----Original Message-----
From: Python-list <python-list-bounces+avi.e.gross=gmail....@python.org> On 
Behalf Of Roel Schroeven
Sent: Tuesday, February 21, 2023 1:11 PM
To: python-list@python.org
Subject: Re: Tuple Comprehension ???

Hen Hanna schreef op 21/02/2023 om 5:13:
>                  (A)   print( max( * LisX ))
>                  (B)   print( sum( * LisX ))        <------- Bad syntax !!!
>
> What's most surprising is....     (A)  is ok, and  (B) is not.
>
>             even tho'   max() and sum()  have   (basically)  the same 
> syntax...  ( takes one arg ,  whch is a list )
>
There's an important difference in syntax.

sum() takes an iterable:

sum(iterable, /, start=0)
     Return the sum of a 'start' value (default: 0) plus an iterable of numbers

     When the iterable is empty, return the start value.
     This function is intended specifically for use with numeric values and may
     reject non-numeric types.

max() on the other hand takes either an iterable or a number of individual 
elements:

max(...)
     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.

That second form of max is why max(*some_list) works while
sum(*some_list) doesn't.

--
"You can fool some of the people all the time, and all of the people some of 
the time, but you cannot fool all of the people all of the time."
         -- Abraham Lincoln
"You can fool too many of the people too much of the time."
         -- James Thurber

--
https://mail.python.org/mailman/listinfo/python-list

-- 
https://mail.python.org/mailman/listinfo/python-list

Reply via email to