IPython for Web Devs
Picture of a Python snake
by Eric Hamiter
© 2020

About the author

Eric Hamiter is a software engineer that has been involved with the open source community for over a decade. Among some of his notable contributions have been the Firefox extension BugMeNot and the Sublime Text package GitHubinator.

Previously, he served in the United States Navy as a Cryptologic Technician - Interpretive (CTI). He lives in Nashville, Tennessee with his wife and two sons, and enjoys traveling, scuba diving, cooking, and writing about himself in the third person.


Per the first blurb on IPython’s web page, it is described as a rich architecture for interactive computing with:

A kernel for Jupyter.
Support for interactive data visualization and use of GUI toolkits.
Flexible, embeddable interpreters to load into your own projects.
Easy to use, high performance tools for parallel computing.

You can see that IPython has a veritable treasure trove of very powerful features. This book won’t be covering any of those.

Instead, we are going to explore the interactive shell via the command line that one would typically use in conjunction with Python web development, typically when working with a Django / Flask / Tornado / other Python web framework.

We are not going to cover every single feature that is available. We are going to concentrate on the ones that I feel will give you a significant boost in efficiency and usefulness. I encourage you to explore the official documentation in depth.

As far as specific versions go, this book will cover what is current at the time of writing, which is Python 3.9.0 and IPython 7.19.0.

Why bother?

What’s the point of using IPython if it’s not going to be using the Jupyter notebook?

Excellent question. While the Jupyter notebook is a wonderful tool, sometimes it can be overkill. At times, all I want is to quickly pop into a shell, grab an object, and do a little manipulation or testing.

What’s wrong with just using python to open a shell?

Another wonderful question. You’re really good at this. The answer is that there is nothing wrong with using the standard Python shell, but the reason to give IPython a try is that you get a lot of things for free. Among some of these features are:

  • Persistent input history
  • Tab completion
  • Extensible system of “magic” commands
  • A rich configuration system
  • Syntax highlighting as you type
  • Integration with a command line editor

…and much, much more.

Who this book is for

This is not a “learn how to program” book, nor is it geared toward data visualization or high performance processing that many may use Jupyter for. The audience in question are Python software developers who are comfortable with object-oriented programming in a command line environment.

If you’re a Django or Flask developer that will run python manage.py shell or flask shell in order to examine objects and test out bits of code, you’re in the right place. This should look familiar to you:

>>> u = User.objects.filter(email__icontains='dev')

>>> len(u)

>>> first_dev = u[0]

>>> first_dev.is_staff

>>> first_dev.username

>>> first_dev.email

If this leaves you slightly befuddled, the rest may be a bit hard to follow. You can learn more about Python and the shell here.

How to read this book

This book was generated using a Rust program called mdBook that has several goodies baked in. It handles the layout and responsive design so my focus can lie on the content of this book instead of the architecture of the site. I also use footnotes from time to time. 1

As far as the features go, you can:

…toggle the chapter menu by clicking on the hamburger menu:

…change the theme by selecting the paintbrush icon:

…search the book using the magnifying glass:

…turn pages by clicking the left and right angles:

You can also navigate by using your keyboard’s left and right arrows.

On the top right of the page, you can either print this book in its entirety or visit its Github repository, where the source code lives.

A warning symbol will appear by a section that has potentially tricky parts that require close attention:

Don’t run on wet tiled surfaces.

For code snippets, you can copy the input by clicking on the copy symbol:

ipython --version

Output from shell commands is represented in a color-inverted block:


1. Like this one.

This book is not free

Well… it’s free as in freedom, but not free as in beer. Although you don’t necessarily have to spend money to buy it.


You are most welcome (and encouraged) to buy me a coffee / beer / pizza to show your appreciation if you enjoy this book and you get something out of it— you learn some new tricks, speed up your efficiency, save your company tens of millions of dollars, and so forth. You can do that by clicking below:

This will not unlock special features of this book, or remove ads, because there are no features to unlock, and no ads to remove. You get the goods up front, and beyond this page, I won’t solicit you any further. If you finish the entire book, and learned some cool things, or especially if you find yourself returning here repeatedly for reference, I ask you to please consider being a supporter.

If you’re strapped for cash, waiting for your Bitcoins to mature, spent all your money investing in a llama farm, et cetera— you can make this book better. I’m a big believer in open source software, and this book is no different. Spot a tpyo typo? See something grievously wrong? Want to clarify an example? Make a pull request, and improve the quality for the next person who reads this book. Click the GitHub icon on the top right of the page to visit the repo. There are instructions on that page for getting everything set up for you locally.

If you don’t want to part with your hard-earned money, and have no desire to improve the content via pull requests, then tell someone about it. Mention this book to a friend, colleague, or enemy. Post a link to a forum you frequently visit. Tweet a link to it. The more people that see it, the better— for everyone. More eyes on the content ensures mistakes are caught, wrongs are righted, and knowledge is shared. Python programming efficiency soars, the global economy recovers, and cats and dogs live together in harmony.


  • You are a curious learner, and want to improve your programming skills.


Some slight assumptions are going to be made. I presume you own a computer, or at least have access to one. I am also going to assume it is of a Mac, Linux, or Windows variety. A further presumption is that you have Python 3 installed, a terminal program to access it, and the Python package installer, pip.

If the above is not true, there are a few remedies:

I also highly suggest using a virtual environment so you can keep your global Python installation nice and tidy, and can work in a separate environment that you can play around with and install different Python packages. This is a complex topic by itself, so for the remainder of this book, the assumption is that you are operating in such an environment. I use virtualenv and virtualenvwrapper, but you should use whatever works for you.

Once you are ready, you can install IPython by running:

pip install ipython

We can test that IPython was successfully installed by entering:

ipython --version


IPython has support for multiple profiles. This is handy if you are working on different projects and want to tweak some behaviors, or test out new settings without changing how IPython will behave globally. By default, IPython will always run the default profile. Once you specify a new profile to create, new configuration files will be created. To create a new profile named zagnut, enter: 2

ipython profile create zagnut
[ProfileCreate] Generating default config file: '/Users/eric/.ipython/profile_zagnut/ipython_config.py'

If at some point you forget where this configuration file was created, you can locate it:

ipython locate profile zagnut

