Python has lexical scoping by default, which means that although an enclosed scope can access values in its enclosing scope, it cannot modify them (unless they're declared global with the global
keyword).
A closure binds values in the enclosing environment to names in the local environment. The local environment can then use the bound value, and even reassign that name to something else, but it can't modify the binding in the enclosing environment.
In your case you are trying to treat counter
as a local variable rather than a bound value. Note that this code, which binds the value of x
assigned in the enclosing environment, works fine:
>>> x = 1
>>> def f():
>>> return x
>>> f()
1