Bring up the subject of Jupyter notebooks among Python developers and you’ll probably get a variety of opinions about them. Many developers believe that using laptops encourages bad habits, creates confusion, and leads to ugly code. A very common problem is the idea of hidden states in notebooks. This hidden state can manifest itself in several ways, but a common way is to execute the notebook units out of order. This often happens during development and exploration. It is common to modify a call, execute it multiple times, or even delete it. Once a cell is deleted or modified and re-executed, the hidden state of the cell remains in the current session. Variables, functions, classes, and any other code will continue to exist and may affect code in other cells.

This leads to some obvious problems, first with the current session to the notebook, and second with any future calls to the notebook. In order for the notebook to reflect reality, it should contain valid code that can be executed to produce consistent results. In fact, you can achieve this in several ways.

Eliminate it

If your laptop is small and fast, you can always reboot your kernel and rerun all the code. This mimics the more typical development approach of unit testing or running scripts from the command line (or in IDE integration). If you just run a new Python instance with saved code, there will be no hidden state and the output will be consistent. This makes sense for small notebooks, where you can quickly visualize all the code and verify it when you check it.

But this may not work in all cases.

Look at it

If developers don’t want to constantly restart their interpreter, they can also see what the current state is. Let’s walk through a few ways to do this, from simple to more complex. Note that this code example uses Jupyter 6.15 and IPython 7.19.0 as the kernel.

First, let’s do some data.

import numpy as np

def a_function():
    pass

class MyClass:
    def __init__(self, name):
        self.name = name

var = "a variable"
var2 = "another variable"
x = np.ones(20)
Copy the code

Now, once the cell with the Python code above is executed, I can check the state of my current session by executing a single cell with one of the variables, or by using the IPythondisplay function. A cell will display the value of the last row in that cell (unless you append one at the end of the line;). . If the default interpreter is used, display, but any variable executed will display the value (according to its __repr__ method).

display(a_function)
display(var2)
display(MyClass)
display(x)
var
Copy the code
<function __main__.a_function()>
'another variable'
__main__.MyClass
array([1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1.,
       1., 1., 1.])
'a variable'
Copy the code

But what if the code disappears?

Well, the above method is obvious and we can look at items that we know exist. But how do we find objects that we don’t know exist? Maybe we removed the cell that created the value, or if we were using the IPython command line, our history would be invisible to the code. Or we edit the cell a few times, then re-execute it and change some variable names.

One feature to consider is the dir built-in function. When you call this function with no arguments, it returns a list of all variable names in the local scope. If you provide a module or class, it lists the properties of that module or class (and its subclasses).

When we do that, we can see that our variables are all there. Note that this is available in standard Python, not just IPython.

dir()
Copy the code
['In',
 'MyClass',
 'Out',
 '_',
 '_2',
 '__',
 '___',
 '__builtin__',
 '__builtins__',
 '__doc__',
 '__loader__',
 '__name__',
 '__package__',
 '__spec__',
 '_dh',
 '_i',
 '_i1',
 '_i2',
 '_i3',
 '_ih',
 '_ii',
 '_iii',
 '_oh',
 'a_function',
 'exit',
 'get_ipython',
 'np',
 'quit',
 'var',
 'var2',
 'x']
Copy the code

Wow, there are so many other things in there. Most of the variables are added by IPython and relate to the command history, so if you run the example with the default interpreter, there won’t be as many variables. In addition, some functions load at startup (you can also configure IPython to load other functions). Other objects exist because Python places them in global scope.

Note that the special variable _ is the value of the cell (or row) that was last executed.

useglobalslocals

There are two other functions that are helpful. The functions locals and globals. Return the symbol table, which is a dictionary of values called keys by variables. For globals, this is the value of the current module (when called in a function or method, the module is where the function is defined, not where it is executed). Locals, which is the same as globals when called at the module level, but returns free variables when called from a function block.

Be careful not to modify these tables, which will affect the running interpreter.

locals()         # get the full dictionary
globals()['var'] # grab out a single value
Copy the code
'a variable'
Copy the code

Can I see something more beautiful?

Working with a large dictionary with some extra values added by IPython may not be the easiest way to check your variables. You can set up a function to beautify the symbol table, but fortunately, there is already some good magic for this purpose. (Magic is a special function in IPython, see here for a quick introduction to magic, especially AutoReload.)

Jupyter/IPython provides three useful magics for checking variables. First, there is a %who. It prints out all interactive variables in a minimal format with no arguments. You can provide the type and display only the variables that match the given type.

%who
MyClass	 a_function	 np	 var	 var2	 x

# just functions
%who function
a_function
Copy the code

The %who_ls magic does the same thing, but returns the variable as a list. It can also limit what you see by type.

%who_ls
['MyClass', 'a_function', 'np', 'var', 'var2', 'x']

%who_ls str function
['a_function', 'var', 'var2']
Copy the code

The final magic is % WHos, which provides a nice formatted table that displays variable, type, and string representations. It includes useful information about Numpy and PANDAS data structures.

%whos Variable Type Data/Info ---------------------------------- MyClass type <class '__main__.MyClass'> a_function function <function a_function at 0x10ca51e50> np module <module 'numpy' from '/Us<... >kages/numpy/__init__.py'> var str a variable var2 str another variable x ndarray 20: 20 elems, type `float64`, 160 bytesCopy the code

Fancy output

Now, if you want to get fancy, Jupyter has an extension that is offered through Nbextensions. The Variable Inspector extension will give you a nice option to view variables in output similar to the % WHOS above. For developers used to ides with auto-update variable checkers, this extension may prove useful and worth checking out.

To delete a variable

After looking at the variables defined locally, you may want to delete some of them. For example, if you delete a cell and want the object created by that cell to be deleted, just del. Use any of the above methods to verify that they are gone.

del var2
%whos
Copy the code
Variable Type Data/Info ---------------------------------- MyClass type <class '__main__.MyClass'> a_function function <function a_function at 0x10ca51e50> np module <module 'numpy' from '/Us<... >kages/numpy/__init__.py'> var str a variable x ndarray 20: 20 elems, type `float64`, 160 bytesCopy the code

conclusion

Now you know the tools you can use to find variables in your current Python session. Using them will give you a better understanding of the code you’re already executing, and maybe save yourself a little time.

The postHow to view all your variables in a Jupyter notebookappeared first onwrighters.io.