To launch IPython with this configuration, pass in the name to the profile argument:

ipython --profile=zagnut
Python 3.9.0 (default, Nov  2 2020, 18:14:37)
Type 'copyright', 'credits' or 'license' for more information
IPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.

IPython profile: zagnut

In [1]:

To exit the shell, you can enter exit or use the keyboard shortcut CTRL-D.

If you are a Django developer and want to use an IPython profile in conjunction with the Django shell, you can do it by using the django-extensions package:

pip install django-extensions

It has a shell_plus extension (which gives you some niceties like auto importing your models), and you can pass the profile name in as:

python manage.py shell_plus --ipython -- --profile=zagnut

Note that there is a separate double dash (--) before the --profile.

Since this is kind of a long command to type each time you want to pop into a shell, I alias mine to something much simpler to remember: Python manage shell_plus:

alias pms='python manage.py shell_plus --ipython -- --profile=zagnut'

2. We all remember the candy bar of choice for Beetlejuice, right? No? Just me?


Once you have created your profile, open up its configuration file in your favorite text editor:

ipython locate profile zagnut
"${EDITOR:-vi}" ~/.ipython/profile_zagnut/ipython_config.py

This file is over 1,000 lines of code, so there’s a lot to take in— we’ll focus on a handful of things that are practical and help tailor your IPython experience. After we’ve explored the settings in this chapter, I encourage you to dive deep into the file for other settings. Experiment with logging, interacting with matplotlib, numpy, and Jedi integration if those are in your wheelhouse.


## Autoformatter to reformat Terminal code. Can be `'black'` or `None`
#  Default: None

black is the uncompromising Python code formatter. It can make collaboration on a project consistent— no matter the style of the coder, black will format the code to its specifications, so everything is nice and tidy.

c.TerminalInteractiveShell.autoformatter = 'black'

Enabling this can turn something like this:

In [1]: cost = {
    ...: 'apple': 0.40,
    ...: 'banana': 0.50}
    ...: bought = {
    ...:     'apple': 1,
    ...:     'banana': 6}
    ...: bill = sum(
    ...: cost[fruit] * bought[fruit]
    ...:                    for fruit in bought
    ...:                    )
    ...: print(
    ...: 'I owe the grocer $%.2f' % bill
    ...: )
I owe the grocer $3.40

…into this:

In [1]: cost = {"apple": 0.40, "banana": 0.50}
    ...: bought = {"apple": 1, "banana": 6}
    ...: bill = sum(cost[fruit] * bought[fruit] for fruit in bought)
    ...: print("I owe the grocer $%.2f" % bill)
I owe the grocer $3.40

It’s very handy for cleaning up your code style, especially if the project you’re working on uses black. In order for this to work, you need to have black installed in your environment:

pip install black

Once caveat that I have found is that if you do set the autoformatter to black, sometimes it will try and format things that aren’t necessarily code if you omit the optional % prefix. To be specific, there is a magic command %history, or its alias %hist. You use this to list the history of your IPython session’s inputs, and by default it lists them without a corresponding number beside each entry. If you do want to see a numbered list, you need to pass in the parameter n. So, it should look like this:

history -n

…but black reformats that, which turns it into

history - n

…which isn’t an actual command, so you don’t see the numbers beside each line. So, this is something you should be aware of. To be safe, if you have black set to autoformat, try to always use the prefix % so there’s no confusion:

%history -n


## If True, any %store-d variables will be automatically restored when IPython
#  starts.
#  Default: False

%store is a “magic” command that we will discuss in just a bit— for the context needed for the autorestore setting, this allows you to store variables, aliases, and macros in IPython’s database during a session, then after exiting that session, having those values be retrieved automatically upon entering a new session.

c.StoreMagics.autorestore = True


## The part of the banner to be printed before the profile
#  Default: "Python 3.9.0 (default, Nov  2 2020, 18:14:37) \nType 'copyright', 'credits' or 'license' for more information\nIPython 7.19.0 -- An enhanced Interactive Python. Type '?' for help.\n"

You can customize the banner that is displayed on startup-- if you’re the kind of person who likes to tweak every customizable aspect of a system. You could cut it down to the important bits if you are into the whole brevity thing: 3

c.InteractiveShell.banner1 = "Python 3.9.0 -- IPython 7.19.0\n"

…or eliminate it entirely:

c.TerminalIPythonApp.display_banner = False

3. Yeah? Well, you know, that’s just like, uh… your opinion, man.


## Set the color scheme (NoColor, Neutral, Linux, or LightBG).
#  Choices: any of ['Neutral', 'NoColor', 'LightBG', 'Linux'] (case-insensitive)
#  Default: 'Neutral'

You can select from a few color schemes— I use a dark background for my terminal so the default Neutral works for me, but try out LightBG if you use a light background color, or Linux if you’re really into Linux, or NoColor if you hate rainbows and happiness.

c.InteractiveShell.colors = 'LightBG'

You can also change this on-the-fly in the shell by invoking the magic command %colors:

%colors Linux


## Set to confirm when you try to exit IPython with an EOF (Control-D in Unix,
#  Control-Z/Enter in Windows). By typing 'exit' or 'quit', you can force a
#  direct exit without any confirmation.
#  Default: True

Whenever I quit an IPython session, I’m asked if I really want to quit. I do. Eventually I figured out that you don’t actually have to enter y for yes, though— you can just hit return and it will allow you to quit. There’s a better way, though, which saves you an additional key stroke. Setting this value to False will let you exit immediately.

c.TerminalInteractiveShell.confirm_exit = False


## Set the editor used by IPython (default to $EDITOR/vi/notepad).
#  Default: 'subl'

The default listed above is subl for me because I use Sublime Text as my default editor. For you, it may be vim, vscode, emacs, nano, or any number of text editors. For my particular case, as we will explore later, there is an %edit magic command in IPython, which lets you …well, edit things. For whatever reason, Sublime Text does not work well with the %edit command. 4Because of this, I want to set IPython’s editor of choice to something else– vim, in my case: 5

c.TerminalInteractiveShell.editor = 'vim'

