default value in __init__

Steven D'Aprano steve at REMOVE-THIS-cybersource.com.au
Thu Oct 16 20:54:17 EDT 2008


On Thu, 16 Oct 2008 12:18:49 -0700, Aaron \"Castironpi\" Brady wrote:

[snip]

>> If Python re-evaluated the default value i=i at runtime, the above
>> would break.
> 
> Not with a mere extra lambda.

Not so. It has nothing to do with lambda, lambda just happens to be a 
convenient example. Here's the code I demonstrated:

>>> for i in xrange(len(callbacks)):
...     callbacks[i] = lambda s, i=i: '%d %s' % (i, s)
...
>>> for cb in callbacks:
...     print cb('string')
...
0 string
1 string
2 string
3 string


At the end of the first loop, i == 3. If the default value i=i was re-
evaluated each time the function was called, then i would get the value 3 
each time, which is the same behaviour you get from the version with this:

callbacks[i] = lambda s: '%d %s' % (i, s)

Worse, because you're now relying on i as a global, it's subject to 
strange and mysterious bugs if you later change i and then call the 
callback.



> The fact that a syntax is an opportunity
> to have a behavior does not imply that it should have one.  The fact
> that newbies ask about these semantics doesn't imply that they'd ask
> about another one just as much.  The fact that these semantics have
> these two uses, doesn't imply that the others don't have more. 

Nowhere did I say that the one logically implies the other. I was asked 
for examples of how the current behaviour is useful, not to prove that 
the current behaviour logically follows from first principles. If you 
want to use a programming language where function default values are re-
evaluated at runtime, you know where to find them.

By the way, for the record I myself has found that behaviour useful on 
occasion. But that's easy to do with current Python:


def spam(x, y=None):
    if y is None:
        # re-evaluate the default value at runtime
        y = get_some_other_value()
    return x + y

So if you want that behaviour, you can get it. But if Python's semantics 
changed, then how would you implement today's semantics where the default 
is evaluated once only? I don't think you can. So Python's current 
semantics allows the behaviour you want, but in a slightly inconvenient 
form; but the re-evaluate-at-runtime semantics would prevent the 
behaviour I want completely.



> Immutable defaults behave identically in both.

Not quite. To have immutable defaults behave identically, you would need 
to remove at least one more feature of Python: the ability to set a 
default value to an arbitrary expression, not just a literal.

Why do you need to do this? This toy example demonstrates the problem if 
you don't:

yy = 3  # immutable value bound to the name yy
def spam(x, y=yy-1):
    return x + y


will have the *expression* yy-1 re-evaluated when they call the function. 
That means that even though 2 is immutable, you can no longer rely on the 
default value being 2, or even existing at all. (What if I del yy at some 
point, then call the function?)

So now to get the behaviour you desire, you not only have to change the 
way Python functions are implemented (and that will have a real and 
significant performance cost), but you also have to change the parser to 
only allow literals as default values.

Note that there is absolutely nothing wrong with using an expression when 
setting default values. But you have to prohibit it, or else introduce 
unexpected behaviour which will trip up not just noobs but everybody. And 
then you'll have noobs writing in weekly asking why they can't write 
"def foo(x, y=10**6)" instead of y=10000000.



-- 
Steven



More information about the Python-list mailing list