IPython's magic function system exposes a rich set of commands that can be used to configure IPython, run and edit code, and inspect code objects. Magic functions, sometimes referred to as magic commands or magics, are one of IPython's defining features.

## Learning Outcomes

By the end of today, you'll know:

• What line magics are
• What cell magics are
• View the IPython quick reference card using the %quickref magic command
• How to explore code objects using the %pdef, %pdoc, %pfile magic commands
• How to view interactive variables with %who and %whos
• How to configure IPython using the %color and %configure magic commands
• How to install packages using the %pip magic command

## Pre-requisites

Before you start today's lessons, make sure you have a working Python installation on your computer (preferably Python 3.8 or greater). You should also have IPython installed and have worked through the Day 3 lesson:

## IPython Magic Commands

Magic commands are, in a lot of ways, the bread and butter of IPython. Without them, IPython is just a fancy Python REPL with colors and a few additional features like better tab completion and multiline editing.

There are two types of magic commands:

1. Line magics start with a % character and have a system command style syntax. They operate on a single line and arguments are passed to the command without any parentheses or quotes. Line magics can return values and can be used on the right-hand side of an assignment expression.
2. Cell magics start with %% and operate on an entire IPython cell.

This tutorial focuses exclusively on line magics.

In yesterday's lesson, you learned about magic commands like %cd and %ls for working with the system shell, but there are so many more at your fingertips. A full list of available magic commands can be found in the IPython docs.

Today, you'll learn about magic commands that can be used to explore code objects, configure the IPython REPL, and install packages with pip. Future lessons will introduce even more magic commands relevant to different topics, such as running, editing, timing, and profiling code.

At any time, you can use the %magic magic command to bring up the docs for the magic function system. Just type %magic into an input prompt and press Enter and you'll see the following screen:

Use the PgUp, PgDn, and arrow keys to navigate the help screen. When you're done, press q to return to the REPL.

## The IPython Quick Reference Card

IPython is a powerful Python REPL, and there's a lot of information to keep up with. Wouldn't it be great to have a cheat sheet available to you at any time? Fortunately, there is! And it's available directly within the REPL any time you need it.

Type %quickref into an input prompt and press enter to see the quick reference sheet:

As usual, use PgUp, PgDn, and the arrow keys to navigate the quick reference card. When you're done, press q to return to the REPL.

Thanks to IPython's automagic functionality, which you learned about on Day 3, you don't even need to type the % character. That is, the following command works just fine:

In [1]: quickref

This does depend on automagic functionality being enabled, so if you see an error when issuing the above command, you may need to enable automagics by running %automagic on first.

## Exploring Code Objects

On Day 2, you learned how to view information about code objects using ? and ??. For example, you can view information about the built-in print() function by typing print? and pressing Enter:

In [2]: print?
Docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Type:      builtin_function_or_method

IPython includes magic commands for viewing specific types of information about code objects. For instance, the %pdoc magic displays just the docstring for an object:

In [3]: %pdoc print
Class docstring:
print(value, ..., sep=' ', end='\n', file=sys.stdout, flush=False)

Prints the values to a stream, or to sys.stdout by default.
Optional keyword arguments:
file:  a file-like object (stream); defaults to the current sys.stdout.
sep:   string inserted between values, default a space.
end:   string appended after the last value, default a newline.
flush: whether to forcibly flush the stream.
Call docstring:
Call self as a function.

You can use %pdef to see the call signature of a function or other Python callable object:

In [4]: %pdef enumerate
Class constructor information:
enumerate(iterable, start=0)

Use %pfile to view the file that an object is defined in:

In [5]: import pathlib
In [6]: %pfile pathlib.Path

The file is opened up at the line where the object is defined and displayed full screen:

You can use PgUp, PgDn, and the arrow keys to navigate the file. You can't edit the file this way, but you can at least view the source, which is handy if you want to see how something works under the hood, or just need to remind yourself of how something is implemented.

If no file exists for the object, then IPython will tell you:

In [7]: %pfile zip
No file found for zip

Out of the three magic commands mentioned here, %pdoc and %pfile are perhaps the most useful. Most of the time, you'll probably just want to use ? to get more information about an object. Other times, it's nice to just view the docstring using %pdoc. And having quick access to the source code for an object with %pfile greatly reduces the number of times you need to switch apps or terminal windows.

## Viewing Interactive Variables

During interactive coding sessions, it's common for lots of names to end up in your namespace. All of these names can be difficult to keep track of, and accidentally overwriting one of them could break your entire workflow and require you to spend significant time recreating state.

1. %who can print all interactive variables for you, or only certain types of variables
2. %whos prints interactive variables and includes additional information such as the type of object assigned to that variable and its value.

For example, suppose you have a few variables assigned and have defined a function:

In [1]: name = "David"

In [2]: n1, n2 = 1, 2

In [3]: def greet(name):
...:     print(f"Hello, {name}")
...:

Running %who shows you all of the variables and names in your namespace:

In [4]: %who
greet	 n1	 n2	 name

You can show only functions by passing the word function to %who:

In [5]: %who function
greet

Using %whos will give you even more details about each variable:

In [6]: %whos
Variable   Type        Data/Info
--------------------------------
greet      function    <function greet at 0x1054b7370>
n1         int         1
n2         int         2
name       str         David

Like %who, you can also search for specific types of variables:

In [7]: %whos int
Variable   Type    Data/Info
----------------------------
n1         int     1
n2         int     2

%who and %whos are handy magics to have built into your muscle memory, so I suggest you spend some time practicing using them.

## Configuring IPython With Magic Commands