4. Once %edit is invoked, a temporary file is created. In Sublime’s case, it immediately executes the code instead of waiting for the save signal to execute it, so there is never a chance of actually editing the file.
5. A thousand apologies if I angered any Emacs wizards. I use Vim here because I know the basics, and watching me try to use Emacs is just an embarrassing spectacle that no one should have to witness.


## lines of code to run at IPython startup.
#  Default: []

InteractiveShellApp.exec_lines is a list that will execute on IPython’s startup. If you wanted to see The Zen of Python by Tim Peters everytime you fired up the shell, you could put in:

c.InteractiveShellApp.exec_lines = ['import this']

That might not be totally practical, but it could be inspiring. An extension that we will talk more about later is the autoreload extension. It’s pretty nice to have this available without having to manually load it— it lets you change source code in an editor while the shell is still open, and it will reload its value without requiring you to have to restart your session. 6

You can enable it to run by default with these lines:

c.InteractiveShellApp.exec_lines = []
c.InteractiveShellApp.exec_lines.append('%load_ext autoreload')
c.InteractiveShellApp.exec_lines.append('%autoreload 2')    

6. As with anything seemingly too good to be true, it does have its caveats and doesn’t work for every case. It works more often than not, though, and can save you a lot of time.


## The name or class of a Pygments style to use for syntax highlighting. To see
#  available styles, run `pygmentize -L styles`.
#  Default: traitlets.Undefined

Pygments is a generic syntax highlighter used to prettify source code. You can set your style of choice by entering:

c.TerminalInteractiveShell.highlighting_style = 'monokai'

It is dependent on the Pygments library, which can be installed via:

pip install Pygments

You can view all of the available styles (below is a sample of the complete output):

pygmentize -L styles
* emacs:
    The default style (inspired by Emacs 22).
* monokai:
    This style mimics the Monokai color scheme.
* vim:
    Styles somewhat like vim 7.0
* xcode:
    Style similar to the Xcode default colouring theme.
* solarized-dark:
    The solarized style, dark.
* solarized-light:
    The solarized style, light.


## Automatically call the pdb debugger after every exception.
#  Default: False

The Python debugger can be a super useful tool for stepping through code and examining what’s going on. Normally to use it, you import it and then set the trace:

import pdb; pdb.set_trace()

Things got a little more simple with the advent of PEP 553 which introduced breakpoint() to Python 3.7. You can accomplish the above with simply:


To invoke this automatically in your shell if you hit an exception, you can set it like so:

c.InteractiveShell.pdb = True

Now, whenever your code hits an exception, you will automatically be dropped into the debugger.

Magic Commands

The magic function system provides a series of functions which allow you to
control the behavior of IPython itself, plus a lot of system-type

There are two kinds of magics: line and cell.

Line magics are prefixed with the % character and work much like OS command-line calls: they get as an argument the rest of the line, where arguments are passed without parentheses or quotes.

Cell magics are prefixed with a double %%, and they are functions that get as an argument not only the rest of the line, but also the lines below it in a separate argument. These magics are called with two arguments: the rest of the call line and the body of the cell, consisting of the lines below the first.

Magic commands can be used without typing the % sign by default— this behavior is altered by running the magic command %automagic, which toggles the necessity of the preceding % character.

Keep in mind that if you create a variable that collides with an automagic command, using your variable (without the explicit % prefix) will override the magic command’s reference, e.g.

In [1]: automagic

Automagic is OFF, % prefix IS needed for line magics.

In [2]: %automagic

Automagic is ON, % prefix IS NOT needed for line magics.

In [3]: automagic = print

In [4]: automagic
Out[4]: <function print>

In [5]: %automagic

Automagic is OFF, % prefix IS needed for line magics.

You can view all available magic commands by running %lsmagic. Some of them will be recognizable as system commands and they behave as you might expect:

%alias  %cat  %cd  %clear  %less  %ls  %man  %mkdir  %more  %mv  %pip  %popd  %pushd  %pwd  %rm  %rmdir

Let’s look at some of the other commands that might be unfamiliar, and some examples of how you might use them.


    %aimport => Import modules for automatic reloading.

%aimport lets you specify a module to import that will automatically be reloaded. This command works alongside %autoreload, which lets you specify the frequency or inclusion of what modules will be autoreloaded.

List modules to automatically import and not to import:


Import module ‘foo’ and mark it to be autoreloaded for %autoreload 1:

%aimport foo

Import modules ‘foo’, ‘bar’ and mark them to be autoreloaded for %autoreload 1:

%aimport foo, bar

Mark module ‘foo’ to not be autoreloaded for %autoreload 1:

%aimport -foo


    %autoreload => Reload modules automatically

%autoreload will automatically reload modules, so you can edit code in an IDE or text editor, and when a change is made and saved, you can test the new functionality in the IPython shell without having to exit and start a new session. This is incredibly helpful and saves a lot of time-- and it will work most of the time. There are some caveats involved, but some of the problems that prevent successful reloading are:

  • Changing a @property to a method or a method to a variable within a class
  • Functions that are removed from a module before it is reloaded are not upgraded
  • C extension modules cannot be reloaded

You can pass in a parameter to either disable reloading completely, only use imports that were specified with the command %aimport, or reload all modules every time before the code is executed.

Disable automatic reloading:

%autoreload 0

Reload all modules imported with %aimport every time before executing the Python code typed:

%autoreload 1

Reload all modules (except those excluded by %aimport) every time before executing the Python code typed:

%autoreload 2


    Manage IPython's bookmark system.

Setting bookmarks is very handy if you find yourself changing directories within a project, or even outside a project and would like to be have faster access to often-used directories.

%bookmark <name>       - set bookmark to current dir
%bookmark <name> <dir> - set bookmark to <dir>
%bookmark -l           - list all bookmarks
%bookmark -d <name>    - remove bookmark
%bookmark -r           - remove all bookmarks

Here’s an example that shows setting a bookmark to the current directory, navigating to the user’s home directory, then coming back to the project:

In [1]: %pwd
Out[1]: '/Users/eric/projects/ipython-book'

In [2]: %bookmark book

In [3]: %bookmark -l
Current bookmarks:
book -> /Users/eric/projects/ipython-book

In [4]: %cd ~

In [5]: %pwd
Out[5]: '/Users/eric'

In [6]: %cd -b book
(bookmark:book) -> /Users/eric/projects/ipython-book

