Function closure inconsistency

S

SeanMon

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
 
B

Benjamin Kaplan

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
 
D

Dave Angel

SeanMon said:
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.
.... x += 1
.... return x
....Traceback (most recent call last):
File "<stdin>", line 1, in <module>
.... 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
 
T

Terry Reedy

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,996
Messages
2,570,237
Members
46,825
Latest member
VernonQuy6

Latest Threads

Top