Hacker News new | past | comments | ask | show | jobs | submit login

> Python uses many dictionaries in the background: among other things, local variables

Just a minor correction, Python doesn't use dicts for local variables, `locals()` is a lie, it creates a dict from scratch. Internally each frame has an array of locals whose values correspond to the names in the code object's co_locals.




> `locals()` is a lie, it creates a dict from scratch.

Are you sure? The behavior I see suggests otherwise...

    >>> a = 1
    >>> d = locals()
    {'a': 1, 'd': {...}}
    >>> b = 2
    {'a': 1, 'd': {...}, 'b': 2}
    >>> d['b'] = 123
    >>> b
    123
    >>> d is locals()
    True


See PyFrame_FastToLocals() in the CPython source.

Try wrapping your code in a function and notice the changes are no longer mirrored. Calls to exec() and eval() cause PyFrame_FastToLocals() to be applied afterwards, as used by the interactive console, but this doesn't happen during normal execution


The REPL essentially operates at the global scope, which is represented as a dictionary. Variables local to a function are not stored in a dictionary, however:

    def main():
        a = 1
        d = locals()
        print d
        d['b'] = 123
        print b
        print d
        print d is locals()

    main()
Which prints

    {'a': 1}
    Traceback (most recent call last):
      File "test.py", line 23, in <module>
        main()
      File "test.py", line 19, in main
        print b
    NameError: global name 'b' is not defined


That's because the compiler doesn't know the locals() dictionary will be modified at runtime, so it treats b as a global variable (which happens to be undefined).

To show that not even changes to existing local variables work, try

  def main():
      a = 1
      d = locals()
      print d
      b = None
      d['b'] = 123
      print b
      print d
      print locals()
      print d is locals()
which prints

  {'a': 1}
  None
  {'a': 1, 'b': 123}
  {'a': 1, 'b': None, 'd': {...}}
  True
I.e. changes to the dictionary returned by locals() are ignored, and calling locals() again overrides the previous values.


Why this happens has been explained, but more generally what you posted really doesn't prove anything at hand really. The dictionary created from scratch could be made an updateable view by hooking __setitem__.

If you gonna contradict with "are you sure?" for something so objectively answered by the source, it might be helpful to think if your example actually demonstrates what you're trying to prove.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: