[Python-Dev] Accessing globals without dict lookup

Tim Peters tim.one@comcast.net
Sun, 10 Feb 2002 18:27:09 -0500

[Skip Montanaro]
> Just to see if I have a correct mental model of what Guido
> proposed, I drew a picture:
>     http://manatee.mojam.com/~skip/python/celldict.png
> The cells are the small blank boxes.  I guess the celldict would be the
> stuff I labelled "module dict".  The "func cells" would be an array like
> fastlocals, but would refer to cells in the module's dict.

Yup, except that fastlocals are part of a frame, not part of a function
object.  Guido didn't make a big deal about this, but it's key to
efficiency:  the expense of setting up func_cells is *not* incurred on a
per-call basis, it's done once when a function object is created
(MAKE_FUNCTION), then reused across all calls to that function object.

> I'm not clear where/how builtins are accessed though.

__builtin__ is just another module, and also has a celldict for a __dict__.
The empty squares in your diagram (the "bottom half" of your cells)
sometimes point to cells in __builtin__'s celldict.  They remain empty
(NULL) in __builtin__'s celldict, though.

> Is that what the extra indirection is, or are builtins incorporated into
> the module dict somehow?

In Guido's proposal, module celldicts sometimes point to builtin's cells.
It's set up so that *all* names of builtins get an entry in the module's
dict, even names that aren't referenced in the module (this avoids global
analysis).  Their initial entries look like:

   "len":  {NULL, pointer to the "len" cell in the builtins}

Setting "len" as a module global (if you ever do that) overwrites the NULL.
Then later del'ing "len" again (if you ever do that) restores the NULL.  For
*most* purposes, a cell with a NULL first pointer acts as if it didn't
exist.  It's only the eval loop that understands the "deep structure".

In the variant I sketched today, there are no cross-dict pointers, and the
initial entries look like

   "len": {the actual value of "len" from builtins, true}

instead.  Then mutating the builtins requires reaching back into modules and
updating their timdicts.  In return, access code is simpler+faster, and
there aren't semantic changes (compared to today) if the builtins mutate
*after* a module's dict is initially populated (Guido's scheme appears
vulnerable here in at least two ways).