Function closure inconsistency

Discussion in 'Python' started by SeanMon, Jul 23, 2010.

  1. SeanMon

    SeanMon Guest

    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
     
    SeanMon, Jul 23, 2010
    #1
    1. Advertising

  2. On Fri, Jul 23, 2010 at 11:30 AM, 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
    > --




    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
     
    Benjamin Kaplan, Jul 23, 2010
    #2
    1. Advertising

  3. SeanMon

    Dave Angel Guest

    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
     
    Dave Angel, Jul 23, 2010
    #3
  4. SeanMon

    Terry Reedy Guest

    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
     
    Terry Reedy, Jul 23, 2010
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Victor Ng
    Replies:
    1
    Views:
    354
    Bengt Richter
    Mar 11, 2005
  2. Replies:
    2
    Views:
    207
    Steven D'Aprano
    Mar 25, 2007
  3. Replies:
    9
    Views:
    282
    Dennis Lee Bieber
    Apr 17, 2007
  4. Julian Mehnle
    Replies:
    0
    Views:
    261
    Julian Mehnle
    Jul 17, 2003
  5. LAN MIND

    What is function closure?

    LAN MIND, Jan 27, 2008, in forum: Javascript
    Replies:
    5
    Views:
    95
    Thomas 'PointedEars' Lahn
    Jan 27, 2008
Loading...

Share This Page