Scope, type and UnboundLocalError

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Paddy

    Scope, type and UnboundLocalError

    Hi,
    I am trying to work out why I get UnboundLocalErr or when accessing an
    int from a function where the int is at the global scope, without
    explicitly declaring it as global but not when accessing a list in
    similar circumstances.

    The documentation: http://docs.python.org/ref/naming.html does not give
    me enough info to determine why the difference exists as it does not
    seem to mention types at all..

    The code:

    ===== scope_and_type. py =======
    m = 0
    n = [0]

    def int_access0():
    m = m + 1
    return m
    def int_access1():
    m += 1
    return m
    def list_access0():
    n[0] = n[0] + 1
    return n
    def list_access1():
    n[0] += 1
    return n

    try:
    print "\nint_access0: ", int_access0()
    except UnboundLocalErr or, inst:
    print " ERROR:\n", inst
    try:
    print "\nint_access1: ", int_access1()
    except UnboundLocalErr or, inst:
    print " ERROR:\n", inst
    try:
    print "\nlist_access0 :", list_access0()
    except UnboundLocalErr or, inst:
    print " ERROR:\n", inst
    try:
    print "\nlist_access1 :", list_access1()
    except UnboundLocalErr or, inst:
    print " ERROR:\n", inst


    print "\n (m,n) = ", (m,n)


    p = (0,)
    def tuple_access():
    return p[0]
    try:
    print "\ntuple_acces: ", tuple_access()
    except UnboundLocalErr or, inst:
    print " ERROR:\n", inst
    print "\n p = ", p

    ===== END scope_and_type. py =======

    The output:
    >>>
    int_access0: ERROR:
    local variable 'm' referenced before assignment

    int_access1: ERROR:
    local variable 'm' referenced before assignment

    list_access0: [1]

    list_access1: [2]

    (m,n) = (0, [2])

    tuple_acces: 0

    p = (0,)
    >>>
  • Frank Millman

    #2
    Re: Scope, type and UnboundLocalErr or


    Paddy wrote:
    Hi,
    I am trying to work out why I get UnboundLocalErr or when accessing an
    int from a function where the int is at the global scope, without
    explicitly declaring it as global but not when accessing a list in
    similar circumstances.
    >
    There has just been a long thread about this. I think I understand it
    now. Here is my explanation.

    Ignoring nested scopes for this exercise, references to objects (i.e.
    variable names) can exist in the local namespace or the global
    namespace. Python looks in the local namespace first, and if not found
    looks in the global namespace.

    Any name assigned to within the function is automatically deemed to
    exist in the local namespace, unless overridden with the global
    statement.

    With the statement 'm = m + 1', as m is assigned to on the LHS, it is
    deemed to be local, but as m does not yet have a value on the RHS, you
    get Unbound Local Error.

    With the statement 'n[0] = n[0] + 1', n is not being assigned to, as it
    is mutable. Therefore Python looks in the global namespace, finds n
    there, and uses it successfully.

    My 2c

    Frank Millman

    Comment

    • Paddy

      #3
      Re: Scope, type and UnboundLocalErr or


      Frank Millman wrote:
      Paddy wrote:
      Hi,
      I am trying to work out why I get UnboundLocalErr or when accessing an
      int from a function where the int is at the global scope, without
      explicitly declaring it as global but not when accessing a list in
      similar circumstances.
      >
      With the statement 'm = m + 1', as m is assigned to on the LHS, it is
      deemed to be local, but as m does not yet have a value on the RHS, you
      get Unbound Local Error.
      >
      With the statement 'n[0] = n[0] + 1', n is not being assigned to, as it
      is mutable. Therefore Python looks in the global namespace, finds n
      there, and uses it successfully.
      >
      My 2c
      >
      Frank Millman
      So, to paraphrase to test my understanding:

      in the statement: ' n[0] = n[0] + 1' it is the object referenced by the
      name n that is being assigned to rather than n itself, so n is not
      'tagged' as a local variable by the LHS of the assignment.

      Thanks Frank. all is is now clear :-)

      Comment

      • Bruno Desthuilliers

        #4
        Re: Scope, type and UnboundLocalErr or

        Frank Millman a écrit :
        Paddy wrote:
        >
        >>Hi,
        >>I am trying to work out why I get UnboundLocalErr or when accessing an
        >>int from a function where the int is at the global scope, without
        >>explicitly declaring it as global but not when accessing a list in
        >>similar circumstances.
        >>
        >
        >
        There has just been a long thread about this. I think I understand it
        now. Here is my explanation.
        >
        Ignoring nested scopes for this exercise, references to objects (i.e.
        variable names) can exist in the local namespace or the global
        namespace. Python looks in the local namespace first, and if not found
        looks in the global namespace.
        >
        Any name assigned to within the function is automatically deemed to
        exist in the local namespace, unless overridden with the global
        statement.
        And this even of the local bindings sequentially comes after another
        access to the name, ie:

        g = 0

        def fun():
        x = g # UnboundLocalErr or here
        g += 1
        return x
        With the statement 'm = m + 1', as m is assigned to on the LHS, it is
        deemed to be local, but as m does not yet have a value on the RHS, you
        get Unbound Local Error.
        Right
        With the statement 'n[0] = n[0] + 1', n is not being assigned to,
        Right
        as it
        is mutable.
        n is effectively mutable, but this is totally irrelevant. In your
        snippet, n is not 'assigned to', it's "mutated" (ie a state-modifying
        method is called). The snippet:

        n[0] = n[0] + 1

        is syntactic sugar for

        n.__setitem__(0 , n.__getitem__(0 ) + 1)

        IOW, it's just method calls on n.

        Comment

        • Bruno Desthuilliers

          #5
          Re: Scope, type and UnboundLocalErr or

          Paddy a écrit :
          Frank Millman wrote:
          >
          >>Paddy wrote:
          >>
          >>>Hi,
          >>>I am trying to work out why I get UnboundLocalErr or when accessing an
          >>>int from a function where the int is at the global scope, without
          >>>explicitly declaring it as global but not when accessing a list in
          >>>similar circumstances.
          >>>
          >>
          >>With the statement 'm = m + 1', as m is assigned to on the LHS, it is
          >>deemed to be local, but as m does not yet have a value on the RHS, you
          >>get Unbound Local Error.
          >>
          >>With the statement 'n[0] = n[0] + 1', n is not being assigned to, as it
          >>is mutable. Therefore Python looks in the global namespace, finds n
          >>there, and uses it successfully.
          >>
          >>My 2c
          >>
          >>Frank Millman
          >
          So, to paraphrase to test my understanding:
          >
          in the statement: ' n[0] = n[0] + 1' it is the object referenced by the
          name n that is being assigned to rather than n itself, so n is not
          'tagged' as a local variable by the LHS of the assignment.
          Nope. You got it plain wrong - cf my answer to Frank in this thread.
          >
          Thanks Frank. all is is now clear :-)
          It is obviously not.

          Comment

          • Paddy

            #6
            Re: Scope, type and UnboundLocalErr or

            Bruno Desthuilliers wrote:
            Frank Millman a écrit :
            Paddy wrote:
            >Hi,
            >I am trying to work out why I get UnboundLocalErr or when accessing an
            >int from a function where the int is at the global scope, without
            >explicitly declaring it as global but not when accessing a list in
            >similar circumstances.
            >

            There has just been a long thread about this. I think I understand it
            now. Here is my explanation.

            Ignoring nested scopes for this exercise, references to objects (i.e.
            variable names) can exist in the local namespace or the global
            namespace. Python looks in the local namespace first, and if not found
            looks in the global namespace.

            Any name assigned to within the function is automatically deemed to
            exist in the local namespace, unless overridden with the global
            statement.
            >
            And this even of the local bindings sequentially comes after another
            access to the name, ie:
            >
            g = 0
            >
            def fun():
            x = g # UnboundLocalErr or here
            g += 1
            return x
            >
            With the statement 'm = m + 1', as m is assigned to on the LHS, it is
            deemed to be local, but as m does not yet have a value on the RHS, you
            get Unbound Local Error.
            >
            Right
            >
            With the statement 'n[0] = n[0] + 1', n is not being assigned to,
            Right
            >
            as it
            is mutable.
            >
            n is effectively mutable, but this is totally irrelevant. In your
            snippet, n is not 'assigned to', it's "mutated" (ie a state-modifying
            method is called). The snippet:
            >
            n[0] = n[0] + 1
            >
            is syntactic sugar for
            >
            n.__setitem__(0 , n.__getitem__(0 ) + 1)
            >
            IOW, it's just method calls on n.
            So,
            An assignment statement may assign an object to a name, in which case
            the name is 'tagged' as being local,
            An assignment statement may mutate a mutable object already bound to a
            name, in which case the assignment will not 'tag' the name as being
            local.

            I guess Bruno, you mean irrelevant as in 'although only mutable objects
            can have their state modified; if n has a mutable value but the
            assignment statement changed the object referred to by n, then the name
            would be tagged as local'?

            - Peace, Paddy.

            Comment

            • Paddy

              #7
              Re: Scope, type and UnboundLocalErr or


              Paddy wrote:
              >
              So,
              An assignment statement may assign an object to a name, in which case
              the name is 'tagged' as being local,
              An assignment statement may mutate a mutable object already bound to a
              name, in which case the assignment will not 'tag' the name as being
              local.
              >
              I guess Bruno, you mean irrelevant as in 'although only mutable objects
              can have their state modified; if n has a mutable value but the
              assignment statement changed the object referred to by n, then the name
              would be tagged as local'?
              >
              - Peace, Paddy.
              No, that last paragraph still does not convey what I meant.


              .... irrelevant as in 'although only mutable objects can have their
              state modified; if n has a mutable value but the assignment statement
              changed n to refer to another object, then the name would be tagged as
              local'?

              Oh bosh, can anyone come at it from a different tack?

              Ta.

              Comment

              • Fredrik Lundh

                #8
                Re: Scope, type and UnboundLocalErr or

                Paddy wrote:
                ... irrelevant as in 'although only mutable objects can have their
                state modified; if n has a mutable value but the assignment statement
                changed n to refer to another object, then the name would be tagged as
                local'?
                >
                Oh bosh, can anyone come at it from a different tack?
                look for "Assignment of an object to a single target is recursively
                defined as follows" on this page (or at the corresponding page in the
                language reference):



                </F>

                Comment

                • Bruno Desthuilliers

                  #9
                  Re: Scope, type and UnboundLocalErr or

                  Paddy a écrit :
                  Bruno Desthuilliers wrote:
                  >
                  >>Frank Millman a écrit :
                  >>
                  >>>Paddy wrote:
                  >>>
                  >>>
                  >>>>Hi,
                  >>>>I am trying to work out why I get UnboundLocalErr or when accessing an
                  >>>>int from a function where the int is at the global scope, without
                  >>>>explicitl y declaring it as global but not when accessing a list in
                  >>>>similar circumstances.
                  >>>>
                  >>>
                  >>>
                  >>>There has just been a long thread about this. I think I understand it
                  >>>now. Here is my explanation.
                  >>>
                  >>>Ignoring nested scopes for this exercise, references to objects (i.e.
                  >>>variable names) can exist in the local namespace or the global
                  >>>namespace. Python looks in the local namespace first, and if not found
                  >>>looks in the global namespace.
                  >>>
                  >>>Any name assigned to within the function is automatically deemed to
                  >>>exist in the local namespace, unless overridden with the global
                  >>>statement.
                  >>
                  >>And this even of the local bindings sequentially comes after another
                  >>access to the name, ie:
                  >>
                  >>g = 0
                  >>
                  >>def fun():
                  > x = g # UnboundLocalErr or here
                  > g += 1
                  > return x
                  >>
                  >>
                  >>>With the statement 'm = m + 1', as m is assigned to on the LHS, it is
                  >>>deemed to be local, but as m does not yet have a value on the RHS, you
                  >>>get Unbound Local Error.
                  >>
                  >>Right
                  >>
                  >>
                  >>>With the statement 'n[0] = n[0] + 1', n is not being assigned to,
                  >>
                  >>Right
                  >>
                  >>
                  >>as it
                  >>>is mutable.
                  >>
                  >>n is effectively mutable, but this is totally irrelevant. In your
                  >>snippet, n is not 'assigned to', it's "mutated" (ie a state-modifying
                  >>method is called). The snippet:
                  >>
                  >>n[0] = n[0] + 1
                  >>
                  >>is syntactic sugar for
                  >>
                  >>n.__setitem__ (0, n.__getitem__(0 ) + 1)
                  >>
                  >>IOW, it's just method calls on n.
                  >
                  >
                  So,
                  An assignment statement may assign an object to a name,
                  An assignment statement binds an object to a name.
                  in which case
                  the name is 'tagged' as being local,
                  Unless that names has been declared as global or lives in another
                  namespace (ie is an element of a mutable collection or an attribute of
                  another object).
                  An assignment statement may mutate a mutable object already bound to a
                  name, in which case the assignment will not 'tag' the name as being
                  local.
                  consider this code:

                  class Foo(object):
                  def __init__(self, baaz):
                  self.baaz = baaz

                  def bar(foo, bak):
                  foo.baaz = bak

                  Which name is getting rebound here ? foo, or foo.baaz ?
                  I guess Bruno, you mean irrelevant as in 'although only mutable objects
                  can have their state modified; if n has a mutable value but the
                  assignment statement changed the object referred to by n, then the name
                  would be tagged as local'?
                  Unless the name has been declared as global, yes.

                  Comment

                  • Paddy

                    #10
                    Re: Scope, type and UnboundLocalErr or


                    Bruno Desthuilliers wrote:
                    Paddy a écrit :
                    Bruno Desthuilliers wrote:
                    >Frank Millman a écrit :
                    >
                    >>Paddy wrote:
                    >>
                    >>
                    >>>Hi,
                    >>>I am trying to work out why I get UnboundLocalErr or when accessing an
                    >>>int from a function where the int is at the global scope, without
                    >>>explicitly declaring it as global but not when accessing a list in
                    >>>similar circumstances.
                    >>>
                    >>
                    >>
                    >>There has just been a long thread about this. I think I understand it
                    >>now. Here is my explanation.
                    >>
                    >>Ignoring nested scopes for this exercise, references to objects (i.e.
                    >>variable names) can exist in the local namespace or the global
                    >>namespace. Python looks in the local namespace first, and if not found
                    >>looks in the global namespace.
                    >>
                    >>Any name assigned to within the function is automatically deemed to
                    >>exist in the local namespace, unless overridden with the global
                    >>statement.
                    >
                    >And this even of the local bindings sequentially comes after another
                    >access to the name, ie:
                    >
                    >g = 0
                    >
                    >def fun():
                    x = g # UnboundLocalErr or here
                    g += 1
                    return x
                    >
                    >
                    >>With the statement 'm = m + 1', as m is assigned to on the LHS, it is
                    >>deemed to be local, but as m does not yet have a value on the RHS, you
                    >>get Unbound Local Error.
                    >
                    >Right
                    >
                    >
                    >>With the statement 'n[0] = n[0] + 1', n is not being assigned to,
                    >
                    >Right
                    >
                    >
                    >as it
                    >>is mutable.
                    >
                    >n is effectively mutable, but this is totally irrelevant. In your
                    >snippet, n is not 'assigned to', it's "mutated" (ie a state-modifying
                    >method is called). The snippet:
                    >
                    >n[0] = n[0] + 1
                    >
                    >is syntactic sugar for
                    >
                    >n.__setitem__( 0, n.__getitem__(0 ) + 1)
                    >
                    >IOW, it's just method calls on n.

                    So,
                    An assignment statement may assign an object to a name,
                    >
                    An assignment statement binds an object to a name.
                    >
                    in which case
                    the name is 'tagged' as being local,
                    >
                    Unless that names has been declared as global or lives in another
                    namespace (ie is an element of a mutable collection or an attribute of
                    another object).
                    >
                    An assignment statement may mutate a mutable object already bound to a
                    name, in which case the assignment will not 'tag' the name as being
                    local.
                    >
                    consider this code:
                    >
                    class Foo(object):
                    def __init__(self, baaz):
                    self.baaz = baaz
                    >
                    def bar(foo, bak):
                    foo.baaz = bak
                    >
                    Which name is getting rebound here ? foo, or foo.baaz ?
                    >
                    I guess Bruno, you mean irrelevant as in 'although only mutable objects
                    can have their state modified; if n has a mutable value but the
                    assignment statement changed the object referred to by n, then the name
                    would be tagged as local'?
                    >
                    Unless the name has been declared as global, yes.
                    Thanks Bruno, that clears it up for me (I had purposefully left out the
                    global statement from my example, but should have included it in the
                    explanation).

                    Comment

                    • Paddy

                      #11
                      Re: Scope, type and UnboundLocalErr or

                      Dennis Lee Bieber wrote:
                      On 9 Jul 2006 11:30:06 -0700, "Paddy" <paddy3118@nets cape.netdeclaim ed
                      the following in comp.lang.pytho n:
                      >
                      So,
                      An assignment statement may assign an object to a name, in which case
                      the name is 'tagged' as being local,
                      >
                      Reverse... Python does not "assign" objects to names... It "assigns"
                      names to objects. One object can have multiple names.
                      >
                      In the absence of a "global <name>" statement, any unqualified
                      <namefound on the left side of an "=" is a local name (the name -- not
                      the object it is bound to -- is held as part of the current stack frame
                      and is removed on return from the function; the object may or may not be
                      garbage collected depending upon any other names bound to it).
                      >
                      A qualified name is one with some sort of component specifier:
                      <name>.<compone nt>, <name>[<component>]. These access items that are
                      inside the object that <nameis bound on. The component access
                      basically is a function/method call telling the object itself to change
                      the <componentbindi ng, not the top-level <namebinding.
                      >
                      Hi Dennis, in the last paragraph you do not state specifically where
                      the name for the component name is looked for. Do you mean that for
                      component name accesses,where the 'base' is not declared gobal, the
                      'base' name nevertheless is always looked for in the global scope?

                      (Please excuse my pedantry).

                      Comment

                      • Bruno Desthuilliers

                        #12
                        Re: Scope, type and UnboundLocalErr or

                        Paddy a écrit :
                        Dennis Lee Bieber wrote:
                        >
                        >>On 9 Jul 2006 11:30:06 -0700, "Paddy" <paddy3118@nets cape.netdeclaim ed
                        >>the following in comp.lang.pytho n:
                        >>
                        >>
                        >>>So,
                        >>>An assignment statement may assign an object to a name, in which case
                        >>>the name is 'tagged' as being local,
                        >>
                        >> Reverse... Python does not "assign" objects to names... It "assigns"
                        >>names to objects. One object can have multiple names.
                        >>
                        >> In the absence of a "global <name>" statement, any unqualified
                        >><namefound on the left side of an "=" is a local name (the name -- not
                        >>the object it is bound to -- is held as part of the current stack frame
                        >>and is removed on return from the function; the object may or may not be
                        >>garbage collected depending upon any other names bound to it).
                        >>
                        >> A qualified name is one with some sort of component specifier:
                        >><name>.<compo nent>, <name>[<component>]. These access items that are
                        >>inside the object that <nameis bound on. The component access
                        >>basically is a function/method call telling the object itself to change
                        >>the <componentbindi ng, not the top-level <namebinding.
                        >>
                        >
                        Hi Dennis, in the last paragraph you do not state specifically where
                        the name for the component name is looked for.
                        First in the local namespace, then in enclosing namespaces until the
                        global (read : module level) namespace, and finally in the builtins.
                        Do you mean that for
                        component name accesses,where the 'base' is not declared gobal, the
                        'base' name nevertheless is always looked for in the global scope?
                        unless it's found in another namespace before - same rules apply as for
                        a non-qualified name.

                        Comment

                        • Paddy

                          #13
                          Re: Scope, type and UnboundLocalErr or


                          Fredrik Lundh wrote:
                          Paddy wrote:
                          >
                          ... irrelevant as in 'although only mutable objects can have their
                          state modified; if n has a mutable value but the assignment statement
                          changed n to refer to another object, then the name would be tagged as
                          local'?

                          Oh bosh, can anyone come at it from a different tack?
                          >
                          look for "Assignment of an object to a single target is recursively
                          defined as follows" on this page (or at the corresponding page in the
                          language reference):
                          >

                          >
                          </F>
                          I had a look Frederick but the page lead to:

                          Which again failed to mention namespace issues.

                          - Pad.

                          Comment

                          • Paddy

                            #14
                            Re: Scope, type and UnboundLocalErr or


                            Bruno Desthuilliers wrote:
                            <SNIP>

                            Ta.

                            Comment

                            • Fredrik Lundh

                              #15
                              Re: Scope, type and UnboundLocalErr or

                              Paddy wrote:
                              I had a look Frederick but the page lead to:

                              Which again failed to mention namespace issues.
                              it says

                              The primary must evaluate to an object of a sequence or mapping type.

                              and links to a page that explains what a primary is. the interesting page is the
                              one about "atoms" (which includes identifiers), which point you to



                              which explains it all.

                              </F>



                              Comment

                              Working...