Python has closures, and Python does lexical scoping.

But.

In a quite retarded way, in the 2.x series. In Python 2.x, the closures aren't really closures, but some read-only thing.

Once you learn about closures, that makes click with all the niceties of functional programming that Python has, and you kind of expect that all of them work and interoperate properly. Python has lambda, functions are first-class citizens there, there is an apply equivalent, map... it makes sense. It should support closures.

It does:

def gen_printer(x):
    def printer():
        print x
    return printer

p1 = gen_printer(1)
p2 = gen_printer(2)
p1()  # 1
p2()  # 2

But it turns out that real closures are not supported. A trivial example (code that I tried to use in a real-world problem) showing a funny issue follows:

def create_counter(initial_point):
    def cnt():
        c = initial_point
        initial_point = initial_point + 1
        return c
    return cnt

counter_from_1 = create_counter(1)
print counter_from_1()

------

UnboundLocalError: local variable 'initial_point' referenced before assignment

Assignment implicitly creates a local name (in the inner function namespace), even if the name does exist in an outer scope. Also, regardless of the location of the assignment (in this case, even after a read to it). That's the cause of the previous error.

What happens is this: when Python sees a request for a variable, it looks for it in the current (local) namespace, then the enclosing namespace (say, the one of the enclosing function), and so on, until the global namespace, and finally the builtins' namespace. But only if you are reading the variable; if you try to change its value, Python assumes that such variable must be in the local namespace; that's the reason for UnboundLocalError. And there is really no proper fix for this in Python 2.x; there are ugly hacks storing the required state in object attributes, which don't really count as "supporting closures".

Fortunately, Python 3 does support closures, through the nonlocal keyword. The following Python 3 code does what you would expect:

def create_counter(initial_point):
    def cnt():
        nonlocal initial_point
        c = initial_point
        initial_point = initial_point + 1
        return c
    return cnt

counter_from_1 = create_counter(10)
print(counter_from_1())