Painful details of variable scope mixed with classes

A code object doesn’t have a reference to the builtins and globals scopes that are required to execute it. Thus exec() and eval() take the globals to use as an option, which defaults to the current globals. The builtins scope can be set as __builtins__ in globals, else it defaults to the current builtins.

A function object references its builtins and globals scopes, which are exposed as its __builtins__ and __globals__ read-only attributes. It doesn’t matter from where a function is called. It always uses the same builtins and globals. For example:

>>> b = vars(builtins).copy()
>>> g = {'__builtins__': b}
>>> exec('f = lambda: spam', g)

>>> g['f'].__builtins__ is b
True
>>> g['f'].__globals__ is g
True

>>> b['spam'] = 'eggs'
>>> g['f']()
'eggs'

Note that the __builtins__ reference in globals no longer matters to the function object because it has its own reference.

>>> del g['__builtins__']
>>> g['f']()
'eggs'
2 Likes