7

Is there an easier way to display the name and the value of all variables defined in a single cell in a pretty way?

The way I'm doing now is like this, but I waste a lot of time when there are 30 variables or more:

enter image description here

Yuri F Becker
  • 358
  • 3
  • 11

3 Answers3

7

You can use whos command to see all variables stored in the current kernel.

k, g, lx = .4, .8, 6.6
m = k*g*lx**2
whos

outputs:

Variable   Type     Data/Info
-----------------------------
g          float    0.8
k          float    0.4
lx         float    6.6
m          float    13.939200000000001

But as said, it displays all variables, so it will display other variables from earlier cells you've run.

A similar result can be achieved using locals() or globals() command from python built-in functions, which return a dictionary of variables. But the way jupyter represents is prettier.


Alternatively you can use InteractiveShell. This will change the behavior of cells and act like a python shell would, so it will output every called value (to output cell) once run.

from IPython.core.interactiveshell import InteractiveShell
InteractiveShell.ast_node_interactivity = "all"

k
g
... do stuff ...
lx
m
... do more stuff ...

outputs:

Out[2]: 0.4
Out[2]: 0.8
Out[2]: 6.6
Out[2]: 13.939200000000001

And finally you can return the interactivity to default by setting it to last_expr.

InteractiveShell.ast_node_interactivity = "last_expr"

But the way you do it is probably the easiest and prettiest way, you can just remove the assignment on dataframe to make it a one liner or you can make it more compact to call by:

k, g, lx, m

Out[3]: (0.4, 0.8, 6.6, 13.939200000000001)
umutto
  • 7,460
  • 4
  • 43
  • 53
6

So, this was a tough nut to crack. Essentially we are just trying to grab all of the lines in the current cell and extract the variables. As it turns out, we cannot use the global variables defined by IPython (e.g. _, __, _i<n> etc) as suggested in Programmatically get current Ipython notebook cell output? because (as far as my experiments have shown) you can only grab values from previously executed cells and not the one currently being executed.

Luckily for us, it turns out that using the magic command %history does grab the input of the current cell. So with the help of this and this I have created a function that does exactly what you want:

def cell_vars(offset=0):
    import io
    from contextlib import redirect_stdout

    ipy = get_ipython()
    out = io.StringIO()

    with redirect_stdout(out):
        ipy.magic("history {0}".format(ipy.execution_count - offset))

    #process each line...
    x = out.getvalue().replace(" ", "").split("\n")
    x = [a.split("=")[0] for a in x if "=" in a] #all of the variables in the cell
    g = globals()
    result = {k:g[k] for k in x if k in g}
    return result

You can test it with something like:

a = 1
b = 2
c = 3

cell_vars()

which should give {'a': 1, 'b': 2, 'c': 3}, you can then format this and print it however you like. Obviously there are some limitations with my line processing (assumes that all variables of interest are in global scope).

Hope this is useful!

BenedictWilkins
  • 1,173
  • 8
  • 25
  • This was exactly what I needed for my project, thank you! Your code does give a deprecation warning as of IPython 8.1, but this can be solved very simply by replacing ipy.magic .... with ipy.run_line_magic("history", format(ipy.execution_count - offset)). – wjmatthews Mar 11 '23 at 13:44
  • Apologies for not formatting the code. Updated solution is `ipy.run_line_magic("history", format(ipy.execution_count - offset)` – wjmatthews Mar 11 '23 at 13:59
2

You can try something like this, using the inspect library.

import inspect

k = 0.0417
g = 0.829
lx = 6.6
m = k*g*lx**2

def get_name(lst=[]):
    local_vars = inspect.currentframe().f_back.f_locals.items()
    for i in local_vars:
        lst.append(i)
    return dict(lst)

import pandas as pd

df = pd.DataFrame(get_name(), index=[0])
result = df.T.loc[df.dtypes != object]
print(result)
          0
g     0.829
k     0.0417
lx    6.6
m     1.50584
Joe T. Boka
  • 6,554
  • 6
  • 29
  • 48
  • Thanks but i'm getting an error. I copied and pasted the exact code and it gives: Shape of passed values is (30, 2), indices imply (30, 1) – Yuri F Becker Oct 19 '17 at 16:13