Indeed. Python is a prime example of a language with closures that doesn't do variable-name binding, due to the way variables and specifically assignments work in general with Python.
>>> i = 10
>>> def x():
... print i
...
>>> x()
10
>>> i = 11
>>> x()
11
The value is not closed over in any language I can think of off the top of my head. It's a reference to a variable in lexical scope.What python does slightly differently is writing to variables in outer scopes. But it still closes over references.
>>> i = 0
>>> def inc():
... i += 1
...
>>> print i
0
>>> inc()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in inc
UnboundLocalError: local variable 'i' referenced before assignment
So variables are name-bound in the sense that you can read from their original name and reference but you can't assign in normal ways. (Python has closures, which I said, just not typical closures that other languages might have.) Leading to the pattern of wrapping an array or dict or class around the thing you're interested in. >>> i_wrapped = [0]
>>> def inc():
... i_wrapped[0] += 1
...
>>> print i_wrapped[0]
0
>>> inc()
>>> print i_wrapped[0]
1
One could argue that one shouldn't really have such mutable state inside a closure of the enclosed items, which I do, but a person expecting to (set!) or the like is going to be surprised.Edit: I guess it should be said that Python 3 has the 'nonlocal' keyword, and Python 2 has the 'global' keyword for global cases, which allows for expected behavior. So the functionality is still there, but still needs an extra statement.
>>> i = 0
>>> def out():
... i = 0
... def inc():
... nonlocal i
... i += 1
... print(i)
... inc()
... print(i)
...
>>> print(i)
0
>>> out()
0
1
>>> print(i)
0