In this Pydon't you'll learn how to make the best use possible of the Python REPL.
(If you are new here and have no idea what a Pydon't is, you may want to read the Pydon't Manifesto.)
The REPL is an amazing tool that every Python programmer should really know and appreciate! Not only that, but you stand to gain a lot if you get used to using it and if you learn to make the most out of it 😉
In this Pydon't, you will:
You can now get your free copy of the ebook “Pydon'ts – Write beautiful Python code” on Gumroad to help support the series of “Pydon't” articles 💪.
Read. Evaluate. Print. Loop.
That's what “REPL” stands for, and it is often referred to as “read-eval-print-loop”. The REPL is the program that takes your input code (i.e., reads your code), evaluates it, prints the result, and then repeats (i.e., loops).
The REPL, sometimes also referred to as the “interactive session”,
or the “interpreter session”,
is what you get when you open your computer's command line and type
That should result in something like the following being printed:
Python 3.9.2 (tags/v3.9.2:1a79785, Feb 19 2021, 13:44:55) [MSC v.1928 64 bit (AMD64)] on win32 Type "help", "copyright", "credits" or "license" for more information. >>>
Of course, the exact things that are printed (especially the first line) are likely to differ from what I show here, but it's still the REPL.
(By the way, if you ever need to leave the REPL, just call the
The REPL is, hands-down, one of your best friends when you are writing Python code. Having a REPL to play around with just makes it much easier to learn the language.
Can't remember the argument order to a built-in function? Just fire up the REPL.
Need to do a quick computation that is just a bit too much for the conventional desktop calculator? Just fire up the REPL.
Can't remember how to spell that module you want to import? Just fire up the REPL.
You get the idea.
I cannot stress this enough. Get used to the REPL. Play with it. Write code in it. As soon as you become familiar with it, you'll love it and thank me for that.
The REPL generally contains a
>>> in the beginning of the line, to the left of your cursor.
You can type code in front of that prompt and press Enter.
When you press Enter, the code is evaluated and you are presented with the result:
>>> 3 + 3 6
The REPL also accepts code that spans multiple lines, like
for loops, function definitions with
In order to do those, just start typing your Python code regularly:
>>> if True:
When you press Enter after the colon,
Python realises the body of the
if statement is missing,
and thus starts a new line containing a
... on the left.
... tells you that this is the continuation of what you started above.
In order to tell Python you are done with the multiline code blocks
is by pressing Enter on an empty line with the continuation prompt
>>> if True: ... print("Hello, world!") ... Hello, world! >>>
Pasting into the REPL should work without any problem.
For example, the function below returns the double of the input. Try copying it into your REPL and then using it.
def double(x): return 2 * x
However, if you try to copy and paste a multiline block that contains empty lines in the middle, then the REPL will break your definition.
For example, if you try pasting the following, you get an error:
def double(x): return 2 * x
Copying the code above and pasting it into the session, you will end up with a session log like this:
>>> def double(x): ... File "<stdin>", line 2 ^ IndentationError: expected an indented block >>> return 2 * x File "<stdin>", line 1 return 2 * x IndentationError: unexpected indent
This happens because the REPL finds a blank line and thinks we tried to conclude the definition of the function.
One last thing you should know about the REPL is that it implicitly “prints” the results of the expressions you type.
I wrote “prints” in quotes because the REPL doesn't really print the result,
it just shows its representation.
The representation of an object is what you get when you call
repr on the object.
If you explicitly
str on it.
I wrote a very detailed Pydon't explaining the differences between the two, so let me just show you how things are different:
# Define a string. >>> s = "Hello\nworld!" # Print its `str` and `repr` values: >>> print(str(s)) Hello world! >>> print(repr(s)) 'Hello\nworld!' # Print the string explicitly and evaluate it in the REPL. >>> print(s) Hello world! >>> s 'Hello\nworld!'
As you can see, printing
s or just typing it in the REPL
gives two different results.
Just be mindful of that.
In particular, if the expression you wrote evaluates to
then nothing gets printed.
The easiest way to see this is if you just type
None in the REPL.
Nothing gets displayed; contrast that with what happens if you just type
>>> None >>> 3 3
If you call a function that doesn't have an explicit return value,
or that returns
then those functions will not show anything in the REPL:
>>> def explicit_None_return(): ... # Return None explicitly. ... return None ... >>> explicit_None_return() # <- nothing gets displayed. >>> def implicit_None_return(): ... # Ending without a `return` returns `None` implicitly. ... pass ... >>> implicit_None_return() # <- nothing gets displayed.
Sometimes it is useful to use the REPL to quickly import a function you just defined. Then you test the function out and then proceed to changing it in the source file. Then you'll want to import the function again and test it again, except that won't work.
You need to understand how the REPL handles imports, because you can't import repeatedly to “update” what's in the session.
To show you this, go ahead and create a file
# In `hello.py`: print("Being imported.")
Now open the REPL:
>>> import hello Being imported!
Now try modifying the string inside the
>>> import hello Being imported! # Modify the file, then import again: >>> import hello >>>
Nothing happens! That's because Python already went through your file and knows what's in there, so it doesn't need to parse and run the file again. It can just give you the functions/variables you need.
In short, if you modify variables, functions, code; and you need those changes to be reflected in the REPL,
then you need to leave the REPL with
exit(), start it again, and import things again.
That's why some of the tips for quick hacks I'll share below are so helpful.
Edit: Another alternative – brought to my attention by a kind reader –
is to use
importlib.reload(module) in Python 3.4+.
In our example, you could use
>>> import hello Being imported >>> import importlib # Use `imp` from Python 3.0 to Python 3.3 >>> importlib.reload(hello) Being imported <module 'hello' from 'C:\\tmp\\hello.py'>
We get that final line because
importlib.reload returns the module
You can take a look at this StackOverflow question and answers to learn a bit more about this approach.
Be mindful that it may not work as you expect when you have multiple imports. Exiting the REPL and opening it again may be the cleanest way to reload your imports in those situations.
I'll be honest with you, I'm not entirely sure if what I'm about to describe is a feature of the Python REPL or of all the command lines I have worked with in my entire life, but here it goes:
You can use the up and down arrow keys to go over the history of expressions you already entered. That's pretty standard.
What's super cool is that the REPL remembers this history of expressions, even if you exit the REPL, as long as you don't close the terminal.
If you read my Pydon't about the usages of underscore
you might know this already,
but you can use the underscore
_ to retrieve the result of the last expression
if you want to use it and forgot to assign.
Here is a silly example:
>>> 3 + 6 9 >>> _ + 10 19
This might come in handy when you call a function or run some code that takes a long time. For example, downloading something from the Internet.
It can also be helpful if you just ran an expression with side-effects and you don't want to run that again because you don't want to trigger the side-effects twice. For example, if you just made a call to an API.
_ is a valid variable name in and out of itself,
so you can still use it as a variable name.
If you do, however, then
_ will stop reflecting the result of the last expression:
>>> _ = 0 >>> _ 0 >>> 3 + 9 12 >>> _ 0 # <- it still evaluates to 0!
If you want to get back the magical behaviour of
_ holding the result of the last expression,
Another great feature that is often underappreciated is the built-in help system.
If you need to take a look at a quick reference for a built-in function,
for example, because you forgot what the arguments are, just use
>>> help(sum) Help on built-in function sum in module builtins: sum(iterable, /, start=0) Return the sum of a 'start' value (default: 0) plus an iterable of numbers When the iterable is empty, return the start value. This function is intended specifically for use with numeric values and may reject non-numeric types. >>>
What is great about this
help built-in is that it can even provide help
about your own code, provided you document it well enough.
Here is the result of calling
help on a function defined by you:
>>> def my_function(a, b=3, c=4): ... return a + b + c ... >>> help(my_function) Help on function my_function in module __main__: my_function(a, b=3, c=4) >>>
You can see that
help tells you the module where your function was defined
and it also provides you with the signature of the function,
default values and all!
To get more information from
help you need to document your function with a docstring:
>>> def my_function(a, b=3, c=4): ... """Return the sum of the three arguments.""" ... return a + b + c ... >>> help(my_function) Help on function my_function in module __main__: my_function(a, b=3, c=4) Return the sum of the three arguments. >>>
Now you can see that the
help function also gives you the information
stored in the docstring.
I'll be writing a Pydon't about docstrings soon. Be sure to subscribe to my newsletter so you don't miss it!
The Python REPL is amazing when you need to flesh an idea out, as it allows you to quickly test some code, tweak it, and iterate over that repeatedly with instant feedback.
It goes without saying, but the REPL is not a replacement for your IDE! However, sometimes it helps to know about a couple of little tricks that you can employ to help you make the most out of your REPL.
Python supports semicolons to separate statements:
>>> a = 3; b = a + 56; print(a * b) 177
However, this feature is something that often does not belong in your code, so refrain from using it.
Despite being generally inadequate for production code, the semicolons are your best friends when in the REPL. I'll explain it to you, and you'll agree.
In the command line you can usually use the up and down arrows to cycle through the most recently typed commands. You can do that in the REPL as well. Just try evaluating a random expression, then press the up arrow and Enter again. That should run the exact same expression again.
Sometimes you will be working in the REPL testing out a solution or algorithm incrementally. However, if you make a mistake, you must reset everything.
At this point, you just press the arrows up and down, furiously trying to figure out all the code you have ran already, trying to remember which were the correct expressions and which ones were wrong...
Semicolons can prevent that! You can use semicolons to keep track of your whole “progress” as you go: whenever you figure out the next step, you can use the arrows to go up to the point where you last “saved your progress” and then you can add the correct step at the end of your sequence of statements.
Here is an example of an interactive REPL session of me trying to order a list of names according to a list of ages.
Instead of two separate assignments, I put them on the same line with
>>> names = ["John", "Anna", "Bill"]; ages = [20, 40, 30]
I could have written
>>> names, ages = ["John", "Anna", "Bill"], [20, 40, 30]
but using the semicolon expresses the intent of having the two assignments in separate lines when it comes time to write the real code down.
Then, I will try to see how to put the ages and names together in pairs:
>>> [(age, name) for name, age in zip(names, ages)] [(20, 'John'), (40, 'Anna'), (30, 'Bill')]
However, at this point I realise I'm being redundant and I can just use
if I reverse the order of the arguments:
>>> list(zip(ages, names)) [(20, 'John'), (40, 'Anna'), (30, 'Bill')]
Now that I'm happy with how I've paired names and ages together, I use the arrow keys to go back to the line with the assignment. Then, I use a semicolon to add the new piece of code I worked out:
>>> names = ["John", "Anna", "Bill"]; ages = [20, 40, 30]; info_pairs = zip(ages, names)
zip is an amazing tool in Python and is one of my favourite
You can learn how to wield its power with this Pydon't.
Now I can move on to the next step, knowing that a mistake now won't be costly: I can reset everything by going up to the line with all the intermediate steps and run that single line.
When you want to define a simple multiline block, you can often get away with inlining what comes after the colon.
For example, instead of
>>> for i in range(3): ... print(i) ... 0 1 2
you can write
>>> for i in range(3): print(i) ... 0 1 2
While this is style that is not recommended for production code, it makes it more convenient to go up and down the REPL history.
If you really want to push the boundaries, you can even combine this with semicolons:
>>> i = 1 >>> while i < 30: print(i); i *= 2 ... 1 2 4 8 16
If you are writing some code and want to take it for a spin – just to make sure it makes sense – fire up the REPL, import the code, and play with it! That's the magic of the REPL.
Be sure to do any setup for the “tests” in a single line separated with semicolons,
together with the import statements.
That way, when you tweak the code you just wrote, you can type
exit() to leave the REPL,
enter it again, and then with a couple of up-arrow presses you get your setup code intact
and are ready to play with it again.
I try to stick to vanilla Python as much as possible when writing these Pydon'ts, for one simple reason: the world of vanilla Python is huge and, for most developers, has lots of untapped potential.
However, I believe I would be doing you a disservice if I didn't mention two tools that can really improve your experience in/with the REPL.
“Rich is a Python library for rich text and beautiful formatting in the terminal.”
Rich is an open source library that I absolutely love. You can read the documentation and the examples to get up to speed with Rich's capabilities, but I want to focus on a very specific one, in particular:
>>> from rich import pretty >>> pretty.install()
Running this in your REPL will change your life. With these two lines, Rich will pretty-print your variables and even include highlighting.
IPython is a command shell for interactive computing in multiple programming languages, originally developed for the Python programming language. IPython offers introspection, rich media, shell syntax, tab completion, and history, among other features.
In short, it is a Python REPL with more bells and whistles.
It is beyond the scope of this Pydon't to tell you all about IPython, but it is something I had to mention (even though I personally don't use it).
Here's the main takeaway of this Pydon't, for you, on a silver platter:
“Get comfortable with using the REPL because that will make you a more efficient Python programmer.”
This Pydon't showed you that:
repr), not its string value (
Noneresults don't get displayed implicitly;
helpbuilt-in can give you basic documentation about the functions, and other objects, you have “lying around”; it even works on user-defined objects;
helpwhen used on custom objects;
If you liked this Pydon't be sure to leave a reaction below and share this with your friends and fellow Pythonistas. Also, subscribe to the newsletter so you don't miss a single Pydon't!
I hope you learned something new! If you did, consider following the footsteps of the readers who bought me a slice of pizza 🍕. Your contribution boosts my confidence and helps me produce this content for you.