of Brython, JavaScript and closures

Those of you tracking the Cuba working group will have seen that Brython is to be a topic [0]. That's "Python is the browser", which I'm eager to try (haven't yet). Brython is a segue to JavaScript, which I'm relearning from scratch ('The Good Parts' etc.). Over on mathfuture I'm continuing to discuss what I call the Lambda Calc track [1] where we introduce programming as a math-relevant way of thinking / activity / skill. A long-running theme here on edu-sig already. In comparing JavaScript and Python, I'm learning quite a bit. Example: JavaScript allows closures wherein a function in a function retains its memory of the variables (names) in the surrounding scope. The following example of a closure is from: Speaking JavaScript by Axel Rauschmayer Publisher: O'Reilly Media, Inc. Release Date: March 2014 ISBN: 9781449365035 in the intro section on Closures. function createIncrementor(start) {return function () { start++; return start; }} ... which gives the following behavior:
var inc = createIncrementor(5); inc() 6 inc() 7 inc() 8
Lets try that same thing in Python. def createIncrementor(x): def increm(): x += 1 return x return increm At first it seems not to work (not just seems, it doesn't):
from closure import createIncrementor inc = createIncrementor(5) inc() Traceback (most recent call last): File "<pyshell#30>", line 1, in <module> inc() File "/Users/kurner/Documents/classroom_labs/closure.py", line 4, in increm x += 1 UnboundLocalError: local variable 'x' referenced before assignment
That's where the keyword nonlocal comes in. The increm function was originally looking in the global namespace for x whereas we need it to look "close to home" (at the originally surrounding scope): def createIncrementor(x): def increm(): nonlocal x x += 1 return x return increm
from closure import createIncrementor inc = createIncrementor(5) inc() 6 inc() 7 inc() 8
Voila, a closure. Closures turn out to be really important in JavaScript thanks to its weak modularization model i.e. namespaces are difficult to segregate minus such patterns. Closures get used to mitigate name collisions. Python is less dependent on that pattern, given it has other ways to confine names to local scopes. Kirby [0] http://tinyurl.com/hpgrebf (Brython sprint / Cuba) [1] http://tinyurl.com/jbpef72 (mathfuture posting)

On Fri, Apr 15, 2016 at 10:40 AM, kirby urner <kirby.urner@gmail.com> wrote:
The increm function was originally looking in the global namespace for x...
That's not quite right either as this is simply wrong as a complete module: x = 0 def createIncrementor(x): def increm(): x = x + 1 return x return increm The "referenced before assignment" error will occur regardless of the presence of a global x. The choices to make increm work would be: x = 100 def createIncrementor(x): def increm(): global x x = x + 1 return x return increm (a module is a kind of closure / enclosure -- coming in ES6 right?) or: def createIncrementor(x): def increm(): nonlocal x x = x + 1 return x return increm for an even more enclosed closure. One may even remove x = from the module's global namespace and inject it retroactively:
from closure import createIncrementor inc = createIncrementor(5) inc() Traceback (most recent call last): File "<pyshell#80>", line 1, in <module> inc() File "/Users/kurner/Documents/classroom_labs/closure.py", line 4, in increm x = x + 1 NameError: global name 'x' is not defined x = 100 # this won't work either as '__main__' is not where it looks inc() Traceback (most recent call last): File "<pyshell#82>", line 1, in <module> inc() File "/Users/kurner/Documents/classroom_labs/closure.py", line 4, in increm x = x + 1 NameError: global name 'x' is not defined closure.x = 100 # this would work if I added closure to the namespace Traceback (most recent call last): File "<pyshell#83>", line 1, in <module> closure.x = 100 NameError: name 'closure' is not defined import closure # which I do here closure.x = 100 inc() # and now the earlier imported function works with no problems 101
Kirby
participants (1)
-
kirby urner