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 [ ]:
%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 [ ]:
%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
import IPython.nbformat as nbf
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 nbf.read(f, as_version=4)
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]:
cells = nb.cells
cells
Out[25]:
We can see all the cells and their type
In [26]:
for cell in cells:
print()
print('----- %s -----' % cell.cell_type)
print(cell.source)
Now I can run all of the code cells with get_ipython().run_cell
In [27]:
for cell in cells:
ip = get_ipython()
if cell.cell_type == 'code':
ip.run_cell(cell.source, silent=True)
And we can now use the function that was defined in that notebook:
In [28]:
nb_info(nb)
Can you write and register an %nbrun
line magic to run a notebook?
%nbrun Sample
In [ ]:
%load soln/nbrun.py
In [31]:
%nbrun _Sample
The common way to make your magics reusable is to write an Extension, so let's give that a try.