Created
August 22, 2013 04:07
-
-
Save anonymous/6303131 to your computer and use it in GitHub Desktop.
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
class A(object): | |
def hook(self, f): | |
atime = 0 | |
def intime(*args): | |
print atime | |
atime += 1 | |
return f(*args) | |
return intime | |
>>> f = A().hook(lambda b: b + 1) | |
>>> f(1) | |
Traceback (most recent call last): | |
File "<stdin>", line 1, in <module> | |
File "<stdin>", line 5, in intime | |
UnboundLocalError: local variable 'atime' referenced before assignment | |
>>> |
Thanks @sjl. it makes sense now. surprised I've never run in to this before.
@mattrobenolt came up with an alternate soltution: https://gist.github.com/mattrobenolt/6303154
here's the correct way to do it
class A(object):
def hook(self, f):
atime = []
def intime(*args):
print sum(atime)
atime.append(1)
return f(*args)
return intime
f = A().hook(lambda b: b + 1)
for i in range(10):
f(i)
and the python 3 way. bout time we start using it I think.
#!/usr/bin/env python3
class A(object):
def hook(self, f):
atime = 0
def intime(*args):
nonlocal atime
print(atime)
atime += 1
return f(*args)
return intime
f = A().hook(lambda b: b + 1)
# works as expected
for i in range(10):
f(i)
and javascript for the fuck of it. and because someone once told me js and python had the same scope behavior.
a = function(f) {
var a = 0;
return function(i) {
console.log(a);
a = a+1;
return f(i);
}
}(function(x) { return x + 1 });
for (i = 0; i < 10; i += 1) {
a(i);
}
Incidentally, when people complain about python not having proper closure support, this is (sometimes) what they mean.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
OK, so this is Python being shitty. Here's the deal.
First,
atime += 1
is essentially the same asatime = atime + 1
. Nothing crazy there, but it's important.When Python is creating the
intime
closure, it tries to determine what variables to capture. Anything that's "non-local" to the function will be captured, but variables that are set inside the function aren't.So when Python sees that you're assigning
atime
a value inside the function, it assumes that you want to declare a localatime
variable in the function. So it doesn't use the one outside.And then when you actually call this function, you try to use
atime
in theprint
before it's defined, and it explodes.This is all only a problem because Python doesn't have separate syntax for declaring and assigning variables. Like, in Scala you have:
Scala knows that the second line is trying to set an existing variable and not declare a new one. Python doesn't have that luxury.
Here's the long version if you want to read more: http://www.python.org/dev/peps/pep-3104/