In [7]: %pwd
Out[7]: '/Users/eric/projects/ipython-book'

You can also omit the -b after the %cd command if there’s no directory with the name of your bookmark. The bookmarks are associated with each profile and persist through IPython sessions.


    Paste & execute a pre-formatted code block from clipboard.

%cpaste and %paste are pretty similar— they allow you to copy a block of code from somewhere outside of the shell and paste it in without having to tweak the indentation or removal of common Python snippet characters, like > or + that are common in e-mails, diff files, and doctests.

The primary difference is that %cpaste allows you to paste in your snippet, and then continue to add more or edit what you pasted before it’s executed. You have to terminate your block with either two minus signs (--) or CTRL-D alone on an empty line.

In [1]: %cpaste
Pasting code; enter '--' alone on the line to stop.
:>>> a = ["world!", "Hello"]
:>>> print " ".join(sorted(a))
Hello world!


    Activate the interactive debugger.

If an exception has just occurred, you can inspect its stack interactively by entering %debug, which will drop you into a pdb session. This will only work on the last traceback that occurred, so it must be called immediately, or else the exception may be clobbered by an additional exception.

In [1]: def this_will_not_work():
    ...:     first = 'abc'
    ...:     second = 'def'
    ...:     third = first / second
    ...:     return third

In [2]: this_will_not_work()
TypeError                                 Traceback (most recent call last)
<ipython-input-2-b68cb3b4fc7d> in <module>
----> 1 this_will_not_work()

<ipython-input-1-2389d0ae72e8> in this_will_not_work()
      2     first = 'abc'
      3     second = 'def'
----> 4     third = first / second
      5     return third

TypeError: unsupported operand type(s) for /: 'str' and 'str'

In [3]: %debug
> <ipython-input-1-2389d0ae72e8>(4)this_will_not_work()
      1 def this_will_not_work():
      2     first = 'abc'
      3     second = 'def'
----> 4     third = first / second
      5     return third

ipdb> first
ipdb> second

You can have IPython do this automatically by setting the %pdb magic in ipython_config.py.


    Toggle doctest mode on and off.

You can change the way that IPython’s prompts, exceptions, and output looks by running %doctest_mode. This makes it easy to copy and paste code that has characters such as >>> and ... and have it recognize it. This is also handy if you use doctests in your docstrings, as you can directly copy and paste them from the shell without having to leave the session and they are ready to use in your functions.

An example:

In [1]: def my_amazing_function(a, b):
    ...:     return a * b

In [2]: %doctest_mode
Exception reporting mode: Plain
Doctest mode is: ON
>>> my_amazing_function(2, 4)
>>> my_amazing_function('woo', 3)
>>> %doctest_mode
Exception reporting mode: Context
Doctest mode is: OFF

Now you can copy and paste the examples directly into your code’s docstring. Below is a complete working example, let’s say saved as example.py:

def my_amazing_function(a, b):
    >>> my_amazing_function(2, 4)
    >>> my_amazing_function('woo', 3)
    return a * b

if __name__ == "__main__":
    import doctest

So running python example.py will run the doctest and verify your statements are true. You won’t see any message (since it passes) but you can pass in the -v parameter for it to print a verbose log.

python example.py -v
    my_amazing_function(2, 4)
    my_amazing_function('woo', 3)
1 items had no tests:
1 items passed all tests:
   2 tests in __main__.my_amazing_function
2 tests in 2 items.
2 passed and 0 failed.
Test passed.


    Bring up an editor and execute the resulting code.

%edit (or %ed as an alias) runs IPython’s edit hook. By default, it will call the editor specified by your environment variable $EDITOR, but this can be specificed in ipython_config.py’s editor setting.

This is nice if you want to edit a lengthy function or potentially save a snippet you’ve been working on to a file.

If it is called with no arguments, it will open up an empty editor and will execute the contents once you save and exit.

%edit also accepts arguments:

  • A filename, which will be loaded into the editor
  • A range of input history, e.g. %edit 5 7 10-12
  • A string variable
  • A function name
  • A macro name

An example of creating a function, the editing it in an external editor:

In [1]: def brilliant_math_program(num):
    ...:     num += 1
    ...:     print(f'I increased your number to {num}')

In [2]: brilliant_math_program(2)
I increased your number to 3

In [3]: %edit brilliant_math_program
Editing In[3]
IPython will make a temporary file named: /var/folders/qx/32hkz1f96yb557l4yd0_c6q80000gn/T/ipython_edit_6gzx7_2p/ipython_edit_s5u64by2.py
Editing... done. Executing edited code...
Out[3]: "def brilliant_math_program(num):\n    num = num * 2\n    print(f'I doubled your number to {num}')\n     \n"

In [4]: brilliant_math_program(2)
I doubled your number to 4


    Get, set, or list environment variables.

If you need access to an environment variable and can’t remember what it was, you can recall it easily using %env. You can list all of them by passing the command by itself, or recall specific ones like %env variable, or set them like %env variable new_value.

In [1]: %env foo
UsageError: Environment does not have key: foo

In [2]: %env foo bar
env: foo=bar

In [3]: %env foo
Out[3]: 'bar'


    Print input history, with most recent last.

By default, %history (or its alias %hist) prints the input history without line numbers for ease in copying into an editor, so if you do want to see them, pass in -n to see them.

You can specify ranges to be returned, e.g.

In [5]: %history -n 1 3-4
  1: a = 5
  3: d = 8
  4: e = 9


    Load code into the current frontend.

%load lets you load in code from a filename, input history range, macro, an element in the user namespace, or even from a URL. It is very useful for taking a section of code from something like a GitHub repo and being able to load it directly into the shell so you can test it or use it.

If you feed in a large section of code, you can specify which lines you want by passing in the range parameter (-r). Below is an example of loading a utility function from the requests library. It passes in the import socket on line 15, and then subsequently loads lines 641-650 for a function that determines if a passed-in string is an IPV4 address:

In [1]: %load -r 15,641-650 https://raw.githubusercontent.com/psf/requests/master/requests/utils.py

