[Python-ideas] fixing mutable default argument values

Chris Rebert cvrebert at gmail.com
Fri Jan 26 04:36:33 CET 2007


So, basically the same as my proposal except without syntax changes and 
with the <Foo()> default argument value semantics applied to all 
arguments. I'm okay with this, however some possible performance issues 
might exist with re-evaluating expensive default arg vals on every call 
where they're required. This is basically why my proposal required new 
syntax, so that people could use the old "eval once at definition-time" 
semantics on expensive default values to get better performance.

Also, since people (including me) don't really like the <>-syntax, I've 
come up with some real syntax possibilities for my proposal:

     def foo(bar=new baz):

     def foo(bar=fresh baz):

     def foo(bar=separate baz):

     def foo(bar=another baz):

     def foo(bar=unique baz):

I personally like 'fresh'. It seems accurate and not too long.
I welcome other thoughts on better syntax for this.

If the performance issues aren't significant, I'm all for your proposal. 
  It'd be nice to not to have to add new syntax.

- Chris Rebert

Jan Kanis wrote:
> I don't like new syntax for something like this, but I think the default 
> argument values can be fixed with semantic changes (which should not 
> break the most common current uses):
> 
> What I think should happen is compile a function like this
> 
> def popo(x=[]):
>     x.append(666)
>     print x
> 
> as if it had read
> 
> def popo(x=__default_argument_marker__):
>     if x == __default_argument_marker__:
>         x = []
>     x.append(666)
>     print x
> 
> This way, every execution of popo gets its own list. Of course, 
> __default_argument_marker__ is just a way to tell the python runtime 
> that no argument was provided, it should not be exposed to the language.
> 
> If a variable is used in the default argument, it becomes a closure 
> variable:
> 
> d = createMyListOfLists()
> n = getDefaultIndex()
> 
> def foo(x=d[n]):
>   x.append(666)
>   print x
> 
> 
> this is compiled as if it had read
> 
> d = createMyListOfLists()
> n = getDefaultIndex()
> 
> def foo(x=__default_argument_marker__):
>   if x == __default_argument_marker__:
>     x = d[n]      # d and n are closure variables
>   x.append(666)
>   print x
> 
> 
> d and n are looked up in foo's parent scope, which in this example is 
> the global scope. Of course the bytecode compiler should make sure d and 
> n don't name-clash with any variables used in the body of foo.
> 
> When you use variables as default value instead of literals, I think 
> most of the time you intend to have the function do something to the 
> same object the variable is bound to, instead of the function creating 
> it's own copy every time it's called. This behaviour still works with 
> these semantics:
> 
>>>> a = []
>>>> def foo(x=[[],a]):
>>>>   x[0].append(123)
>>>>   x[1].append(123)
>>>>   print x
>>>> foo()
> [[123], [123]]
>>>> foo()
> [[123], [123, 123]]
>>>> foo()
> [[123], [123, 123, 123]]
> 
> foo is compiled as if it had read:
> 
> def foo(x=__default_argument_marker__):
>   if x == __default_argument_marker__:
>     x = [[],a]    # a is a closure variable
>   x[0].append(123)
>   x[1].append(123)
>   print x
> 
> An other difference between this proposal and the current situation is 
> that it would be possible to change the value of a default argument 
> after the function is defined. However I don't think that would really 
> be a problem, and this behaviour is just the same as that of other 
> closure variables. Besides, this (what I perceive as a) problem with 
> closure variables is fixable on its own.
> 
> Jan
> 
> 
> On Mon, 22 Jan 2007 01:49:51 +0100, Josiah Carlson <jcarlson at uci.edu> 
> wrote:
> 
>>
>> Chris Rebert <cvrebert at gmail.com> wrote:
>>> Josiah Carlson wrote:
>>> > As provided by Calvin Spealman, the above can be fixed with:
>>> >
>>> >     def popo(x=None):
>>> >         x = x if x is not None else []
>>> >         x.append(666)
>>> >         print x
>>> >
>>> > I would also mention that forcing users to learn about mutable 
>>> arguments
>>> > and procedural programming is not a bad thing.  Learning the "gotcha"
>>> > of mutable default arguments is a very useful lesson, and to remove 
>>> that
>>> > lesson, I believe, wouldn't necessarily help new users to Python, 
>>> or new
>>> > programmers in general.
>>> >
>>> >  - Josiah
>>
>> Maybe you are taking me a bit too seriously, but hopefully this will add
>> some levity; I'm a poo-poo head.  Moving on...
>>
>>
>>> First, your 'fix' misses the point: though the proposed feature isn't
>>> necessary, and code can be written without using it, it allows mutable
>>> default argument values to be expressed more clearly and succinctly than
>>> the idiom your 'fix' uses.
>>
>> As I stated, it wasn't my fix.  And using previously existing syntax
>> that adds 1 line to a function to support a particular desired result, I
>> think, is perfectly reasonable.  Had the conditional syntax been
>> available for the last decade, those "gotchas" pages would have said
>> "mutable default arguments are tricky, always use the following, and it
>> will probably be the right thing" and moved on.
>>
>>> Second, Python isn't (inherently) about
>>> teaching new programmers about programming, and what is good for newbies
>>> isn't necessarily good for experienced programmers.
>>
>> Indeed, and what *may* be good for *certain* experienced programmers,
>> may not be good for other experienced programmers, or for the language
>> in general.  And personally, I am not sure that I could be convinced
>> that a syntax to support what can be emulated by a single line is even
>> worthy of addition.  In the case of decorators, or even the py3k support
>> for argument annotation, there are certain operations that can be made
>> *significantly* easier.  In this case, I'm not convinced that the extra
>> syntax baggage is worthwhile.
>>
>> Nevermind that it would be one more incompatible syntax that would make
>> it difficult to write for 2.5/2.6 and 3.x .
>>
>>
>>  - Josiah
>>
>> _______________________________________________
>> Python-ideas mailing list
>> Python-ideas at python.org
>> http://mail.python.org/mailman/listinfo/python-ideas
> 
> 
> 



More information about the Python-ideas mailing list