How to mutate both globals() and locals() from code.interact
Unfortunately code.interact
doesn't let you pass both globals()
and locals()
from the current namespace unless you copy them into a single dict like code.interact(local={**globals(), **locals()})
, but then changes you make to globals()
and locals()
won't be persisted.
However you can work around this by subclassing the console and overriding its runcode
method:
import code
try:
import readline
except ImportError:
pass
class MyInteractiveConsole(code.InteractiveConsole):
"""Extends InteractiveConsole to also pass globals to exec."""
def __init__(self, globals, *args, **kwargs):
code.InteractiveConsole.__init__(self, *args, **kwargs)
self.globals = globals
def runcode(self, code):
try:
exec(code, self.globals, self.locals)
except SystemExit:
raise
except:
self.showtraceback()
Having defined this somewhere, you can use it similarly to code.interact
:
MyInteractiveConsole(globals(), locals()).interact()
Except that this will let you read and mutate both globals and locals:
x = 7
will set a local
global x; x = 7
will set a global
and when you leave the interactive console with Ctrl+D (or Ctrl+Z then Enter on Windows), the changes you made should persist in your globals()
and locals()
.
Caveat: The docs for locals() warn:
The contents of this dictionary should not be modified; changes may not affect the values of local and free variables used by the interpreter.
so don't rely on these mutations to locals()
for anything mission-critical. PEP 558 and PEP 667 go into more detail, and might make locals()
behave more consistently in future versions of Python.