In [2]: # %load -r 15,641-650 https://raw.githubusercontent.com/psf/requests/master/requests/utils.py
    ...: import socket
    ...: def is_ipv4_address(string_ip):
    ...:     """
    ...:     :rtype: bool
    ...:     """
    ...:     try:
    ...:         socket.inet_aton(string_ip)
    ...:     except socket.error:
    ...:         return False
    ...:     return True

In [3]: is_ipv4_address("")
Out[3]: True

In [4]: is_ipv4_address("pizza-is-delicious")
Out[4]: False


    List currently available magic functions.

Available line magics: %aimport %alias %alias_magic %autoawait %autocall %autoindent %automagic %autoreload %bookmark %cat %cd %clear %colors %conda %config %cp %cpaste %debug %dhist %dirs %doctest_mode %ed %edit %env %gui %hist %history %killbgscripts %ldir %less %lf %lk %ll %load %load_ext %loadpy %logoff %logon %logstart %logstate %logstop %ls %lsmagic %lx %macro %magic %man %matplotlib %mkdir %more %mv %notebook %page %paste %pastebin %pdb %pdef %pdoc %pfile %pinfo %pinfo2 %pip %popd %pprint %precision %prun %psearch %psource %pushd %pwd %pycat %pylab %quickref %recall %rehashx %reload_ext %rep %rerun %reset %reset_selective %rm %rmdir %run %save %sc %set_env %store %sx %system %tb %time %timeit %unalias %unload_ext %who %who_ls %whos %xdel %xmode

Available cell magics: %%! %%HTML %%SVG %%bash %%capture %%debug %%file %%html %%javascript %%js %%latex %%markdown %%perl %%prun %%pypy %%python %%python2 %%python3 %%ruby %%script %%sh %%svg %%sx %%system %%time %%timeit %%writefile


    Define a macro for future re-execution. It accepts ranges of history,
    filenames or string objects.

%macro is a great way of storing code snippets into a bundle that can be re-used for future use.

An example:

In [1]: a = 10

In [2]: b = 2

In [3]: c = a * b

In [4]: print(c)

In [5]: %macro abc 1-4
Macro `abc` created. To execute, type its name (without quotes).
=== Macro contents: ===
a = 10
b = 2
c = a * b

In [6]: abc

You can view a macro’s contents by explicitly printing it:

In [7]: print(abc)
a = 10
b = 2
c = a * b


    Print information about the magic function system.

Think of %magic as the user’s guide to magic commands. It steps through all of the commands listed in %lsmagic with extensive examples and all available parameters.

It supports three optional display parameters: -latex, -brief, and -rest. Here’s an example of the results for the first entry, aimport:

    %aimport => Import modules for automatic reloading.

    List modules to automatically import and not to import.

    %aimport foo
    Import module 'foo' and mark it to be autoreloaded for %autoreload 1

    %aimport foo, bar
    Import modules 'foo', 'bar' and mark them to be autoreloaded for %autoreload 1

    %aimport -foo
    Mark module 'foo' to not be autoreloaded for %autoreload 1
%magic -latex
\texttt{\textbf{ \%aimport}}:
    \texttt{\%aimport} => Import modules for automatic reloading.

    List modules to automatically import and not to import.

    \texttt{\%aimport} foo
    Import module 'foo' and mark it to be autoreloaded for \texttt{\%autoreload} 1

    \texttt{\%aimport} foo, bar
    Import modules 'foo', 'bar' and mark them to be autoreloaded for \texttt{\%autoreload} 1

    \texttt{\%aimport} -foo
    Mark module 'foo' to not be autoreloaded for \texttt{\%autoreload} 1
%magic -brief
    %aimport => Import modules for automatic reloading.
magic -rest

    %aimport => Import modules for automatic reloading.

    List modules to automatically import and not to import.

    %aimport foo
    Import module 'foo' and mark it to be autoreloaded for %autoreload 1

    %aimport foo, bar
    Import modules 'foo', 'bar' and mark them to be autoreloaded for %autoreload 1

    %aimport -foo
    Mark module 'foo' to not be autoreloaded for %autoreload 1


    Export and convert IPython notebooks.

Jupyter notebooks are very powerful tools and support a wide range of workflows in data science, scientific computing, and machine learning. We can export the history of a shell session into a notebook file, which can be opened and executed or edited later within a notebook.

%notebook filename.ipynb


    Paste & execute a pre-formatted code block from clipboard.

Similar to %cpaste, %paste allows you to paste a copied block of text properly into the shell, and it automatically handles any indentation differences, and ignores the > and + characters that may be present in e-mails, diffs, doctests, or code samples.

Unlike %cpaste, once you execute %paste, it automatically pastes and executes the block, so there is no further editing involved. It does however assign a variable to the pasted block, which is aptly named pasted_block, so you can then later edit it, e.g. %edit pasted_block. You can override this variable name by passing in a variable name directly:

%paste my_cool_code


    Upload code to dpaste's paste bin, returning the URL.

Sharing code with a collaborator can be tricky sometimes– formatting in e-mails can be hit or miss, Slack has pretty good support, but if it’s a free account, then the history gets erased after a couple of days. Pastebin sites are usually a good way to do this, but it can still be a pain to copy and paste using the correct indentation and erasing all of the In and Out prompts.

%pastebin allows you to upload a history range, filename, string, or macro to dpaste.com, which is a publicly-accessible pastebin site. The snippet that you upload is shareable through a unique link, and expires after 7 days.

By default, the title is “Pasted from IPython” but you can set the description with -d:

In [1]: import codecs

In [2]: def my_secret_translator(message):
    ...:     coded_message = codecs.encode(message, 'rot_13')
    ...:     print(coded_message)

In [3]: my_secret_translator('My cat meows at midnight')
Zl png zrbjf ng zvqavtug

In [4]: my_secret_translator('Zl png zrbjf ng zvqavtug')
My cat meows at midnight

In [5]: %pastebin -d 'I learned this in "IPython for Web Devs"!' 1-2
Out[5]: 'http://dpaste.com/CVQQQLVKX'


    Control the automatic calling of the pdb interactive debugger.

Just as you can set pdb to trigger on an exception in the ipython_config.py file, you can set it directly with the magic command %pdb.

It accepts “truthy” (%pdb on or %pdb 1) or “falsey” (%pdb off or %pdb 0) values, and if called without the argument it works as a toggle.

