Hi Pascal,

Taking the example of 

def foo(bar = []):

I'm totally with you in thinking that what is 'natural' is to expect to get a new, empty, list every time. However this isn't want happens. As far as I'm concerned, that should more or less be the end of the discussion in terms of what should ideally happen. 

The responses to the change in behaviour which I see as more natural are, to summarise, as follows:
  -- For all sorts of technical reasons, it's too hard
  -- It changes the semantics of the function definition being evaluated at compile time
  -- It's not what people are used to

With regards to the second point, it's not like the value of arguments is set at compile time, so I don't really see that this stands up. I don't think it's intuitive, it's just that people become accustomed to it. There is indeed, *some sense* in understanding that the evaluation occurs at compile-time, but there is also a lot of sense (and in my opinion, more sense) in understanding the evaluation as happening dynamically when the function is called. 

With regards to the first point, I'm not sure that this is as significant as all of that, although of course I defer to the language authors here. However, it seems as though it could be no more costly than the lines of code which most frequently follow to initialise these variables. 

On the final point, that's only true for some people. For a whole lot of people, they stumble over it and get it wrong. It's one of the most un-Pythonic things which I have to remember about Python when programming -- a real gotcha. I don't see it as changing one way of doing things for another equally valid way of doing things, but changing something that's confusing and unexpected for something which is far more natural and, to me, Pythonic.

For me, Python 3k appears to be a natural place to do this. Python 3 still appears to be regarded as a work-in-progress by most people, and I don't think that it's 'too late' to change for Python 3k. Perhaps, given the timing, the people involved, the complexity of change etc, then for pragmatic reasons this may have to be delayed, but I don't think that's a good thing. I'd much rather see it done, personally. I think that many people would feel the same way.


On Sat, May 9, 2009 at 6:31 AM, Pascal Chambon <chambon.pascal@wanadoo.fr> wrote:


I'm surely not original in any way there, but I'd like to put back on the table the matter of "default argument values".
Or, more precisely, the "one shot" handling of default values, which makes that the same mutable objects, given once as default arguments, come back again and again at each function call.
They thus become some kinds of "static variables", which get polluted by the previous calls, whereas many-many-many python users still believe that they get a fresh new value at each function call.
I think I understand how default arguments are currently implemented (and so, "why" - technically - it does behave this way), but I'm still unsure of "why" - semantically - this must be so.

I've browsed lots of google entries on that subject, but as far as I'm concerned, I've found nothing in favor current semantic.
I've rather found dozens, hundreds of posts of people complaining that they got biten by this gotcha, many of them finishing with a "Never put mutable values in default arguments, unless you're very very sure of what you're doing !".

And no one seemed to enjoy the possibilities of getting "potentially static variables" this way. Static variables are imo a rather bad idea, since they create "stateful functions", that make debugging and maintenance more difficult ; but  when such static variable are, furthermore, potentially non-static (i.e when the corresponding function argument is supplied), I guess they become totally useless and dangerous - a perfect way to get hard-to-debug behaviours.

On the other hand, when people write "def func(mylist=[]):", they basically DO want a fresh new list at each call, be it given by the caller or the default argument system.
So it's really a pity to need tricks like
> def f(a, L=None):
> if L is None:
> L = []
to get what we want (and if None was also a possible value ? what other value should we put as a placeholder for "I'd like None or a fresh new list but I can't say it directly ?").

So I'd like to know : are there other "purely intellectual" arguments for/against the current semantic of default arguments (I might have missed some discussion on this subject, feel free to point them ?

Currently, this default argument handling looks, like a huge gotcha for newcomers, and, I feel, like an embarrassing wart to most pythonistas. Couldn't it be worth finding a new way of doing it ?
Maybe there are strong arguments against a change at that level ; for example, performance issues (I'm not good in those matters). But I need to ensure.

So here are my rough ideas on what we might do - if after having the suggestions from expert people, it looks like it's worth writting a PEP, I'll be willing to particpateon it.
Basically, I'd change the python system so that, when a default argument expression is encountered, instead of being executed, it's wrapped in some kind of zero-argument lambda expression, which gets pushed in the "func_defaults" attribute of the function.
And then, each time a default argument is required in a function call, this lambda expression gets evaluated and gives the expected value.

I guess this will mean some overhead during function call, so this might become another issue.
It's also a non retrocompatible change, so I assume we'd have to use a "from __future__ import XXX" until Python4000.
But I think the change is worth the try, because it's a trap which waits for all the python beginners.

So, if this matters hasn't already been marked somewhere as a no-go, I eagerly await the feedback of users and core developpers on the subject. :)

By the way, I'm becoming slightly allergical to C-like languages (too much hassle for too little gain, compared to high level dynamic languages), but if that proposition goes ahead, and no one wants to handle the implementation details, I'll put the hands in the engine ^^


Python-ideas mailing list

Tennessee Leeuwenburg
"Don't believe everything you think"