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