Read first: one-page quick-start guide for teachers
Python Tutor is a free tool that visualizes what your code does step-by-step as it runs. Since I created it in 2010, over 25 million people in over 180 countries have used it to visualize over 500 million pieces of code, and it's used for teaching in over 10,000 schools, including MIT, Harvard, Princeton, UC Berkeley, Tsinghua, and the IITs.
This article shows what it can illustrate across the full range of Python courses, from a student's very first loop up through closures and generators.
If you think this tool may be helpful for your students, please share this direct link in relevant course materials, chat groups, mailing lists, discussion forums, or social media:
This article starts with first-semester topics and works its way up. If you teach beginners, the first half may be all you need – feel free to stop whenever it goes past your course's level. And if you're more experienced, check out the "More Advanced Python" section near the end to see concepts (closures, generators) that other tools usually can't draw. All examples below are interactive: drag the slider under each one to step forward and back through execution, and click "Edit Code" under any example to open it in the full editor, where you and your students can modify and re-run it.
When students learn their first loops, teachers often have them trace code by hand, keeping a little table of each variable's value at each step. Python Tutor works like a self-updating trace table:
At the current step (Step 10), we're partway through the loop: day is
2 and total is 50. Students can step forward and backward to see
every value this program ever computes. There's nothing to install or set up:
students go to the website, type code, and press Visualize. Or they can
click a
link you send to them.
The visualizer also supports programs that read keyboard input from the
user typing in a text box on the webpage. When execution reaches a
call to input(), the visualizer prompts for a value, and then
saves what the user types so that they can edit and re-run without retyping.
Here's a loop that reads three test scores and averages them:
The "User inputs" panel below the code lists all three values that the
user typed during this run. Here at Step 7 the first two are crossed
out in gray because the code has already consumed them.
Step backward and forward to watch each call to input()
cross off each value right when it gets read.
Each function call gets its own frame that holds its local variables:
At the current step, the frames for both checkout and add_tax are
on screen at once. Stepping through shows values flowing into
parameters and back out through return values (each function's return
value is displayed just before its frame disappears).
In the example below why does a print as [1, 2, 3, 4] when the code appended to b?
Because b = a doesn't copy anything. Both names now refer to the same
list, so the diagram shows two arrows pointing to one list. Note that
list(a) creates an actual copy, which appears as a second list in the
visualization.
This also happens when lists get passed to functions:
In the current step, replace_all has just reassigned its local name
lst to a brand-new list, and there are now two separate lists on the
heap: groceries still points at the original one (which add_item
successfully mutated earlier), while the new ['coffee'] list is about
to disappear when the function returns.
Here's an example of using a dict as a running counter:
Tuples, sets, and some other collections from the standard library also render in similar ways.
Python Tutor handles nested data structures by either using pointers or nesting, depending on what option you set.
Users can 'eyeball' what expressions like s['scores'][0] evaluate to
by simply following the right arrows.
There's also a "show list-of-lists as 2D array" checkbox below the code editor, which is useful for seeing nested loops and matrix data structures:
For teaching object-oriented programming, the visualizer draws classes, instances, and method calls:
Here's an example of inheritance and method overriding:
Class objects (not just instances) appear on the heap, with Dog
labeled as extending Animal. At the current step, the loop is calling
speak() on Rex, so self points at the Dog instance and calls
Dog's overriding method. Step back one iteration to see that same
method call go to Animal's version.
Python Tutor makes recursion easier to understand by showing all active frames on the stack, with each having their own private copies of local variables. For instance, here's the ultra-cliched recursive factorial example:
At the current step, four frames of factorial are visible, each
holding its own n. Stepping forward shows each frame returning its
result to its caller until the original call returns 24.
When an exception happens, rather than seeing a wall of error text, users can see exactly where an error occurred and the context around it. This can be useful when exceptions are caught by handlers or bubbled up through layers of function calls before being caught. Here's a simple example:
Note here how the red arrow jumps to the exception handler inside of
except.
Everything below this point is for more advanced courses beyond CS1/CS2.
First, closures are something that almost no other tool draws correctly:
At this step make_counter already returned, yet its frame lives on
(shown in light gray) because the nested increment function still
refers to its count variable. The visualizer draws increment's frame
with a link to that parent frame. It can cover features like nonlocal,
lexical scoping, and functions carrying around their environment with
them.
Related to above, it can also visualize generators:
Each time the for loop asks for another value, the countdown frame
comes back onto the stack, resumes where it left off, and shows the
value it's about to yield.
The visualizer can also illustrate some (simple) functional programming concepts:
At the current step, sorted is repeatedly calling the lambda, which
runs in its own frame with its own n. In addition, default arguments,
*args and **kwargs, and circular references display correctly (e.g.,
lst.append(lst) renders as a list pointing to itself). Lastly, the
tool can visualize more advanced concepts like iterator protocols,
dunder methods, descriptors, context managers, MRO (method resolution
order), ABC (abstract base classes), and metaclasses.
Python Tutor can help your students see what their code actually does. It's free, it runs in the browser with nothing to install, and has been used by tens of millions since 2010.
Feel free to share this direct link in relevant course materials, chat groups, mailing lists, discussion forums, social media, or anywhere else:
And if you also teach Java, C/C++, or JavaScript, check out my companion articles on what the Java visualizer, C/C++ visualizer, and JavaScript visualizer can do.