exit
isn't in globals()
because it isn't a global, it's a builtin.
In Python, the "global" namespace is per-module, not system-wide. There's a special "builtins" module that holds the things that are truly system-wide, like the normal builtin functions and a few special things like exit
.
You can access this module with import builtins
.
The way the interpreter accesses this module is a little funky. Global lookup works roughly like this:
def get_global(global_namespace, name):
try:
return global_namespace[name]
except KeyError:
pass
try:
builtins = global_namespace['__builtins__']
except KeyError:
raise NameError(name)
if isinstance(builtins, types.ModuleType):
builtins = builtins.__dict__
try:
return builtins[name]
except KeyError:
raise NameError(name)
There's special code in places like exec
, and the internal code for building function objects, that makes sure that if you override the normal globals
dictionary, __builtins__
gets copied over (unless you explicitly tell it not to). When the import system builds a module object out of your module source (or compiled .pyc
), it calls exec
, so every module's globals ends up with the right __builtins__
.
Most things in the builtins
module are there because they're compiled into it (as you'd expect from the name); for CPython, you can see the source in Python/bltinmodule.c
.
But notice that exit
isn't there. In fact, it's injected into the builtins
module by the site
module, which is imported (unless you disable it) as part of the normal startup sequence. You can see the code that does this in Lib/site.py
and Lib/_sitebuiltins.py
. And the exit
constant says it's injected this way.
So, when you type exit
in your code, or at the interactive prompt, it's found in globals()['__builtins__']['exit']
or globals()['__builtins__'].__dict__['exit']
.
But if you want to access it manually, you're better off doing an import builtins
and accessed it as builtins.exit
.
Although really, you rarely want to access builtins.exit
anyway; if you want to exit programmatically, call sys.exit
, which is a normal function. builtins.exit
is a special Quitter
object that's made specifically for interactive use. (It has a repr
that gives a helpful message if you forget the parentheses, and some extra code to make it play nice with IDLE.)
In fact, the docs on the exit
constant explicitly say that it's:
… useful for the interactive interpreter shell and should not be used in programs.