On Day 2, you learned how to open IPython's configuration file. Some of the configuration settings are available for editing from within the IPython REPL itself. So, if you ever need to change IPython's configuration in the middle of an interactive session, you might be able to do so without opening a text editor.

For instance, you can change the color scheme using the %colors magic command:

In [8]: %colors nocolor    # Change to black and white

In [9]: %colors linux      # Works on dark background

In [10]: %colors lightbg   # Works on light background

Changing the color scheme with %colors works only as long as the current REPL session or until you use %colors to change to a new color scheme. IPython's configuration file does not get changed, so the choice of color scheme does not persist between sessions.

Use the %config magic to expose parts of IPython's configuration system. Running %config without any arguments will show you what configuration classes are available:

In [11]: %config
Available objects for config:
AliasManager
DisplayFormatter
HistoryManager
IPCompleter
LoggingMagics
MagicsManager
OSMagics
PrefilterManager
ScriptMagics
StoreMagics
TerminalIPythonApp
TerminalInteractiveShell

To see all of the available options on a class, you can pass just the class name to %config:

In [12]: %config TerminalInteractiveShell
TerminalInteractiveShell(InteractiveShell) options
------------------------------------------------
TerminalInteractiveShell.ast_node_interactivity=<Enum>
'all', 'last', 'last_expr' or 'none', 'last_expr_or_assign' specifying which
nodes should be run interactively (displaying output from expressions).
Choices: any of ['all', 'last', 'last_expr', 'none', 'last_expr_or_assign']
Current: 'last_expr'
TerminalInteractiveShell.ast_transformers=<list-item-1>...
A list of ast.NodeTransformer subclass instances, which will be applied to
user input before code is run.
Current: []
TerminalInteractiveShell.auto_match=<Bool>
Automatically add/delete closing bracket or quote when opening bracket or
quote is entered/deleted. Brackets: (), [], {} Quotes: '', ""
Current: False
~ Output shortened ~

The output also shows you what the current values of the configuration settings are. For example, the TerminalInteractiveShell.auto_match setting is current;y set to False. That setting controls whether or not IPython automatically adds closing brackets or quotes when an opening bracket or quote is entered.

To set TerminalInteracticeShell.auto_match to True, pass the entire assignment expression to %config:

In [13]: %config TerminalInteractiveShell.auto_match = True

Typing out the long IPython configuration class names is clunky and error-prone. Fortunately, IPython's tab completion system works here:

Just like %colors doesn't persist color scheme changes between sessions, %config doesn't write any changes to the IPython configuration file. Any changes you make to the configuration will be reset the next time you close and open IPython again.

## Using pip Inside of IPython

One of the more useful magic commands is the %pip magic, which allows you to install packages with pip from right inside of the IPython REPL:

In [1]: %pip install requests
Collecting requests
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 63.1/63.1 KB 1.7 MB/s eta 0:00:00
Collecting idna<4,>=2.5
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 61.2/61.2 KB 2.0 MB/s eta 0:00:00
Collecting certifi>=2017.4.17
Using cached certifi-2021.10.8-py2.py3-none-any.whl (149 kB)
Collecting urllib3<1.27,>=1.21.1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 139.0/139.0 KB 4.2 MB/s eta 0:00:00
Collecting charset-normalizer~=2.0.0
Installing collected packages: certifi, urllib3, idna, charset-normalizer, requests
Successfully installed certifi-2021.10.8 charset-normalizer-2.0.12 idna-3.3 requests-2.27.1 urllib3-1.26.9
Note: you may need to restart the kernel to use updated packages.

In some cases, you'll need to restart IPython in order for the freshly installed package to work.

All of the pip commands that you know and love work inside of IPython. For instance, you can run %pip list to see the current packages installed in your Python environment:

In [2]: %pip list
Package            Version
------------------ ---------
appnope            0.1.3
asttokens          2.0.5
backcall           0.2.0
certifi            2021.10.8
charset-normalizer 2.0.12
decorator          5.1.1
executing          0.8.3
idna               3.3
ipython            8.2.0
jedi               0.18.1
matplotlib-inline  0.1.3
parso              0.8.3
pexpect            4.8.0
pickleshare        0.7.5
pip                22.0.4
prompt-toolkit     3.0.29
ptyprocess         0.7.0
pure-eval          0.2.2
Pygments           2.11.2
requests           2.27.1
setuptools         61.3.1
six                1.16.0
stack-data         0.2.0
traitlets          5.1.1
urllib3            1.26.9
wcwidth            0.2.5
wheel              0.37.1
Note: you may need to restart the kernel to use updated packages.

But which environment did requests get installed in? If you exit IPython and run pip list in your shell, you might see a different set of packages:

\$ pip list
Package    Version
---------- -------
pip        22.0.4
setuptools 58.1.0

Since we installed IPython using pipx on Day 1, the %pip command uses the isolated environment that pipx created for IPython instead of the global Python environment. This means that any package installed using %pip will be available from within IPython without polluting your global environment.

Of course, this behavior isn't always what you want. You may want to install something in your global environment. Or, perhaps more likely, you'll want to install a package in an active virtual environment.

In those cases, use !pip install to install the package. Rather than using the isolated environment created by pipx, packages will be installed in whatever the currently active Python environment is in your shell.

⚠️
In order to make sure the right pip is used, you may want to use the !python3 -m pip command instead. Brett Cannon's article Why You Should use python -m pip gives a great explanation for this pattern.

## Day 4 Activity

Continue to use IPython for all of your daily tasks. Practice using magic commands. Use the configuration magic commands to explore and play around with different configuration options.

Enjoying this course? Why not share it with a friend or colleague that you think will benefit from it? Just right-click on this link, copy the URL, and send it to them in an email!