On Fri, 23 Dec 2011 17:03:11 +0000, Neil Cerutti wrote:

>> The disadvantage of late binding is that since the expression is live,
>> it needs to be calculated each time, even if it turns out to be the
>> same result. But there's no guarantee that it will return the same
>> result each time:
> 
> That's its main *advantage*.
Ah yes, sorry, poor wording on my part. Whether calculating the default 
value *once* or *each time* is an advantage or disadvantage depends on 
what you're trying to do. Either way, it could be just what you want, or 
an annoying source of bugs.


>> consider a default value like x=time.time(), which will return a
>> different value each time it is called; or one like x=a+b, which will
>> vary if either a or b are changed. Or will fail altogether if either a
>> or b are deleted. This will surprise some people some of the time and
>> lead to demands that Python "fix" the "obviously buggy" default
>> argument gotcha.
> 
> It's hard to see anyone being confused by the resultant exception.

That's because you're coming at it from the perspective of somebody who 
knows what to expect, in the middle of a discussion about the semantics 
of late binding. Now imagine you're a newbie who has never thought about 
the details of when the default value is created, but has a function like 
"def foo(x, y=a+b)". He calls foo(x) seven times and it works, and on the 
eighth time it blows up, perhaps with a NameError. It's surprising 
behaviour, and newbies aren't good at diagnosing surprising bugs.

Or worse, it doesn't blow up at all, but gives some invalid value that 
causes your calculations to be completely wrong. Exceptions are not the 
worst bug to have -- they are the best.


> It's
> much harder to figure out what's going wrong with an early-bound
> mutable.

Only for those who don't understand, or aren't thinking about, Python's 
object model. The behaviour of early-bound mutables is obvious and clear 
once you think about it, but it does require you to think about what's 
going on under the hood, so to speak.

[...]
>> To fake early binding when the language provides late binding, you
>> still use a sentinel value, but the initialization code creating the
>> default value is outside the body of the function, usually in a global
>> variable:
[...]
 
> I'd use a function attribute.
> 
> def func(x, y=None):
>   if y is None:
>     y = func.default_y
>   ...
> func.default_y = []
> 
> That's awkward only if you believe function attributes are awkward.

I do. All you've done is move the default from *before* the function is 
defined to *after* the function is defined, instead of keeping it in the 
function definition. It's still separate, and if the function is renamed 
your code stops working. In other words, it violates encapsulation of the 
function.

That's not to say that you shouldn't do this. It's a perfectly reasonable 
technique, and I've used it myself, but it's not as elegant as the 
current Python default argument behaviour.


[...]
> The greater efficiency was probably what decided this question for
> Python, right? Since late-binding is so easy to fake, is hardly ever
> what you want, and would make all code slower, why do it?

Excellent point.


-- 
Steven
-- 
http://mail.python.org/mailman/listinfo/python-list

Reply via email to