Welcome to Day 2 of the Learn IPython in 10 Days mini-course! Today you'll learn about some of IPython's main features, such as syntax highlighting, tab completion, object details, and multiline editing.

Learning Outcomes

By the end of today, you'll know:

  • What syntax highlighting and bracket matching are in IPython
  • How to create an IPython profile and change the color scheme
  • How to use tab completions in IPython
  • How to view details about a code object
  • What an IPython code block is
  • How to edit multiple lines in IPython


Before you start today's lesson, 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 1 lesson:

Installing IPython | Learn IPython in 10 Days
Learn how to install IPython using the pipx tool, open IPython from your terminal, and access IPython’s built-in help menu.

Syntax Highlighting

One of the first things you'll notice about IPython is that, unlike the standard Python REPL which is black and white by default, you get syntax highlighting out-of-the-box:

By default, keywords like def and built-in function names like print() are displayed in green, function names in a function definition, like greet() in the example above, are displayed in blue, and strings are displayed in yellow.

IPython also matches brackets and parentheses by highlighting matched pairs when closing brackets:

Bracket matching makes it easy to see at a glance which bracket or parenthesis is being closed and is especially helpful with nested function calls or nested lists and tuples.

Syntax highlighting is one of those features that feels like a breath of fresh air coming from the standard Python REPL. Depending on your terminal set-up, however, the colors may not be ideal. For example, I find the blue function names difficult to read against a black terminal background.

Fortunately, you can change the default color scheme.

IPython Profiles and Configuration

To change IPython's color scheme, the first thing you need to do is create a new IPython profile. Exit IPython and return to your shell, then execute the following command:

$ ipython profile create

You'll see a message telling you that a default configuration file has been created, along with the location of that configuration file:

[ProfileCreate] Generating default config file: PosixPath('/Users/damos/.ipython/profile_default/ipython_config.py')

Take note of the configuration file's location and open it in your favorite text editor. For example, here's how I open my configuration file from the terminal in Visual Studio Code:

$ code ~/.ipython/profile_default/ipython_config.py

This launches VS Code with the configuration file ready to edit:

There is a lot to take in here, and you'll learn more about configuring IPython in a future lesson. If your editor supports it, press Ctrl+F (Cmd+F on macOS) and search for c.InteractiveShell.colors to find the line for changing the color scheme:

By default, c.InteractiveShell.colors is set to 'Neutral'. But there are three other options:

  1. 'NoColor' removes syntax highlight. You probably don't want this.
  2. 'Linux' works best on terminals with dark backgrounds.
  3. 'LightBG' works best on terminals with light backgrounds.

To change the color scheme, uncomment the line containing c.InteractiveShell.colors and then change the value to your desired setting.

I prefer 'Linux', so I'm going to change my color scheme to that:

Save the configuration file and close your text editor. Then launch IPython again and check out your new color scheme:

If you want to go back to the default color scheme, open your configuration file again and change c.InteractiveShell.colors back to 'Neutral'.

Tab Completion

The standard Python shell has minimal tab completion. For example, if you create a variable called name on one line, and then type na<TAB> on another line, the Python shell will try and complete the variable name for you. But IPython offers so much more.

To see IPython tab completions in action, type the letter g into the prompt and press Tab. Assuming the function greet() from the previous example is in your namespace, you'll see that option, as well as several built-ins, displayed in an overlay:

Use the Down arrow key to enter the overlay and then use the arrow keys to select the name you want to use:

Notice that function signatures are shown below the overlay whenever a function is in focus. For instance, with greet() selected, the signature function(name) is shown below the overlay. For an even better example of this, select getattr() to see what a more complex signature looks like:

If the function was defined with type hints, these also show up in the overlay! To select a name to use, use the arrow keys to bring the name into focus. Then press Enter.

If you type a few characters of a name into the prompt, and there is only one completion available matching the characters you typed in, the IPython will not show an overlay and will just complete the name for you.

IPython can even infer the types of items in a list, tuple, or dictionary and offer helpful completions based on the type. For instance, create a list with various types of objects in it, like a number, string, and another list:

In [3]: mylist = [3.14, "pi", [3, 1, 4]]

In the next prompt, type mylist[0].<TAB> and you'll get an overlay with available methods and attributes for the floating-point number 3.14:

