Last active
August 26, 2016 23:58
-
-
Save hunan-rostomyan/7ed95562c0e961ead8dc to your computer and use it in GitHub Desktop.
Closures: Javascript vs Python
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Calling Counter with (a possibly `undefined`) `init` | |
returns a function that closes over `counter` and | |
increments it every time it's called. | |
*/ | |
function Counter(init) { | |
var counter = init || 1; | |
return function() { | |
var current = counter; | |
counter += 1; | |
return current; | |
}; | |
} | |
var c = Counter(); | |
c() //=> 1 | |
c() //=> 2 | |
c() //=> 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Instantiating Counter with (a possibly `None`) `init` | |
we obtain a callable object (effectively, a function) with | |
instance variable `counter` initialized to `init` or 0 that | |
gets incremented every time the 'function' it called. | |
""" | |
class Counter: | |
def __init__(self, init=0): | |
self.counter = init | |
def __call__(self): | |
self.counter += 1 | |
return self.counter | |
c = Counter() | |
c() #=> 1 | |
c() #=> 2 | |
c() #=> 3 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
I was playing around with a simple decorator for tracking | |
function calls. What follows are two failed attempts and | |
an interesting workaround suggested by Eric D. Wang. | |
""" | |
""" | |
Failed attempt #1 | |
""" | |
def track_calls(fn): | |
counter = 0 | |
def _fn(*args, **kwargs): | |
result = fn(*args, **kwargs) | |
counter += 1 | |
print 'That was call #{}'.format(counter) | |
return result | |
return _fn | |
@track_calls | |
def add(a, b): | |
return a + b | |
add(2, 3) # UnboundLocalError: local variable 'counter' | |
# referenced before assignment | |
""" | |
Failed attempt #2 | |
This seemed to work, but only because I had declared `counter` | |
globally. Thanks to Eric D. Wang for pointing this out. | |
""" | |
def track_calls(fn): | |
counter = 0 | |
def _fn(*args, **kwargs): | |
result = fn(*args, **kwargs) | |
global counter | |
counter += 1 | |
print 'That was call #{}'.format(counter) | |
return result | |
return _fn | |
@track_calls | |
def add(a, b): | |
return a + b | |
add(2, 3) # NameError: global name 'counter' is not defined | |
""" | |
Eric's workaround: | |
"You can get around it though by keeping a | |
counter in a mutable object (kinda hacky)" | |
""" | |
def track_calls(fn): | |
counter = [0] | |
def _fn(*args, **kwargs): | |
result = fn(*args, **kwargs) | |
counter[0] += 1 | |
print 'That was call #{}'.format(counter[0]) | |
return result | |
return _fn | |
@track_calls | |
def add(a, b): | |
return a + b | |
add(2, 3) #=> 5 (side effect: That was call #1) | |
add(2, 3) #=> 5 (side effect: That was call #2) | |
add(2, 3) #=> 5 (side effect: That was call #2) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
""" | |
Another option is to use the `nonlocal` keyword available | |
since version 3. Here is the basic idea. | |
""" | |
def counter(): | |
count = 0 | |
def inner(): | |
nonlocal count | |
count += 1 | |
return count | |
return inner | |
c = counter() | |
c() #=> 1 | |
c() #=> 2 | |
c() #=> 3 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment