Optional parameter object re-used when instantiating multiple objects
Steven D'Aprano
steve at REMOVE-THIS-cybersource.com.au
Sun Nov 16 01:52:05 EST 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