If you want to just activate the debugger after an exception has fired, without having to type %pdb on and rerunning your code, you can use the %debug magic.


    Print the call signature for any callable object.

%pdef prints a call signature for an object, or if the object is a class, it will print the constructor information. This is an easy way to see what parameters may or may not be required when creating or updating an object.

In [1]: import calendar

In [2]: %pdef calendar.TextCalendar
Class constructor information:

In [3]: import hashlib

In [4]: %pdef hashlib.md5
 hashlib.md5(string=b'', *, usedforsecurity=True)


    Print the docstring for an object.

%pdoc will print out the object’s docstring, or if it is a class, it will print both the class and constructor docstrings.

In [1]: from textwrap import dedent

In [2]: %pdoc dedent
Class docstring:
    Remove any common leading whitespace from every line in `text`.

    This can be used to make triple-quoted strings line up with the left
    edge of the display, while still presenting them in the source code
    in indented form.

    Note that tabs and spaces are both treated as whitespace, but they
    are not equal: the lines "  hello" and "\thello" are
    considered to have no common leading whitespace.

    Entirely blank lines are normalized to a newline character.
Call docstring:
    Call self as a function.


    Provide detailed information about an object.

%pinfo is a synonym for object? or ?object, which prints out detailed information about an object. This is an incredibly useful feature that lets you examine objects, including magic commands. We can get information about %pinfo itself, inception-style:

In [1]: %pinfo?
Provide detailed information about an object.

'%pinfo object' is just a synonym for object? or ?object.
File:      ~/.virtualenvs/ipython-book/lib/python3.9/site-packages/IPython/core/magics/namespace.py

Off the top of your head, do you know all of the parameters for timedelta? If not, this is a great way to show them along with some other helpful information:

In [2]: from datetime import timedelta

In [3]: timedelta?
Init signature: timedelta(self, /, *args, **kwargs)
Difference between two datetime values.

timedelta(days=0, seconds=0, microseconds=0, milliseconds=0, minutes=0, hours=0, weeks=0)

All arguments are optional and default to 0.
Arguments may be integers or floats, and may be positive or negative.
File:           ~/.pyenv/versions/3.9.0/lib/python3.9/datetime.py
Type:           type


    Provide extra detailed information about an object.

%pinfo2 is %pinfo taken one step further, and diving into the source code. Also similarly, %pinfo2 is a synonym for object?? or ??object. Again, we examine the source code that actually makes %pinfo2 tick:

