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
--
https://mail.python.org/mailman/listinfo/python-list