lambda in list comprehension acting funny

Steven D'Aprano steve+comp.lang.python at pearwood.info
Sat Jul 14 19:29:02 EDT 2012


On Fri, 13 Jul 2012 12:54:02 -0600, Ian Kelly wrote:

> On Fri, Jul 13, 2012 at 11:53 AM, Hans Mulder <hansmu at xs4all.nl> wrote:
>> The function `function` refers to a variable `VERBOSE` that isn't
>> local.  In some programming langauages, the interpreter would then scan
>> the call stack at run-time, looking for a scope where that name is
>> defined.  It would find the local one in `caller`.  This is known as
>> "dynamic binding".
>>
>> Other interpreters use the `VERBOSE` that was in scope at the point in
>> the program text where `function` was defined. In this case, that would
>> be the global one.  This is called "lexical binding".
>>
>> Some programming languages allow you to indicate on a per- variable
>> basis whether you want dynamic or lexical binding.
>>
>> Python is firmly in the lexical camp.  Dynamic binding is not available
>> in Python, and never will be.

I don't remember whether it is Javascript or PHP that uses dynamic 
binding, but whichever it is, it is generally considered to be a bad 
idea, at least as the default or only behaviour.

Bash is another language with dynamic binding. Some very old versions of 
Lisp use dynamic binding, because it was the easiest to implement. Most 
modern languages use lexical (also known as static) binding, because it 
is more sensible.

Here is an illustration of the difference: suppose we have two modules, 
library.py and main.py:

# library.py
x = 23
def func(y):
    return x + y

# main.py
import library
x = 1000
print func(1)


If main.py prints 24 (and it does), then Python is using lexical scoping. 
But if it prints 1001 (which it doesn't), then it is using dynamic 
scoping. The obvious problem with dynamic binding is that the behaviour 
of a function may vary depending on where you call it.



> I don't believe that dynamic vs. lexical binding is what rusi was
> attempting to describe.  If he was, then Python and Haskell would be a
> bad comparison since both are lexical.  Rather, I think what he was
> trying to show was capture by reference vs. capture by value in the
> context of closures.  Python uses capture by reference, and so the
> upvalue is the value of that reference at the time the closure is
> called.  Haskell uses capture by value, and the upvalue is the value at
> the time of definition.

I don't think "by reference" versus "by value" are good terms to use 
here, since they risk conflating the issue with "call by reference" 
versus "call by value" semantics. I prefer "late" versus "early", as you 
suggest below.

 
> I've also seen the distinction described as "early" vs. "late" binding
> on this list, but I'm not sure how precise that is -- I believe that
> terminology more accurately describes whether method and attribute names
> are looked up at compile-time or at run-time, 

Not necessarily *compile* time, but the distinction is between when the 
function is defined (which may at compile time, or it may be at run time) 
versus when the function is called. I think that gets to the heart of the 
issue, not whether the capture copies a value or a reference. At some 
point, the capture must make use of the value: whether it does so via a 
direct C-style memory location copy, or an object pointer, or some other 
mechanism, is irrelevant. What matters is whether that value is grabbed 
at the time the closure is created, or when the closure is called.


> late binding being the
> feature that makes duck typing possible.

That is conflating two entirely distinct subjects. Python 1.5 had duck-
typing but no closures, so the one certainly does not depend on the other.

Duck-typing is more a philosophy than a language feature: the language 
must be typed, and the programmer must prefer to program to a protocol or 
a specification rather than to membership of a type.


-- 
Steven



More information about the Python-list mailing list