In [1]: pinfo2??
    def pinfo2(self, parameter_s='', namespaces=None):
        """Provide extra detailed information about an object.

        '%pinfo2 object' is just a synonym for object?? or ??object."""
        self.shell._inspect('pinfo', parameter_s, detail_level=1,
File:   ~/.virtualenvs/ipython-book/lib/python3.9/site-packages/IPython/core/magics/namespace.py

If you wondered what happens when you base64 encode a file, you can see for yourself:

In [2]: import base64

In [3]: base64.encode??
Signature: base64.encode(input, output)
def encode(input, output):
    """Encode a file; input and output are binary files."""
    while True:
        s = input.read(MAXBINSIZE)
        if not s:
        while len(s) < MAXBINSIZE:
            ns = input.read(MAXBINSIZE-len(s))
            if not ns:
            s += ns
        line = binascii.b2a_base64(s)
File:      ~/.pyenv/versions/3.9.0/lib/python3.9/base64.py
Type:      function


    Toggle pretty printing on/off.

Pretty printing is on by default, but you can toggle it off and on with %pprint:

In [1]: s = {
     ...:     'a': [1,2,3,4,5,6,7,8,9,10],
     ...:     'b': {1:2, 2:3, 3:4, 4:5, 5:6, 6:7, 7:8, 8:9, 9:10},
     ...:     'c': (1,2,3,4,5,6,7,8,9,10)
     ...: }

In [2]: %pprint
Pretty printing has been turned OFF

In [3]: s
Out[3]: {'a': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 'b': {1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10}, 'c': (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)}

In [4]: %pprint
Pretty printing has been turned ON

In [5]: s
{'a': [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
 'b': {1: 2, 2: 3, 3: 4, 4: 5, 5: 6, 6: 7, 7: 8, 8: 9, 9: 10},
 'c': (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)}


    Search for object in namespaces by wildcard.

%psearch lets you search for objects in namespaces, both built-in objects like dict, as well as any user-created objects in the session.

? can be used as a synonym at the beginning or end for %psearch, if used with * as a wildcard. For example:

In [1]: a*?

You can pass in -i to make it a case-insensitive search:

In [2]: %psearch -i a*

To list all available object types for object matching, pass in -l:

In [3]: %psearch -l


    Show a syntax-highlighted file through a pager.

%pycat is very similar to the cat utility, which will read a file and write it to standard output, but additionally assumes the file is written in Python, and will show it with syntax highlighting. The command can take a local filename, a URL, a %history range, or a %macro.

%pycat my_file.py
%pycat https://raw.githubusercontent.com/ehamiter/pindead/master/pindead.py
%pycat 16-23
%pycat my_macro


    Show a quick reference sheet

%quickref shows the IPython quick reference card in a pager. This has some concise examples and shows a brief summary of all of the available magic commands.


    Repeat a command, or get command to input line for editing.

%recall (along with its alias %rep) repeats a command, and places the resulting output into a new line input. This allows you to create elaborate command lines without relying on copying and pasting.

In [1]: grocery_list = ['apples', 'bananas', 'soup', 'ice cream']

In [2]: ", ".join(grocery_list)
Out[2]: 'apples, bananas, soup, ice cream'

In [3]: %recall

In [4]: apples, bananas, soup, ice cream  # <= The cursor will be waiting here

You can also place lines from history (find out by using %history -n) on the next input prompt:

In [5]: a = 'foo'

In [6]: b = 'bar'

In [7]: c = a + ' ' + b

In [8]: c
Out[8]: 'foo bar'

In [9]: %recall 7

In [10]: c = a + ' ' + b  # <= The cursor will be waiting here


    Re-run previous input

You can repeat the last line by passing %rerun with no arguments, or pass in a line or line range from history.

In [1]: class Person:
    ...:     def __init__(self, name, age, email):
    ...:         self.name = name
    ...:         self.age = age
    ...:         self.email = email

In [2]: p1 = Person('Zoe', 45, 'zoe@anemailaddress.com')

In [3]: p1.age = 57

In [4]: p1.age
Out[4]: 57

In [5]: rerun 2
=== Executing: ===
p1 = Person('Zoe', 45, 'zoe@anemailaddress.com')
=== Output: ===

In [6]: p1.age
Out[6]: 45


    Resets the namespace by removing all names defined by the user, if
    called without arguments, or by removing some types of objects, such
    as everything currently in IPython's In[] and Out[] containers.

You can %reset all assigned variables in your session without confirmation by passing in the -f parameter:

%reset -f

Keep in mind this will also delete your %history. To preserve your history, you can pass in -s for a “soft” reset:

%reset -s

You can also reset just the input or output history or directory history:

%reset in
%reset out
%reset dhist


    Save a set of lines or a macro to a given filename.

After you have tested and tweaked a few lines in the shell, and would benefit from having the code around permananetly, you can %save a set of lines or a macro to a filename.

The default syntax is %save filename [lines]:

In [1]: def ends_in_za(word):
   ...:     if word.endswith('za'):
   ...:         print('It ends in za!')
   ...:     else:
   ...:         print('It does not end in za.')

In [2]: ends_in_za('pizza')
It ends in za!

In [3]: ends_in_za('asparagus')
It does not end in za.

In [4]: %save ends_in_za 1
The following commands were written to file `ends_in_za.py`:
def ends_in_za(word):
    if word.endswith('za'):
        print('It ends in za!')
        print('It does not end in za.')

There are a few options you can pass in directly after %save:

-r: use 'raw' input.  By default, the 'processed' history is used,
so that magics are loaded in their transformed version to valid
Python.  If this option is given, the raw input as typed as the
command line is used instead.

-f: force overwrite.  If file exists, %save will prompt for overwrite
unless -f is given.

-a: append to the file instead of overwriting it.


    Run a cell via a shell command

    The `%%script` line is like the #! line of script,
    specifying a program (bash, perl, ruby, etc.) with which to run.

    The rest of the cell is run by that program.

%%script is a cell magic that can be used to run scripts other than Python in your shell, like Bash, Perl, Ruby, or different versions of Python.

Each language has a shortcut, so %%ruby is the equivalent of %%script ruby, %%bash is the equivalent of %%script bash, etc.

In [1]: %%script bash
    ...: for i in 1 2 3; do
    ...:   echo $i
    ...: done
In [2]: %%ruby
    ...: things = %w( granite snails calcium pie )
    ...: puts things
In [3]: %%perl
    ...: not exp log srand xor s qq qx xor
    ...: s x x length uc ord and print chr
    ...: ord for qw q join use sub tied qx
    ...: xor eval xor print qq q q xor int
    ...: eval lc q m cos and print chr ord
    ...: for qw y abs ne open tied hex exp
    ...: ref y m xor scalar srand print qq
    ...: q q xor int eval lc qq y sqrt cos
    ...: and print chr ord for qw x printf
    ...: each return local x y or print qq
    ...: s s and eval q s undef or oct xor
    ...: time xor ref print chr int ord lc
    ...: foreach qw y hex alarm chdir kill
    ...: exec return y s gt sin sort split
just another perl hacker


    Lightweight persistence for python variables.

%store allows you to save a variable and access it after exiting a session. To save a variable, you simply pass it as the sole argument:

In [1]: my_name = 'Eric'

In [2]: %store my_name
Stored 'my_name' (str)

You can then exit the session, enter a new one, and recall it with the -r parameter:

In [3]: exit
ipython --profile=zagnut
In [1]: my_name
Out[1]: NameError: name 'my_name' is not defined

In [2]: %store -r

In [3]: my_name
Out[3]: 'Eric'

You can edit your IPython configuration to always autoload any stored variables.

Additional options

Show a list of all variables and their current values:


Store the current value of the variables eggs and motorcycles:

%store eggs motorcycles

Remove the variable eggs and its value from storage:

%store -d eggs

Remove all variables from storage:

%store -z

It should be noted that if you change the value of a variable, you need to %store it again if you want to persist the new value.


    Shell execute - run shell command and capture output (!! is short-hand).

%system has two aliases: %sx and !!.

To run a system command in IPython, like ls, you can put a single leading ! in front of it, e.g.

In [1]: !ls
LICENSE     README.md   book        book.toml   deploy.sh   src

Two leading !! is the short-hand for %system or %sx. The difference between using single or double exclamation points is that !! returns the results in a list that is split on \n, and since it is returned, it will be stored in the output history.

In [2]: !!ls
Out[2]: ['LICENSE', 'README.md', 'book', 'book.toml', 'deploy.sh', 'src']


    Print the last traceback.

%tb prints the last traceback. You can also pass in exception reporting modes (plain, context, verbose, minimal) to get more or less information (normally set with %xmode):

In [1]: 5 // 0
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-7-e6530c2158eb> in <module>
----> 1 5 // 0

ZeroDivisionError: integer division or modulo by zero

In [2]: %tb
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-7-e6530c2158eb> in <module>
----> 1 5 // 0

ZeroDivisionError: integer division or modulo by zero

In [3]: %tb plain
Traceback (most recent call last):
  File "<ipython-input-23-e6530c2158eb>", line 1, in <module>
    5 // 0
ZeroDivisionError: integer division or modulo by zero

In [4]: %tb minimal
ZeroDivisionError: integer division or modulo by zero


    Time execution of a Python statement or expression

%timeit is a commonly used magic command used for gauging the efficiency and speed of a function. Suppose we have two methods that return the same result, but we’re not exactly sure which one is more efficient (which is especially helpful if you’re not super familiar with Big O notation).

In [1]: def square(x):
   ...:     return pow(x, 2)

In [2]: square(2)
Out[2]: 4

In [3]: def square_alternative(x):
   ...:     return x * x

In [4]: square_alternative(2)
Out[4]: 4

In [5]: %timeit square(2)
479 ns ± 15.3 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)

In [6]: %timeit square_alternative(2)
130 ns ± 0.217 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

In this example we can see that the square_alternative() is much faster than the square() function that uses Python’s builtin pow() function.

We can also use cell magic to only time certain aspects of a function if it requires some initial setup. Suppose we want to run the square_alternative function on a number that will be calculated, but we don’t want to include the initial calculation of x. We can do this using two % symbols, so it only times the last line:

In [7]: import math

In [8]: %%timeit x = math.pi * math.tau
   ...: square_alternative(x)
132 ns ± 1.54 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)


    Print all interactive variables, with some minimal formatting.

