Feature request for @ProjectJupyter: Define multiple namespaces within the same notebook (without using functions).
— Juan Manuel Caicedo (@cavorite) May 5, 2016
This is a simple proof-of-concept implementation of switching namespaces via magics. The key points we need:
.user_ns
attribute on the IPython instanceip.init_user_ns
First, we create a dict of namespaces by name on IPython, and save the initial value:
ip = get_ipython()
ip.namespaces = {}
ip._original_user_ns = ip.user_ns
Next, we define a %ns
line magic for switching namespaces by name:
We use ChainMap so that globals that IPython defines, such as In, Out, etc. are available no matter what namespace we switch to:
from collections import ChainMap
def set_namespace(name):
"""Line magic for switching namespaces:
%ns foo
a = 5
%ns bar
a = 10
%ns foo
print(a)
# 10
"""
if name not in ip.namespaces:
ip.namespaces[name] = ChainMap({}, ip._original_user_ns)
ip.user_ns = ip.namespaces[name]
ip.register_magic_function(set_namespace, magic_name='ns')
set_namespace('default')
%ns foo
a = 5
%ns bar
a = 10
%ns foo
a
5
ip.namespaces['foo']['a']
5
ip.namespaces['bar']['a']
10
%whos
Variable Type Data/Info ------------------------------------- ChainMap ABCMeta <class 'collections.ChainMap'> a int 5 set_namespace function <function set_namespace at 0x109866d90>
%ns bar
%whos
Variable Type Data/Info ------------------------------------- ChainMap ABCMeta <class 'collections.ChainMap'> a int 10 set_namespace function <function set_namespace at 0x109866d90>
We can also make a cell magic for running a whole cell in a given namespace, then switching back to whatever was already active:
def namespace_cell(name, cell):
"""Cell magic for running a single cell in a given namespace
%%ns foo
a = 5
"""
save_ns = ip.user_ns
set_namespace(name)
try:
ip.run_cell(cell)
finally:
ip.user_ns = save_ns
ip.register_magic_function(namespace_cell, magic_kind='cell', magic_name='ns')
%%ns cellns
a = 'hello,'
print(a * 2)
hello,hello,
This didn't affect the running namespace:
a
10
But we can recall the cell namespace:
%%ns cellns
a
'hello,'
for name, ns in ip.namespaces.items():
print(name, ns.get('a', 'undefined'))
foo 5 bar 10 default undefined cellns hello,