What is a function parameter =[] for?

BartC bc at freeuk.com
Thu Nov 19 08:19:25 EST 2015


On 19/11/2015 12:19, Steven D'Aprano wrote:
> On Thu, 19 Nov 2015 10:14 am, BartC wrote:

> Consider this pair of functions:
>
>
> def expensive():
>      # Simulate some expensive calculation or procedure.
>      time.sleep(100)
>      return random.randint(1, 6)
>
>
> def demo(arg=expensive()):
>      return arg + 1
>
>
> Now we call the second function four times, without an argument so that the
> default value is used:
>
> demo()
> demo()
> demo()
> demo()
>
> What results do you expect?

If someone /wants/ expensive() to be called each time, then why not? If 
they don't, then it seems easy enough to write:

demo_default=expensive()
def demo(arg=demo_default):
	...

(As you mention later...)

> - if the language defaults to early binding, it is *easy* for the
>    programmer to get late binding semantics;
>
> - if the language defaults to late binding, it is *very difficult*
>    for the programmer to get early binding semantics.

I got the impression that Python was a nice, easy language for everyone 
to use. Not one where you need a Master's degree in CS to understand the 
nuances of! And to understand why something that is so blindingly 
obvious doesn't work.

> But let's try going the other way. Suppose function defaults were evaluated
> each and every time you called the function. How could you *avoid* the
> expense and waste of re-evaluating the default over and over again?

I use default parameters a lot in other languages.

99% of the time the default value is a constant. And most often that 
constant is 0, "" or an empty list.

You want these very common examples to /just work/ instead of going to 
lengths trying to explain why they don't.

> You can't, or at least, not cleanly and easily. The most obvious way is to
> use a global variable:
>
> ARG = expensive()
>
> def demo(arg=ARG):
>      ...
>
> This is ... horrible. You are still evaluating the default each time,

I implement an interpreted language where these calls:

   demo()
   demo(ARG)

would have exactly the same cost.

I understand that Python is very different: at the call-site, the 
compiler has no idea of the number of arguments a function defines or 
what the default values might be, or even if it is a function that is 
being called.

But even under those circumstances, I would endeavour to make such a 
function call as fast as is practical.

(That could involve a runtime check on number of parameters, 
substituting the equivalent of None for missing ones, or whatever 
default expression has been declared.

But here, I am benefiting from my language not being Python which does 
seem to like making things difficult.)

> but at
> least it is only a global variable lookup,

Maybe you can wrap the entire module inside a function? Other than a bit 
at the end that calls that function. Does that solve the global lookup 
problem?

> When you deal with mutable objects, you have to expect them to mutate. The
> whole point of mutability is that their value can change.

That [] doesn't look like an object that could change. It looks like an 
empty list constructor. You would expect a constructor for an empty list 
to yield an empty list throughout a program! (As it does, in most other 
contexts.)

You presumably think differently because you have some inside knowledge 
of how Python works, and know that that [] undergoes a one-time 
assignment to a local, persistent 'default' variable where it's value 
can indeed by changed. (Thanks to another Python feature where an 
assignment is a very shallow copy of an object.) And it is that volatile 
variable that is the actual default.

But not everyone is going to know that.

-- 
Bartc



More information about the Python-list mailing list