[BangPypers] Does Python have lexical scoping?

Anand Chitipothu anandology at gmail.com
Mon Nov 10 08:04:22 CET 2014


On Mon, Nov 10, 2014 at 12:17 PM, Anand Chitipothu <anandology at gmail.com>
wrote:

> On Sun, Nov 9, 2014 at 10:38 AM, Noufal Ibrahim KV <noufal at nibrahim.net.in
> > wrote:
>
>>
>> Okay, I've been struggling through the proglang course on coursera and
>> this thing came up
>>
>>    val x = 2;
>>    fun f y = x + y;
>>
>> The second line creates a function that adds `x` to it's argument. Since
>> ML is statically scoped, this is really a function that adds 2 to its
>> argument.  Even if I later create a new binding for x later like so
>>
>>    val x = 10;
>>    f (3);
>>
>> I will still get back 5 (i.e. 2 + 3) instead of 13 (10 + 3). This makes
>> sense to me as an example of lexical scoping. The bindings are at the
>> time of definition rather than invocation.
>>
>> With python, it's different. The claim is that it has lexical scoping
>> but.
>>
>>      x = 2
>>      def f(y): return x + y
>>
>>      x = 10
>>      f(3)
>>
>> The answer is, distressingly, 13. The explanation was that although
>> Python has lexical scoping, that closure "close over variables rather
>> than values". Meaning that the variables (and not their values) at
>> definition time are stored in the closure. This is how elisp does it
>> which claims to be, by default, dynamically scoped.
>>
>> (setq m 5)
>> (defun test (x)
>>   (+ x m))
>>
>> (test 3) ; -> 8
>> (setq m 15)
>> (test 3) ; -> 18
>>
>>
>> So, my question is, how different is this from dynamic scoping (like in
>> elisp) where the values are actually picked up from the execution
>> (rather than definition) environment. This business of "closes over
>> variables rather than values" sounds like a cop out.
>>
>> Comments?
>>
>
> There are cases where both lexical scope and dynamic scope produce same
> results. The example that you gave falls into that category.
>

Sorry, forgot to add the output.


>
> Try the following example:
>
> (setq x 5)
> (defun getx () x)
> (getx)
>
> (defun f (x) (getx))
>
> (f 10)
>

prints 10, the x from function f, not global x.


> (setq x 4)
> (f 10)
>

prints 10 again. changing the global x don't have any affect.

Python or scheme (lexical scoping) would produce 4 in this case.


>
> The function getx takes the values of x that is closest to in the stack,
> not the one that is lexically closest.
>
> Another example to demonstrate that.
>
> (defun g (x) (h x))
> (defun h (y) (getx))
> (g 3)
>

prints 3. Picks x from 2 stack frames below.


> With lexical scoping a can be resolved at the time of declaring the
> function it self (as in name x in getx is alias to x defined in the
> top-level), where as with dynamic scoping it can only be determined at the
> run time. Because of this lexical scoping is usually faster.
>

Anand


More information about the BangPypers mailing list