IPython extends Python by adding shell-like commands called magics.
In [1]:
%lsmagic
Out[1]:
In [2]:
import numpy
In [3]:
%timeit A=numpy.random.random((1000,1000))
In [4]:
%%timeit -n 1
A=numpy.random.random((1000,1000))
b = A.sum()
As we have seen already, IPython has cell and line magics. You can define your own magics using any Python function and the register_magic_function method:
In [5]:
ip = get_ipython()
In [6]:
import time
def sleep_magic(line):
"""A simple function for sleeping"""
t = float(line)
time.sleep(t)
In [7]:
ip.register_magic_function?
In [8]:
ip.register_magic_function(sleep_magic, "line", "sleep")
In [9]:
%sleep 2
In [10]:
%sleep?
Define %tic and %toc magics, which can be use for simple timings, e.g. where
for p in range(1,4):
N = 10**p
print "N=%i" % N
%tic
A = np.random.random((N,N))
np.linalg.eigvals(A)
%toc
each %toc will print the time since the last %tic. Create separate tic and toc functions that read and write
a global time variable.
In [11]:
%load soln/tictocf.py
In [13]:
import numpy as np
import sys
for p in range(1,4):
N = 10**p
print "N=%i" % N
sys.stdout.flush()
%tic
A = np.random.random((N,N))
np.linalg.eigvals(A)
%toc
Cell magics take two args:
In [14]:
def dummy_cell_magic(line, cell):
"""dummy cell magic for displaying the line and cell it is passed"""
print "line: %r" % line
print "cell: %r" % cell
ip.register_magic_function(dummy_cell_magic, "cell", "dummy")
In [15]:
%%dummy this is the line
this
is the
cell
In [16]:
def parse_magic_line(line):
"""parse a magic line into a name and eval'd expression"""
name, values_s = line.split(None, 1)
values = eval(values_s, get_ipython().user_ns)
return name, values
parse_magic_line("x range(5)")
Out[16]:
Can you write and register a cell magic that automates the outer iteration, timing a block for various values of a particular variable:
In [17]:
%load soln/scalemagic.py
In [19]:
%%scale N [ int(10**p) for p in range(1,4) ]
A = np.random.random((N,N))
np.linalg.eigvals(A)
In [20]:
%%scale N [ int(2**p) for p in np.linspace(6, 11, 11) ]
A = np.random.random((N,N))
np.linalg.eigvals(A)
We can load a notebook into memory using IPython.nbformat.
In [21]:
import io
import os
from IPython.nbformat import current
In [22]:
def load_notebook(filename):
"""load a notebook object from a filename"""
if not os.path.exists(filename) and not filename.endswith(".ipynb"):
filename = filename + ".ipynb"
with io.open(filename) as f:
return current.read(f, 'json')
In [23]:
nb = load_notebook("Sample")
A notebook is just a dictionary with attribute access for convenience.
In [24]:
nb.keys()
Out[24]:
In [25]:
nb.worksheets[0].keys()
Out[25]:
In [26]:
cells = nb.worksheets[0].cells
cells
Out[26]:
We can see all the cells and their type
In [27]:
for cell in cells:
print
print '----- %s -----' % cell.cell_type
if cell.cell_type == 'code':
print cell.input
else:
print cell.source
Now I can run all of the code cells with get_ipython().run_cell
In [28]:
for cell in cells:
ip = get_ipython()
if cell.cell_type == 'code':
ip.run_cell(cell.input, silent=True)
And we can now use the function that was defined in that notebook:
In [29]:
nb_info(nb)
Can you write and register an %nbrun line magic to run a notebook?
%nbrun Sample
In [30]:
%load soln/nbrun.py
In [32]:
%nbrun Sample
The common way to make your magics reusable is to write an Extension, so let's give that a try.