From: SeanMon on
I was playing around with Python functions returning functions and the
scope rules for variables, and encountered this weird behavior that I
can't figure out.

Why does f1() leave x unbound, but f2() does not?

def f1():
x = 0
def g():
x += 1
return x
return g1

def f2():
x = []
def g():
x.append(0)
return x
return g

a = f1()
b = f2()

a() #UnboundLocalError: local variable 'x' referenced before
assignment
b() #No error, [0] returned
b() #No error, [0, 0] returned
From: Benjamin Kaplan on
On Fri, Jul 23, 2010 at 11:30 AM, SeanMon <smono927(a)gmail.com> wrote:
>
> I was playing around with Python functions returning functions and the
> scope rules for variables, and encountered this weird behavior that I
> can't figure out.
>
> Why does f1() leave x unbound, but f2() does not?
>
> def f1():
>    x = 0
>    def g():
>        x += 1
>        return x
>    return g1
>
> def f2():
>    x = []
>    def g():
>        x.append(0)
>        return x
>    return g
>
> a = f1()
> b = f2()
>
> a() #UnboundLocalError: local variable 'x' referenced before
> assignment
> b() #No error, [0] returned
> b() #No error, [0, 0] returned
> --



It's not closure related at all. Same thing happens at the module level.

x = 0
def f1() :
   x += 1
#gives UnboundLocalError

x = []
def f2() :
   x.append(1)
#succeeds.

The reason for it is that if you have any assignments to the variable
in the function, Python creates a new local variable for it. x += 1 is
an assignment, not a modification. Python 2.x allows you to assign to
the global scope (using the global keyword) but support for assigning
to the outer function's scope wasn't added until Python 3 (with the
nonlocal keyword)


def f1():
   x = 0
   def g():
       nonlocal x
       x += 1
       return x
   return g1

>
> http://mail.python.org/mailman/listinfo/python-list
From: Dave Angel on
SeanMon wrote:
> I was playing around with Python functions returning functions and the
> scope rules for variables, and encountered this weird behavior that I
> can't figure out.
>
> Why does f1() leave x unbound, but f2() does not?
>
> def f1():
> x = 0
> def g():
> x += 1
> return x
> return g1
>
> def f2():
> x = []
> def g():
> x.append(0)
> return x
> return g
>
> a = f1()
> b = f2()
>
> a() #UnboundLocalError: local variable 'x' referenced before
> assignment
> b() #No error, [0] returned
> b() #No error, [0, 0] returned
>
>
Your example is more complex than needed. The symptom doesn't need a
function closure.

>>> def g():
.... x += 1
.... return x
....
>>> g()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in g
UnboundLocalError: local variable 'x' referenced before assignment
>>> def f():
.... x.append(0)
.... return x
....
>>> x = [3,5]
>>> f()
[3, 5, 0]
>>>


The difference between the functions is that in the first case, x is
reassigned; therefore it's a local. But it's not defined before that
line, so you get the ref before assign error.

In the second case, append() is an in-place operation, and doesn't
create a local variable.

DaveA

From: Terry Reedy on
On 7/23/2010 2:30 PM, SeanMon wrote:
> I was playing around with Python functions returning functions and the
> scope rules for variables, and encountered this weird behavior that I
> can't figure out.
>
> Why does f1() leave x unbound, but f2() does not?
>
> def f1():
> x = 0
> def g():
In 3.x, add
nonlocal x
> x += 1
> return x
> return g1
You meant g

def f1():
x = 0
def g():
nonlocal x
x += 1
return x
return g
f=f1()
print(f())
print(f())
print(f())
print(f())

1
2
3
4
--
Terry Jan Reedy