Did you know numbers in Python have methods? There's so much more to numbers than meets the eye! Learn more (potentially) surprising facts about numbers in my article 3 Things You Might Not Know About Numbers in Python.

You can see all the methods and attributes on the string "pi" by typing mylist[1].<TAB>:

The same goes for lists, like the nested list [3, 1, 4] inside of mylist:

Tab completions are a small, but useful feature, especially if you can't remember the exact name for a method that you want to call on an object!

View Object Details

On Day 1 you learned how to access IPython's help page by typing ? into a prompt and pressing Enter. The question mark is also used to inspect objects and get help with commands.

For instance, type print? into a prompt and press Enter. IPython shows you the print() function's docstring and tells you what type of object it is:

? works with any code object available in your current namespace, including modules, classes, and variables. If the name doesn't exist — such as trying to get help for the math module before importing it — IPython will warn you that the object can't be found:

In [5]: math?
Object `math` not found.

You can get more details about an object by using two question marks instead of one. This depends on what information is available, however. For example, typing print?? and pressing Enter doesn't display any additional information:

For some objects, such as the Path class from the pathlib module, inspecting them with ?? shows you a ton of information, including the code used to define them. Import the pathlib module, then type pathlib.Path?? and press Enter:

In [7]: import pathlib
In [8]: pathlib.Path??

IPython displays a screen with all of the information about the Path class, and even highlights the syntax for its source code:

You can navigate the help page using PgUp, PgDown, and the arrow keys. To quit the help page and return to the REPL, press q.

? and ?? work with objects imported from anywhere, including third-party packages and your own source code files. It's a great way to get help on objects and, in my opinion, offers a significantly better experience than Python's built-in help() function.

Multiline Editing

One of the biggest upgrades the IPython offers over the standard Python shell, as far as basic features go, is multiline editing.

You probably noticed that IPython displays line numbers in the REPL prompt. Really these numbers refer to cells that can contain multiple lines of code, and you can edit each line of code in a cell.

To see this in action, write a function called absolute_value() that returns the absolute value of a number. (Yes, I know there is a built-in abs() function! Just roll with me for a minute here.) Type the following code into your prompt:

In [10]: def absolute_value(num):
    ...:     """Returns the absolute value of a number."""
    ...:     if num > 0:
    ...:         return num
    ...:     else:
    ...:         return -num

Look closely. Do you see a mistake?

What happens if you pass 0.0 to absolute_value()? It will return -0.0 since the case where num = 0 isn't handled explicitly but instead flows into the negative case:

In [10]: absolute_value(0.0)
Out[10]: -0.0

That's probably not what you want!

Did you know that negative zero was a thing? It's not just something peculiar about Python. It's part of the IEEE-754 floating-point specification and is usually used to indicate that small negative values got rounded to zero. The more you know!

You can fix this in IPython rather easily. Press the Up arrow twice to bring up the code for the absolute_value() function. Unlike the standard Python shell, the history isn't recalled line-by-line, but cell-by-cell!

Then you can use the up arrows to move your cursor to the line you want to edit and fix the issue:

Multiline editing is one of those features that you just can't live without once you have it at your disposal. If there's one feature of IPython that sells you on it, this might be it!

But, as you'll see in coming lessons, there are plenty of other features that will make switching from IPython back to the standard IPython REPL hard to do.

Day 2 Activities:

Continue to use IPython in your daily workflow. Keep recording things you like as well as any struggles you encounter.

In addition to that, here are some exercises to get some practice with the new features you learned today:

  1. Try out all of the color schemes in your profile configuration. Which one do you like the best?
  2. Practice using ? and ?? while coding. For what kind of objects does ?? give you more detail? (See the answer below!)
  3. What happens if you have a syntax error while typing out a multiline function definition? Practice fixing errors like that using multiline editing.

I hope you enjoyed today's lesson. See you tomorrow for Day 3 of Learn IPython in 10 Days.

Day 2 Answers:

What kind of objects does ?? show your more detail for? There are many, but you might notice that only object written in Python get their source code displayed with ??. For example, try importing the math module and inspecting the sqrt() function:

math.sqrt() is implemented in C, not Python, so you can't see its source code!

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!