How to get Python interactive console in current namespace?
Question:
I would like to have my Python code start a Python interactive console (REPL) in the middle of running code using something like code.interact(). But the console that code.interact() starts doesn’t see the variables in the current namespace. How do I do something like:
mystring=”hello”
code.interact()
… and then in the interactive console that starts, I should be able to type mystring and get “hello”. Is this possible? Do I need to set the “local” argument of code.interact() to something? What would this be set to? How should it be called?
Answers:
For debug I usually use this
from pdb import set_trace; set_trace()
it may help
Try:
code.interact(local=locals())
Another way is to start the debugger, and then run interact
:
import pdb
pdb.set_trace()
Then from the debugger:
(Pdb) help interact
interact
Start an interactive interpreter whose global namespace
contains all the (global and local) names found in the current scope.
(Pdb) interact
*interactive*
>>>
For Python 3.10.0:
code.InteractiveConsole(locals=locals()).interact()
See the Python documentation for more details.
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__(*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.
I would like to have my Python code start a Python interactive console (REPL) in the middle of running code using something like code.interact(). But the console that code.interact() starts doesn’t see the variables in the current namespace. How do I do something like:
mystring=”hello”
code.interact()
… and then in the interactive console that starts, I should be able to type mystring and get “hello”. Is this possible? Do I need to set the “local” argument of code.interact() to something? What would this be set to? How should it be called?
For debug I usually use this
from pdb import set_trace; set_trace()
it may help
Try:
code.interact(local=locals())
Another way is to start the debugger, and then run interact
:
import pdb
pdb.set_trace()
Then from the debugger:
(Pdb) help interact
interact
Start an interactive interpreter whose global namespace
contains all the (global and local) names found in the current scope.
(Pdb) interact
*interactive*
>>>
For Python 3.10.0:
code.InteractiveConsole(locals=locals()).interact()
See the Python documentation for more details.
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__(*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 localglobal 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.