[Tutor] Global namespace/dictionary

Steven D'Aprano steve at pearwood.info
Sun Dec 22 11:58:33 CET 2013


On Sat, Dec 21, 2013 at 02:22:32PM -0500, Keith Winston wrote:
> On Sat, Dec 21, 2013 at 12:56 PM, <tutor-request at python.org> wrote:
> 
> > py> x = 23
> > py> d = globals()
> > py> d['x']
> > 23
> > py> d['x'] = 42
> > py> x
> > 42
> >
> 
> 
> Well this is sort of fascinating, but a bit confusing: I was playing with
> this, and it seems like the global dictionary includes not just the name
> but the entire contents of every dictionary within it... 

Not just every dictionary, but every string, every list, every object in 
the global scope. That's the whole point of a namespace -- it is the 
"thing" which holds variable names and values.

So if you have a variable "x" set to the dict {1: "one"} and a variable 
"y" set to the list [1, 2, 4, 8], then your global namespace will be:

globals()
=> {"y": [1, 2, 4, 8], "x": {1: "one"}, ...}


(plus other stuff I'm not showing). Now don't worry about that being 
wasteful of memory. The objects (the dict, the list, etc.) have to be 
*somewhere* in memory, and that place happens to be the global 
namespace. Python is very efficient here, and doesn't duplicate values: 
the dictionary returned by globals() is NOT a copy of the variables, it 
actually is the very same dictionary that Python uses. So although it is 
quite large to print, there is nothing redundant about it.


> that seems
> implausibly redundant, so maybe that's just something about how exploring a
> dictionary functions recursively, or something? Maybe it's correct to say
> that any dictionaries within a namespace are stored in that namespace,
> though that doesn't really sound right.

No, that's exactly right. And the same applies for lists, strings, ints, 
floats and any other object. They have to live somewhere.



> >>> d = globals()
> >>> fubar = {1: 'spam', 'eggs': 2}
> >>> d
> {'__name__': '__main__', '__builtins__': <module 'builtins' (built-in)>,
> '__doc__': None, '__loader__': <class '_frozen_importlib.BuiltinImporter'>,
> 'fubar': {1: 'spam', 'eggs': 2}, 'd': {...}, '__package__': None}

Now this is a really good example of Python at work. You have a global 
variable d which is bound to the global namespace dict. That's the same 
dictionary which Python uses for global variables. But d is itself a 
global dictionary! Which means that the global namespace dict, which we 
call "d", has to include a reference back to itself.

Sure enough, if you print d, it shows d as a key. What does the value 
for d show? Well, it obviously cannot show the entire globals, since 
that would recurse infinitely:

print(d) 
=> {'__name__': '__main__', '__doc__': None, 
    'd': {'__name__': '__main__', '__doc__': None, 
          'd': {'__name__': '__main__', '__doc__': None, 
                'd': {'__name__': '__main__', '__doc__': None, 
                      'd': ... # and so on, forever


Instead, Python recognises the recursion, and short-cuts the process by 
only displaying "..." inside the dict:

print(d)
=> {'__name__': '__main__', '__doc__': None,
    'd': {...} }

(Obviously I've simplified the contents a bit, for brevity.)


You can experiment with such recursive structures in Python very easily. 
Here's a simple example:

L = []  # Empty list.
L.append(L)
print(L)

L.append(42)
print(L[0] == L)



-- 
Steven


More information about the Tutor mailing list