%who is a nice way of looking at all of the variables you have created or assigned:

In [1]: class Automobile:
   ...:     def __init__(self, name, color, doors):
   ...:         self.name = name
   ...:         self.color = color
   ...:         self.doors = doors

In [2]: a = Automobile('Family Truckster', 'green', 4)

In [3]: s = 'this is some string'

In [4]: i = 54447877

In [5]: f = 45.99

In [6]: d = {'a': 'dict'}

In [7]: t = ('a', 'tuple')

In [8]: %who
Automobile   a   d   f   i   s   t

You can also filter by types, e.g. str, int, et cetera:

In [9]: %who str

To get a more detailed view of assigned variables, you can use %whos.


    Like %who, but gives some extra information about each variable.
In [1]: class Automobile:
   ...:     def __init__(self, name, color, doors):
   ...:         self.name = name
   ...:         self.color = color
   ...:         self.doors = doors

In [2]: a = Automobile('Family Truckster', 'green', 4)

In [3]: s = 'this is some string'

In [4]: i = 54447877

In [5]: f = 45.99

In [6]: d = {'a': 'dict'}

In [7]: t = ('a', 'tuple')

In [8]: %whos
Variable   Type       Data/Info
Automobile type       <class '__main__.Automobile'>
s          str        this is some string
i          int        54447877
f          float      45.99
d          dict       n=1
t          tuple      n=2
a          Automobile <__main__.Automobile object at 0x104a0bd30>

Like %who, you can filter by type:

In [9]: %whos dict
Variable   Type    Data/Info
d          dict    n=1


    Delete a variable, trying to clear it from anywhere that
    IPython's machinery has references to it. By default, this uses
    the identity of the named object in the user namespace to remove
    references held under other names. The object is also removed
    from the output history.
In [1]: animal = 'porcupine'

In [2]: animal
Out[2]: 'porcupine'

In [3]: %xdel animal

In [4]: animal
NameError: name 'animal' is not defined


    Switch modes for the exception handlers.

%xmode toggles between different modes of exception handling (plain, context, verbose, minimal). A mode can also be passed in directly as a parameter.

In [1]: bologna
NameError: name 'bologna' is not defined

In [2]: %xmode
Exception reporting mode: Plain

In [3]: bologna
Traceback (most recent call last):
  File "<ipython-input-38-5de53f9f76d4>", line 1, in <module>
NameError: name 'bologna' is not defined

In [4]: %xmode verbose
Exception reporting mode: Verbose

In [5]: bologna
NameError                                 Traceback (most recent call last)
<ipython-input-40-5de53f9f76d4> in <module>
----> 1 bologna
        global bologna = undefined

NameError: name 'bologna' is not defined

Custom magic commands

Along with the standard magic commands IPython provides, you can create custom magic commands that can be useful. Some good candidates would be to simplify tasks that you normally do but they take significant time to set up, initializing an object or objects for extensive testing, or maintenance routines that you find yourself doing over and over.

Just like we used cell and line magic, these two types exist for creating your own magic commands. For most of my use cases, line magic suffices, because I either don’t need an argument, or I can use a singular one-- I haven’t come across a case where it would benefit me to use the multiple lines available for cell magic, but it is an option if you so choose.

To use custom magic, create a Python file (I name mine custom_magic.py but the name can be anything you like) and place it in your profile’s startup directory.

When working on a local machine, it makes things easier if all users have the same password, which may not always be the case, especially right after a database refresh. I typically use something trivial because locally, security is not an issue, so I’d like to get around the sometimes stringent requirements that a user’s password must abide by. We can invoke this password normalizer using a line magic decorator:

# /Users/eric/.ipython/profile_zagnut/startup/custom_magic.py
from IPython.core.magic import register_line_magic

def reset_passwords(line):
    new_password = line or 'foobar'
    all_users = User.objects.all()
    first_user = all_users.first()
    hashed_password = first_user.password
    num_users = all_users.update(password=hashed_password)
    print(f'{num_users} passwords were changed to "{new_password}"')

This can be executed in the shell by simply running %reset_passwords. If you want to use something besides the given default of foobar, just pass it in:

In [1]: %reset_passwords apples
15 passwords were changed to "apples"

Another use case that you may find handy is generating UUIDs. I had a task where I needed to be able to generate one or more on the fly, and having a command that can do so is quite useful:

# /Users/eric/.ipython/profile_zagnut/startup/custom_magic.py
import uuid

def generate_uuid(line):
    def gen(n=1):
        for _ in range(n):
    if line:
        except ValueError:
            print('You must pass in an integer.')

Again, you can pass %generate_uuid by itself or with an argument:

In [1]: %generate_uuid

In [2]: %generate_uuid 4

In [3]: %generate_uuid abc
You must pass in an integer.


The body text of IPython for Web Devs is set in Gentium Book Basic, which was designed by Victor Gaultney. The Gentium Book Basic font family is based on the original Gentium design, but with additional weights. The family comes with a complete regular, bold, italic and bold italic set of fonts.

The side chapter text is set in Open Sans, a humanist sans serif typeface which was designed by Steve Matteson. Open Sans was designed with an upright stress, open forms and a neutral, yet friendly appearance. It was optimized for print, web, and mobile interfaces, and has excellent legibility characteristics in its letterforms.

The monospaced font used for code samples is Edlo, which I created by modifying a version of Stephen G. Hartke’s Aurulent Sans, which I thought was beautiful, but hazardous for programming because the similarities between zeroes and ohs and ones and els were too close for comfort.

The book cover was illustrated by lutfihakim394.

The favicon snake graphic was created by Bakunetsu Kaito from the Noun Project.

This book was generated by using mdBook, which is a free, open source command line tool and Rust crate to create books using Markdown (as by the CommonMark specification) files. It’s very similar to Gitbook but written in Rust.