Confused by Python and nested scoping (2.4.3)

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

    #1

    Confused by Python and nested scoping (2.4.3)

    Hi. I'm new to Python, and downloaded a Windows copy a little while
    ago. I was doing some experiments with nested functions, and ran into
    something strange.

    This code:

    def outer():
    val = 10
    def inner():
    print val
    inner()

    outer()

    ...prints out the value '10', which is what I was expecting.

    But this code..

    def outer():
    val = 10
    def inner():
    print val
    val = 20
    inner()
    print val

    outer()

    ...I expected to print '10', then '20', but instead got an error:

    print val
    UnboundLocalErr or: local variable 'val' referenced before assignment.

    I'm thinking this is some bug where the interpreter is getting ahead of
    itself, spotting the 'val = 20' line and warning me about something that
    doesn't need warning. Or am I doing something wrong?

    Thanks,
    -Sean Givan
  • Kelvie Wong

    #2
    Re: Confused by Python and nested scoping (2.4.3)

    There are only two scopes in Python -- global scope and function scope.

    On 4/19/06, Sean Givan <kinsman@nbnet. nb.ca> wrote:[color=blue]
    > Hi. I'm new to Python, and downloaded a Windows copy a little while
    > ago. I was doing some experiments with nested functions, and ran into
    > something strange.
    >
    > This code:
    >
    > def outer():
    > val = 10
    > def inner():
    > print val
    > inner()
    >
    > outer()
    >
    > ..prints out the value '10', which is what I was expecting.
    >
    > But this code..
    >
    > def outer():
    > val = 10
    > def inner():
    > print val
    > val = 20
    > inner()
    > print val
    >
    > outer()
    >
    > ..I expected to print '10', then '20', but instead got an error:
    >
    > print val
    > UnboundLocalErr or: local variable 'val' referenced before assignment.
    >
    > I'm thinking this is some bug where the interpreter is getting ahead of
    > itself, spotting the 'val = 20' line and warning me about something that
    > doesn't need warning. Or am I doing something wrong?
    >
    > Thanks,
    > -Sean Givan
    > --
    > http://mail.python.org/mailman/listinfo/python-list
    >[/color]


    --
    Kelvie

    Comment

    • Ben Cartwright

      #3
      Re: Confused by Python and nested scoping (2.4.3)

      Sean Givan wrote:[color=blue]
      > def outer():
      > val = 10
      > def inner():
      > print val
      > val = 20
      > inner()
      > print val
      >
      > outer()
      >
      > ..I expected to print '10', then '20', but instead got an error:
      >
      > print val
      > UnboundLocalErr or: local variable 'val' referenced before assignment.
      >
      > I'm thinking this is some bug where the interpreter is getting ahead of
      > itself, spotting the 'val = 20' line and warning me about something that
      > doesn't need warning. Or am I doing something wrong?[/color]


      Short answer: No, it's not a Python bug. If inner() must modify
      variables defined in outer()'s scope, you'll need to use a containing
      object. E.g.:

      class Storage(object) :
      pass
      def outer():
      data = Storage()
      data.val = 10
      def inner():
      print data.val
      data.val = 20
      inner()
      print data.val

      Long answer:

      The interpreter (actually, the bytecode compiler) is indeed looking
      ahead. This is by design, and is why the "global" keyword exists. See
      Contents: Programming FAQ- General questions- Is there a source code-level debugger with breakpoints and single-stepping?, Are there tools to help find bugs or perform static analysis?, How can I c...


      Things get more complex than that when nested function scopes are
      involved. But again, the behavior you observed is a design decision,
      not a bug. By BDFL declaration, there is no "parentscop e" keyword
      analogous to "global". See PEP 227, specifically the "Rebinding names
      in enclosing scopes" section: http://www.python.org/dev/peps/pep-0227/

      Hope that helps,
      --Ben

      Comment

      • Schüle Daniel

        #4
        Re: Confused by Python and nested scoping (2.4.3)

        Sean Givan schrieb:[color=blue]
        > Hi. I'm new to Python[/color]

        welcome
        [color=blue]
        > ago. I was doing some experiments with nested functions, and ran into
        > something strange.
        >
        > This code:
        >
        > def outer():
        > val = 10
        > def inner():
        > print val
        > inner()
        >
        > outer()
        >
        > ...prints out the value '10', which is what I was expecting.
        >
        > But this code..
        >
        > def outer():
        > val = 10
        > def inner():
        > print val
        > val = 20
        > inner()
        > print val
        >
        > outer()
        >
        > ...I expected to print '10', then '20', but instead got an error:
        >
        > print val
        > UnboundLocalErr or: local variable 'val' referenced before assignment.
        >
        > I'm thinking this is some bug where the interpreter is getting ahead of
        > itself, spotting the 'val = 20' line and warning me about something that[/color]

        just a little carefull thought
        if something that basic should really be a bug
        how many thousand people would discover it daily?
        [color=blue]
        > doesn't need warning. Or am I doing something wrong?[/color]

        yes, you can't modify it
        you can do it for global namespace or local
        but not inbetween

        val = 0
        def outer():
        val = 10
        def inner():
        global val
        val = 30
        inner()
        print val
        outer()
        10 # outer val is not changed
        print val # global is modified
        30

        hth, Daniel

        Comment

        • Terry Reedy

          #5
          Re: Confused by Python and nested scoping (2.4.3)


          "Sean Givan" <kinsman@nbnet. nb.ca> wrote in message
          news:AGy1g.6259 5$VV4.1170375@u rsa-nb00s0.nbnet.nb .ca...[color=blue]
          > Hi. I'm new to Python, and downloaded a Windows copy a little while
          > ago. I was doing some experiments with nested functions, and ran into
          > something strange.[/color]
          Experiments are good. Strange can be instructive.
          ....[color=blue]
          > I'm thinking this is some bug[/color]
          Blaming the interpreter is not so good, but amazingly common among
          newcomers ;-)
          [color=blue]
          > where the interpreter is getting ahead of itself,[/color]
          ....[color=blue]
          > Or am I doing something wrong?[/color]

          In a sense, you got ahead of yourself. And the issue has nothing to do
          with nested scopes per se. When things seem strange, try a simpler
          experiment.[color=blue][color=green][color=darkred]
          >>> x=1
          >>> def f():[/color][/color][/color]
          print x
          x = 2
          [color=blue][color=green][color=darkred]
          >>> f()[/color][/color][/color]
          Traceback (most recent call last):
          File "<pyshell#5 >", line 1, in -toplevel-
          f()
          File "<pyshell#4 >", line 2, in f
          print x
          UnboundLocalErr or: local variable 'x' referenced before assignment

          The compiler compiles functions in two passes: the first to classify names
          as local or global (or nested if relevant, but not really so here), the
          second to generate bytecodes which depend on that classification.

          Terry Jan Reedy



          Comment

          • Fredrik Lundh

            #6
            Re: Confused by Python and nested scoping (2.4.3)

            Sean Givan wrote:
            [color=blue]
            > Hi. I'm new to Python, and downloaded a Windows copy a little while
            > ago. I was doing some experiments with nested functions, and ran into
            > something strange.
            >
            > This code:
            >
            > def outer():
            > val = 10
            > def inner():
            > print val
            > inner()
            >
            > outer()
            >
            > ..prints out the value '10', which is what I was expecting.
            >
            > But this code..
            >
            > def outer():
            > val = 10
            > def inner():
            > print val
            > val = 20
            > inner()
            > print val
            >
            > outer()
            >
            > ..I expected to print '10', then '20', but instead got an error:
            >
            > print val
            > UnboundLocalErr or: local variable 'val' referenced before assignment.
            >
            > I'm thinking this is some bug where the interpreter is getting ahead of
            > itself, spotting the 'val = 20' line and warning me about something that
            > doesn't need warning. Or am I doing something wrong?[/color]

            reading the reference documentation may help:



            "If a name binding operation occurs anywhere within a code block,
            all uses of the name within the block are treated as references to
            the current block."

            </F>



            Comment

            • Petr Prikryl

              #7
              Re: Confused by Python and nested scoping (2.4.3)

              I have added some spaces guessing how the original was formatted.
              See the simplified example and the explanation below...

              "Sean Givan" wrote...[color=blue]
              > Hi. I'm new to Python [...] something strange.
              > This code:
              >
              > def outer():
              > val = 10
              > def inner():
              > print val
              > inner()
              > outer()
              >
              > ..prints out the value '10', which is what I was expecting.
              >
              > But this code..
              > def outer():
              > val = 10
              > def inner():
              > print val
              > val = 20
              > inner()
              > print val
              > outer()
              >
              > ..I expected to print '10', then '20', but instead got an error:
              >
              > print val
              > UnboundLocalErr or: local variable 'val' referenced before assignment.
              >
              > I'm thinking this is some bug where the interpreter is getting ahead of
              > itself, spotting the 'val = 20' line and warning me about something that
              > doesn't need warning. Or am I doing something wrong?[/color]

              The simplified example of both cases can be
              script a.py
              ---------------------------------------------
              val = 10

              def myFunction():
              print val

              myFunction()
              ---------------------------------------------

              In this case the val is not defined inside myFunction();
              therefore, it is searched in the "upper level", above
              the function body. Such variable is called free variable.

              script b.py
              ---------------------------------------------
              val = 10

              def myFunction():
              print val
              val = 20

              myFunction()

              ---------------------------------------------

              In this case the val is assigned inside the myFunction()
              and it is not marked to be global. In this case Python
              decides that it will be the local variable (cannot be
              free variable anymore). Python insists on fact that
              in one block the variable can be or free or locally
              bound, but not both. This is decided during the
              compilation of the module and it does not depend
              on whether val = 20 assignment precedes the print val
              command or not. It is decided that it will be local
              inside myFunction and then the print wants to use
              the variable that was not assingned yet.

              pepr

              P.S. I have just noticed that Terry Jan Reedy answered
              similarly. Never mind... Repeat, repeat, repeat.... until
              you know ;)


              Comment

              • Kent Johnson

                #8
                Re: Confused by Python and nested scoping (2.4.3)

                Kelvie Wong wrote:[color=blue]
                > There are only two scopes in Python -- global scope and function scope.[/color]

                No, Python has local, nested, global and built-in scope.

                Kent

                Comment

                • BartlebyScrivener

                  #9
                  Re: Confused by Python and nested scoping (2.4.3)

                  >> P.S. I have just noticed that Terry Jan Reedy answered[color=blue][color=green]
                  >> similarly. Never mind... Repeat, repeat, repeat.... until
                  >> you know ;)[/color][/color]

                  Yes, and some of us appreciate the extra examples.

                  rick

                  Comment

                  Working...