Oddity in 2.4 with eval('None')

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Leif K-Brooks

    #1

    Oddity in 2.4 with eval('None')

    In Python 2.4, although None can't be directly assigned to,
    globals()['None'] can still be; however, that won't change the value of
    the expression "None" in ordinary statements. Except with the eval
    function, it seems:

    Python 2.4 (#2, Dec 3 2004, 17:59:05)
    [GCC 3.3.5 (Debian 1:3.3.5-2)] on linux2
    Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
    >>> print None[/color][/color][/color]
    None[color=blue][color=green][color=darkred]
    >>> print eval('None')[/color][/color][/color]
    None[color=blue][color=green][color=darkred]
    >>> globals()['None'] = "spam"
    >>> print None[/color][/color][/color]
    None[color=blue][color=green][color=darkred]
    >>> print eval('None')[/color][/color][/color]
    spam

    I don't really mind this weird behavior; I'm just curious about it. Does
    anyone know what might be going on in Python's internals to cause the
    difference between "print None" and "print eval('None')"?
  • Steve Holden

    #2
    Re: Oddity in 2.4 with eval('None')

    Leif K-Brooks wrote:
    [color=blue]
    > In Python 2.4, although None can't be directly assigned to,
    > globals()['None'] can still be; however, that won't change the value of
    > the expression "None" in ordinary statements. Except with the eval
    > function, it seems:
    >
    > Python 2.4 (#2, Dec 3 2004, 17:59:05)
    > [GCC 3.3.5 (Debian 1:3.3.5-2)] on linux2
    > Type "help", "copyright" , "credits" or "license" for more information.[color=green][color=darkred]
    > >>> print None[/color][/color]
    > None[color=green][color=darkred]
    > >>> print eval('None')[/color][/color]
    > None[color=green][color=darkred]
    > >>> globals()['None'] = "spam"
    > >>> print None[/color][/color]
    > None[color=green][color=darkred]
    > >>> print eval('None')[/color][/color]
    > spam
    >
    > I don't really mind this weird behavior; I'm just curious about it. Does
    > anyone know what might be going on in Python's internals to cause the
    > difference between "print None" and "print eval('None')"?[/color]

    Yes. "print eval('None')" is printing the value of None as defined in
    your module's global namespace:

    Python 2.4 (#1, Dec 4 2004, 20:10:33)
    [GCC 3.3.3 (cygwin special)] on cygwin
    Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
    >>> import sys
    >>> globals()['None'] = "FooBar"
    >>> print sys.modules["__main__"].None[/color][/color][/color]
    FooBar[color=blue][color=green][color=darkred]
    >>> print __builtins__.No ne[/color][/color][/color]
    None[color=blue][color=green][color=darkred]
    >>> print eval("__builtin s__.None")[/color][/color][/color]
    None >>>

    regards
    Steve
    --
    Steve Holden http://www.holdenweb.com/
    Python Web Programming http://pydish.holdenweb.com/
    Holden Web LLC +1 703 861 4237 +1 800 494 3119

    Comment

    • M.E.Farmer

      #3
      Re: Oddity in 2.4 with eval('None')

      Python 2.2.2 (#37, Nov 26 2002, 10:24:37) [MSC 32 bit (Intel)] on win32
      Type "help", "copyright" , "credits" or "license" for more information.[color=blue][color=green][color=darkred]
      >>> dir()[/color][/color][/color]
      ['__builtins__', '__doc__', '__name__', 'shell'][color=blue][color=green][color=darkred]
      >>> globals()['None'][/color][/color][/color]
      Traceback (most recent call last):
      File "<input>", line 1, in ?
      KeyError: None[color=blue][color=green][color=darkred]
      >>> print None[/color][/color][/color]
      None[color=blue][color=green][color=darkred]
      >>> print eval('None')[/color][/color][/color]
      None[color=blue][color=green][color=darkred]
      >>> globals()['None']='wassabi'
      >>> print None[/color][/color][/color]
      wassabi[color=blue][color=green][color=darkred]
      >>> print eval('None')[/color][/color][/color]
      wassabi[color=blue][color=green][color=darkred]
      >>> dir()[/color][/color][/color]
      ['None', '__builtins__', '__doc__', '__name__', 'shell'][color=blue][color=green][color=darkred]
      >>>[/color][/color][/color]

      I think you are seeing two things and I admit I was confused a bit too.
      None is becoming a constant and this is the first step. That is why you
      see diffrent results than mine. Also notyice that None didn't exist in
      your lnamespace till you defined it then you see all your trouble
      start.Shadowing builtins and semi-constants are a bad thing
      M.E.Farmer

      Comment

      • Leif K-Brooks

        #4
        Re: Oddity in 2.4 with eval('None')

        Steve Holden wrote:[color=blue]
        > Yes. "print eval('None')" is printing the value of None as defined in
        > your module's global namespace:[/color]

        Right, but why? The expression "None" doesn't worry about the global
        namespace when used in normal code; why does it when used in eval()ed code?

        Comment

        • Steve Holden

          #5
          Re: Oddity in 2.4 with eval('None')

          Leif K-Brooks wrote:
          [color=blue]
          > Steve Holden wrote:
          >[color=green]
          >> Yes. "print eval('None')" is printing the value of None as defined in
          >> your module's global namespace:[/color]
          >
          >
          > Right, but why? The expression "None" doesn't worry about the global
          > namespace when used in normal code; why does it when used in eval()ed code?[/color]

          I have no idea why. Given that
          [color=blue][color=green][color=darkred]
          >>> eval("globals()['__builtins__'].globals().keys ()")[/color][/color][/color]
          ['None', '__builtins__', '__file__', 'sys', '__name__', '__doc__']

          it's beginning to smell a bit like a buglet.

          regards
          Steve
          --
          Steve Holden http://www.holdenweb.com/
          Python Web Programming http://pydish.holdenweb.com/
          Holden Web LLC +1 703 861 4237 +1 800 494 3119

          Comment

          • Fredrik Lundh

            #6
            Re: Oddity in 2.4 with eval('None')

            Leif K-Brooks wrote
            [color=blue][color=green]
            >> Yes. "print eval('None')" is printing the value of None as defined in your module's global
            >> namespace:[/color]
            >
            > Right, but why? The expression "None" doesn't worry about the global namespace when used in normal
            > code; why does it when used in eval()ed code?[/color]

            from what I can tell, the mapping of the None symbol to a constant is done
            in the peephole optimizer, which doesn't seem to be used when compiling
            expressions.

            in 2.4:
            [color=blue][color=green][color=darkred]
            >>> dis.dis(compile ("None", "", "exec"))[/color][/color][/color]
            1 0 LOAD_CONST 0 (None)
            3 POP_TOP
            ...[color=blue][color=green][color=darkred]
            >>> dis.dis(compile ("None", "", "eval"))[/color][/color][/color]
            0 0 LOAD_NAME 0 (None)
            3 RETURN_VALUE

            in 2.3:
            [color=blue][color=green][color=darkred]
            >>> dis.dis(compile ("None", "", "exec"))[/color][/color][/color]
            1 0 LOAD_NAME 0 (None)
            3 POP_TOP
            ...[color=blue][color=green][color=darkred]
            >>> dis.dis(compile ("None", "", "eval"))[/color][/color][/color]
            0 0 LOAD_NAME 0 (None)
            3 RETURN_VALUE

            </F>



            Comment

            • Raymond Hettinger

              #7
              Re: Oddity in 2.4 with eval('None')

              "Leif K-Brooks" <eurleif@ecritt ers.biz>[color=blue]
              > In Python 2.4, although None can't be directly assigned to,
              > globals()['None'] can still be; however, that won't change the value of
              > the expression "None" in ordinary statements. Except with the eval
              > function, it seems:
              >
              > Python 2.4 (#2, Dec 3 2004, 17:59:05)
              > [GCC 3.3.5 (Debian 1:3.3.5-2)] on linux2
              > Type "help", "copyright" , "credits" or "license" for more information.[color=green][color=darkred]
              > >>> print None[/color][/color]
              > None[color=green][color=darkred]
              > >>> print eval('None')[/color][/color]
              > None[color=green][color=darkred]
              > >>> globals()['None'] = "spam"
              > >>> print None[/color][/color]
              > None[color=green][color=darkred]
              > >>> print eval('None')[/color][/color]
              > spam
              >
              > I don't really mind this weird behavior; I'm just curious about it. Does
              > anyone know what might be going on in Python's internals to cause the
              > difference between "print None" and "print eval('None')"?[/color]

              It is a nuance of how None is being made constant.

              For backwards compatability, None still has to be in the globals dictionary.
              Like all entries in the globals dictionary, you can change it if you try hard
              enough (which you did).

              For Py2.4, whenever bytecode is generated for a code object, references to
              "None" in the globals dictionary are bypassed and replaced with a constant
              reference to Py_None, the one, true, singleton instance of None. That will
              occur even if you've mucked with None entry in the globals dictionary.

              Bytecode for eval() doesn't go through the bytecode optimizer so its dictionary
              lookup is retained (producing the effect in your example).

              To have made None a literal constant would have been a much more radical step.
              Py2.4 simulates this and gives you the real benefit being sought, faster
              function execution, without having incurred the costs of having a new literal.

              It's possible to fool the simulation, but who cares.


              Raymond Hettinger


              Comment

              Working...