mutable default parameter problem [Prothon]

Mark Hahn mark at
Wed Jun 16 08:52:33 CEST 2004

Troy Melhase wrote:

> Here's an idea:  if it ain't broke, don't fix it.
> Seriously, you see a "wart" and a "problem".  I see a pleasant
> side-effect of the documented semantics.  True, new folks are
> surprised by the behavior, but once it's understood, it becomes more
> powerful.

All four of the Python gotcha's, wart's and regrets lists I have found
included this problem.  It is not only a newbie's problem as I showed in my

> How do you intend to account for code like this:
> def F(a, b, cache={}):
>     try:
>         return cache[(a,b)]
>     except (IndexError, ):
>         value = cache[(a,b)] = do_some_long_calc(a,b)
>         return value
> Or even this:
> shared_cache = {}
> def F(a, b, cache=shared_cache):
>     ...

The first example is very unreadable and uncool in general.  Your second
example will work just fine with our fix.

> Of course you can argue that this is bad style,

Yes I (and many others) will.

> but the counter
> argument is just as strong:  this is quite pythonic and quite
> readable.

I disagree strongly.  I would never be caught coding something like that and
I love Python dearly.

> Python is a tool, and you decrease the utility of that tool when you
> limit it's idioms.

So far you have only shown me an idiom that many say should not be used.
Show me one that everyone agrees is useful.

>> How much Python code would these different proposals break?
> A lot.  I ran this:
> $  find /usr/lib/python2.3/ -name "*.py" -exec grep "def.*=\[\]" {}
> \; | wc
> And see 67 instances just in the standard library.  Multiply that by
> a factor of 1000, 10000 or more to reflect code in the field, and you
> might start to understand the significance of changing the language
> definition.

That count is not accurate.  Fixing this will not break every use of [] as a
default formal param.  Using [] in __init__ for example would break nothing.
I can think of many other cases where it is legal to use [].  The only case
I can think of that would break would be the idiom we disagree on above.  If
I am wrong, then show me other cases.

If I also might make a general argument for the fix then let me continue.
Doing a late evaluation of the default expression makes the language more
dynamic, which fits the overall goal of making Prothon more dynamic.  Using
prototypes instead of classes, dynamic var scoping, this fix, and many other
Prothon changes from Python all work towards that goal.

Dynamic var scoping fixed another Python gotcha which doesn't break
anything.  Here are the two versions of code showing the problem and the

--- Python ---

>>> x = 1
>>> def f():
...         x = x + 1
...         print x
>>> f()
UnboundLocalError: local variable 'x' referenced before assignment

--- Prothon ---

O>> x = 1
O>> def f():
...        x = x + 1
...        print x
O>> f()

Prothon's scoping rules are dynamic which means that x comes from outside
the function until the actual assignment happens.  At that point x becomes a
local variable.  This, along with the fact that vars are inherited from
ancestors along with methods, allow for some intuitive and simple var
initialization techniques.

Obviously it is the responsibility of the programmer to make sure that the
outer x has the proper initialization value for the local x.  This can cause
a hiding-of-uninitialized-vars bug if the programmer uses the same names for
unrelated variables but it is worth the extra power and intuitiveness.

More information about the Python-list mailing list