exec src in {}, {} strangeness

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

    #1

    exec src in {}, {} strangeness

    hi there,

    I have trouble running some python code with 'exec':

    t.py contains:
    class Foo: pass
    class Bar:
    f = Foo

    From a python shell I do:
    [color=blue][color=green][color=darkred]
    >>> f = ''.join(open('t .py').readlines ())
    >>> exec f in {}, {}[/color][/color][/color]
    Traceback (most recent call last):
    File "<stdin>", line 1, in ?
    File "<string>", line 2, in ?
    File "<string>", line 3, in Bar
    NameError: name 'Foo' is not defined


    However, when I use the current global and local scope, i.e.
    simply 'exec f', everything works fine. What am I missing ?

    Thanks,
    Stefan
  • Do Re Mi chel La Si Do

    #2
    Re: exec src in {}, {} strangeness

    Hi !


    Try :

    exec f in globals(),local s()
    or
    exec(f,globals( ),locals())
    or
    exec f in globals(),globa ls()
    or
    exec(f,globals( ),globals())



    @-salutations

    Michel Claveau


    Comment

    • Stefan Seefeld

      #3
      Re: exec src in {}, {} strangeness

      Do Re Mi chel La Si Do wrote:[color=blue]
      > Hi !
      >
      >
      > Try :
      >
      > exec f in globals(),local s()
      > or
      > exec(f,globals( ),locals())
      > or
      > exec f in globals(),globa ls()
      > or
      > exec(f,globals( ),globals())[/color]

      Indeed, using 'globals()' and 'locals()' works. However,
      both report the same underlaying object, which is a bit
      confusing. (Under what circumstances does 'locals()' return
      not the same object as 'globals()' ?)

      The problem appears to be that

      exec f in a, b

      where a and b are distinct dictionaries, does not look up
      symbols in 'a' when in local scope.
      I filed a bug report (#1167300).

      Regards,
      Stefan

      Comment

      • Peter Hansen

        #4
        Re: exec src in {}, {} strangeness

        Stefan Seefeld wrote:[color=blue]
        > Indeed, using 'globals()' and 'locals()' works. However,
        > both report the same underlaying object, which is a bit
        > confusing. (Under what circumstances does 'locals()' return
        > not the same object as 'globals()' ?)[/color]

        When you aren't at the interactive prompt... there are
        no "locals" there, so locals() just maps through to globals().
        (Probably this applies to all code at the module level,
        as oppsed to code inside any callable, but I haven't
        verified... you can easily enough.)

        Does this information invalidate your bug report?

        -Peter

        Comment

        • Stefan Seefeld

          #5
          Re: exec src in {}, {} strangeness

          Peter Hansen wrote:[color=blue]
          > Stefan Seefeld wrote:
          >[color=green]
          >> Indeed, using 'globals()' and 'locals()' works. However,
          >> both report the same underlaying object, which is a bit
          >> confusing. (Under what circumstances does 'locals()' return
          >> not the same object as 'globals()' ?)[/color]
          >
          >
          > When you aren't at the interactive prompt... there are
          > no "locals" there, so locals() just maps through to globals().
          > (Probably this applies to all code at the module level,
          > as oppsed to code inside any callable, but I haven't
          > verified... you can easily enough.)
          >
          > Does this information invalidate your bug report?[/color]

          No, but that's possibly only because I don't (yet) understand
          the implications of what you are saying.

          Is there anything wrong with 'exec source in a, b' where
          a and b are distinc originally empty dictionaries ? Again,
          my test code was

          class Foo: pass
          class Bar:
          foo = Foo

          and it appears as if 'Foo' was added to 'a', but when evaluating
          'foo = Foo' the interpreter only looked in 'b', not 'a'.

          Thanks,
          Stefan

          Comment

          • Bernhard Herzog

            #6
            Re: exec src in {}, {} strangeness

            Stefan Seefeld <seefeld@sympat ico.ca> writes:
            [color=blue]
            > Is there anything wrong with 'exec source in a, b' where
            > a and b are distinc originally empty dictionaries ? Again,
            > my test code was
            >
            > class Foo: pass
            > class Bar:
            > foo = Foo
            >
            > and it appears as if 'Foo' was added to 'a', but when evaluating
            > 'foo = Foo' the interpreter only looked in 'b', not 'a'.[/color]

            No, it's the other way round. Foo is added in b since bindings are done
            in the local scope. Your case is a bit more complicated, though.
            Here's what I think happens:

            class Foo is bound in b, the locals dictionary, so there is no reference
            to Foo in the globals dictionary. The body of class B is executed with
            it's own new locals dictionary. That locals dictionary will effectively
            be turned into Bar.__dict__ when the class object is created.

            When "foo = Foo" is executed, Foo is first looked up in that new locals
            dictionary. That fails, so it's also looked up in the globals
            dictionary a. That fails as well because Foo was bound in b. The final
            lookup in the builtins also fails, and thus you get an exception.


            Bernhard

            --
            Intevation GmbH http://intevation.de/
            Skencil http://skencil.org/
            Thuban http://thuban.intevation.org/

            Comment

            • Stefan Seefeld

              #7
              Re: exec src in {}, {} strangeness

              Bernhard Herzog wrote:[color=blue]
              > Stefan Seefeld <seefeld@sympat ico.ca> writes:
              >
              >[color=green]
              >>Is there anything wrong with 'exec source in a, b' where
              >>a and b are distinc originally empty dictionaries ? Again,
              >>my test code was
              >>
              >>class Foo: pass
              >>class Bar:
              >> foo = Foo
              >>
              >>and it appears as if 'Foo' was added to 'a', but when evaluating
              >>'foo = Foo' the interpreter only looked in 'b', not 'a'.[/color]
              >
              >
              > No, it's the other way round. Foo is added in b since bindings are done
              > in the local scope. Your case is a bit more complicated, though.
              > Here's what I think happens:
              >
              > class Foo is bound in b, the locals dictionary, so there is no reference
              > to Foo in the globals dictionary. The body of class B is executed with
              > it's own new locals dictionary. That locals dictionary will effectively
              > be turned into Bar.__dict__ when the class object is created.
              >
              > When "foo = Foo" is executed, Foo is first looked up in that new locals
              > dictionary. That fails, so it's also looked up in the globals
              > dictionary a. That fails as well because Foo was bound in b. The final
              > lookup in the builtins also fails, and thus you get an exception.[/color]

              Thanks for the explanation ! I'm still unable to make a conclusion:
              What is wrong ? Am I doing something stupid (I did try various things
              such as inserting __builtin__ into the dictionary, etc.) ?
              Or is that really a bug ?

              Thanks,
              Stefan

              Comment

              • Greg Ewing

                #8
                Re: exec src in {}, {} strangeness

                Stefan Seefeld wrote:[color=blue]
                > Bernhard Herzog wrote:
                >[color=green]
                >> When "foo = Foo" is executed, Foo is first looked up in that new locals
                >> dictionary. That fails, so it's also looked up in the globals
                >> dictionary a. That fails as well because Foo was bound in b. The final
                >> lookup in the builtins also fails, and thus you get an exception.[/color][/color]

                Yes, from the experiment I just did, that does seem to
                be what is happening.
                [color=blue]
                > Thanks for the explanation ! I'm still unable to make a conclusion:
                > What is wrong ? Am I doing something stupid...? Or is that really a bug?[/color]

                It seems to be a hangover from the old two-scope system
                where local scopes didn't nest. It probably qualifies as
                a bug, since it differs from the modern behaviour of
                a class definition inside the local scope of a function.

                However, if your intention is to define the classes in
                the global dict then yes, you are doing something wrong --
                you should be passing the same dictionary for both scopes:

                g = {}
                exec stuff_to_define in g, g
                # definitions are now in g

                --
                Greg Ewing, Computer Science Dept,
                University of Canterbury,
                Christchurch, New Zealand

                Comment

                • Brano Zarnovican

                  #9
                  Re: exec src in {}, {} strangeness

                  As Greg pointed..

                  g = {}
                  exec open('t.py').re ad() in g, g

                  is what you want.

                  But you can write it also this way:
                  exec open('t.py').re ad() in {}

                  because if you specify only globals, the same
                  dictionary is also used for locals. (locals() is
                  used as a default only if you don't specify globals)

                  OR

                  explicitly move class Foo to globals

                  t.py contains:
                  globals Foo
                  class Foo: pass
                  class Bar:
                  f = Foo

                  (Should work. I haven't tried it, though)

                  BranoZ

                  Comment

                  Working...