Optional parameter object re-used when instantiating multiple objects

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Sun Nov 16 07:52:05 CET 2008


On Sat, 15 Nov 2008 21:29:22 -0800, Aaron Brady wrote:

> I don't think Dennis or Steven read your post very well.

It's possible.

> You said 'Why
> does Python do X?', and 'It seems natural to you to do not X'. Dennis
> and Steven both said, 'Python does X'.

I also disputed that it is natural to do not-X (runtime creation of 
default arguments), and explained why such an interpretation doesn't 
match with the way Python operates. I admit I didn't answer the "why" 
part.

 
> Steven did get around to suggesting an answer though.  He said:
> 
>> If you want something to be
>> created each time the function is called, you have to put it inside the
>> body of the function:

If you want to be pedantic, then my "answer" (which you seem to approve 
of) doesn't correspond to either of the original poster's questions. If 
you're going to be pedantic, then be pedantic all the way, and criticize 
me for answering a question that wasn't asked :-P


> Taking this to be true, the answer to your question is, 'Because the
> object isn't created inside the body of the function,' or, 'Because the
> argument list is outside the body of the function'.

Actually, the correct answer to "Why?" would be "Because that's the 
decision Guido van Rossum made back in the early 1990s when he first 
started designing Python". That of course leads to the obvious question 
"Why did he make that decision?", and the answer to that is:

* it leads to far more efficient performance when calling functions;

E.g. if the default value is expensive to calculate, it is better to 
calculate it once, when the function is created, than every single time 
the function is called.

Additionally, the effbot once mentioned in a similar thread that there 
are real performance benefits in the Python VM from binding the default 
value once only. I don't know the exact details of that, but I trust 
Fredrik knows what he's talking about.


* it has less scope for surprise when calling functions.

E.g. I would argue that most people would be surprised, and dismayed, if 
this code fails:

x = 1
def foo(a, b=x):
   return a+b

del x
print foo(2)


> From your post, it's hard to tell whether this 'duh'-type observation
> would point out the salient feature of the construct, or whether you're
> after something deeper.
> 
> If you're asking, 'Why isn't the argument list considered to be inside
> the body?', then the answer is, it's pretty much arbitrary.

No, it is not an arbitrary choice. I've given practical reasons why the 
Python choice is better. If you want default argument to be created from 
scratch when the function is called, you can get it with little 
inconvenience, but the opposite isn't true. It is very difficult to get 
static default arguments given a hypothetical Python where default 
arguments are created from scratch. There's no simple, easy idiom that 
will work. The best I can come up with is a convention:

# Please don't change this, or strange things will happen.
_private = ResultOfExpensiveCalculation()

def foo(a, b=_private):
    return a+b

The above is still vulnerable to code accidentally over-writing _private 
with some other value, or deleting it, but at least we avoid the 
expensive calculation every time.

Or possibly:

def foo(a, b=foo._private):
    return a+b

foo._private = ResultOfExpensiveCalculation()

which has obvious disadvantages with regard to shadowing, renaming, 
anonymous functions, and so forth.



> Regardless
> of which one the author of Python chose, the other's workaround would be
> equally short, 

Not true. One has an obvious workaround, the other only has a *partial* 
workaround.

> and neither one is obviously indicated by the syntax.

I would disagree, but not enough to argue.


-- 
Steven



More information about the Python-list mailing list