86

I'm debugging my Python scripts using pdb and the manual says I can use p variables command to print the values of the specified variables at a certain point. But what if I had lots of variables, like 20 variables, and I would like to track the value of all of them? How do I print all of them without specifying each one manually? Take for example this script:

a = 1
b = 2
c = 3

I can debug it with pdb and print all of them using p a, b, c like this:

$ python -m pdb test.py 
> /media/test.py(1)<module>()
-> a = 1
(Pdb) n
> /media/test.py(2)<module>()
-> b = 2
(Pdb) n
> /media/test.py(3)<module>()
(Pdb) n
--Return--
> /media/test.py(3)<module>()->None
-> c = 3
(Pdb) p a, b, c
(1, 2, 3)
(Pdb) 

But I have to manually specify each variable. Is there a way of print all variables at once, without specifying each one of them?

renatov
  • 5,005
  • 6
  • 31
  • 38
  • 1
    Would executing `locals()` and `globals()` help? Note that pdb is capable of interpreting any python code, not only those special commands... – mike.dld Feb 22 '14 at 22:56
  • sub-duplicate of/answered here: [Enumerate or list all variables in a program of](http://stackoverflow.com/questions/430811/enumerate-or-list-all-variables-in-a-program-of-your-favorite-language-here) – OJFord Feb 22 '14 at 22:57
  • No, that is not what I am looking for. locals() and globals() print lots of information I don't want, and a big load of them, which turns everything into a mess. And the "solution" on that other thread is not what I am looking for either. That doesn't solve my question. – renatov Feb 22 '14 at 23:40
  • What do you envision your solution looking like? If there was a function show_all_my_variables() you could use, what would the output be? – munk Feb 22 '14 at 23:50
  • 2
    Exactly the same output as if I manually typed "p var1, var2, var3 ... varn" – renatov Feb 23 '14 at 00:07

2 Answers2

126

pdb is a fully featured python shell, so you can execute arbitrary commands.

locals() and globals() will display all the variables in scope with their values.

You can use dir() if you're not interested in the values.

When you declare a variable in Python, it's put into locals or globals as appropriate, and there's no way to distinguish a variable you defined and something that's in your scope for another reason.

When you use dir(), it's likely that the variables you're interested in are at the beginning or end of that list. If you want to get the key, value pairs

Filtering locals() might look something like:

>>> x = 10
>>> y = 20
>>> {k: v for k,v in locals().iteritems() if '__' not in k and 'pdb' not in k}
{'y': 20, 'x': 10}

If your locals() is a real mess, you'll need something a little more heavy handed. You can put the following function in a module on your pythonpath and import it during your debugging session.

def debug_nice(locals_dict, keys=[]):
    globals()['types'] = `__import__`('types')
    exclude_keys = ['copyright', 'credits', 'False', 
                    'True', 'None', 'Ellipsis', 'quit']
    exclude_valuetypes = [types.BuiltinFunctionType,
                          types.BuiltinMethodType,
                          types.ModuleType,
                          types.TypeType,
                          types.FunctionType]
    return {k: v for k,v in locals_dict.iteritems() if not
               (k in keys or
                k in exclude_keys or
                type(v) in exclude_valuetypes) and
               k[0] != '_'}

I've added an example session on pastebin

There are a couple of cases this misses. And you might want to extend it to allow you to pass in types too. But it should let you filter most everything but the variables you defined.

dir()

If you just want the last 20 values so you get output like >>> p var1 var2 ... varn would give you, then you're better off slicing dir() like dir()[-20:], but you won't easily see the relationship between the variables and values. eg: "Did I declare foo before or after bar?"

If you want to see that relationship, you can try something like this, which assumes that your variables are at the end of dir(). You can slice differently if they're at the beginning. This won't work well if your variables aren't contiguous.

>>> zip(dir(), [eval(var) for var in dir()])[-4:]
[('a', 10), ('var', 'var'), ('x', 30), ('y', 50)]
Celeo
  • 5,583
  • 8
  • 39
  • 41
munk
  • 12,340
  • 8
  • 51
  • 71
  • 1
    Executing locals() or globals() returns a bulky mess of non human readable information. Am I missing something? – renatov Feb 22 '14 at 23:06
  • 1
    It's just a dictionary containing names and values. You can try pprint to make it more readable. You can also try to filter out names with underscores. – munk Feb 22 '14 at 23:21
  • pprint will only put some indentation into that giant amount of information. Even if I filter names with underscores, this is not what I am looking for. – renatov Feb 22 '14 at 23:37
  • 1
    You can filter more specifically, but I can't give you a general solution because everything in locals() is something that could be a variable you're interested in. If you share your locals() we can help make a better filter for this use case though. – munk Feb 22 '14 at 23:44
  • Here is my locals() output from within pdb at the end of the script I posted: http://pastebin.com/VQ5fjMsH – renatov Feb 23 '14 at 00:11
  • This solution doesn't solve the issue, but it was the one which helped me the most, so I'm choosing it to close the topic. – renatov May 06 '15 at 18:53
  • 4
    @renatov using locals() or globals() "returns a bulky mess of non human readable information" then use them with pp (pretty print) command. pp locals() or pp globals() – Gaurav Oct 05 '16 at 10:30
  • 1
    For Python 3: I had to remove `types.TypeType` (not sure if there is [a replacement](https://docs.python.org/3.7/library/types.html)), and change `locals_dict.iteritems()` to `locals_dict.items()`. – Jonathon Reinhart Jun 01 '20 at 13:33
  • Correction: Change `types.TypeType` to just `type`. – Jonathon Reinhart Jun 01 '20 at 13:41
5

As given in this list for multiple languages:

a = 1
b = 1
n = 'value'
#dir() == ['__builtins__', '__doc__', '__name__', '__package__', 'a', 'b', 'n']
for var in dir()[4:]:
    value_of_var = eval(var)
    print(value_of_var)

Output:

1
1
'value'

Labelling each one is as simple as printing var + " equals " + eval(var).

You state your "ideal output" is exactly the result as typing p a, b, ... , n, ...:

vars = []
for var in dir()[4:-1]
    vars.append(var)
print(tuple(vars))

Output looks like:

(1, 1, 'value')
Community
  • 1
  • 1
OJFord
  • 10,522
  • 8
  • 64
  • 98
  • This command prints a lot of information, that's not what I am looking for. – renatov Feb 22 '14 at 23:40
  • "A lot of information".. `dir()` returns a list containing `__builtins__, `__doc__`, `__name__`, `__package__`, `your_vars` where applicable. Slice the list if there's stuff you don't want. e.g. `your_vars` only: `for var in dir()[4:]: print(eval(var))` – OJFord Feb 23 '14 at 00:48
  • The problem with this solution is that you only get the values, not the variable names. If you have 20+ variables you want to see then a list of say numbers is far less useful than a dict of the names and values. – munk Feb 23 '14 at 01:25
  • @usmcs That's not true. Please read the comment in my answer. Or my above comment, which specifies it returns a list of variables. Their names. Calling `eval()` gives the value. – OJFord Feb 23 '14 at 01:26
  • @usmcs You haven't declared any variables! – OJFord Feb 23 '14 at 01:42
  • @OllieFord `__builtins__`, `__doc__`, etc are all variables. But you see the result is the same here when I declare x,y,z and a http://pastebin.com/0TkhS2ZU. Your solution would work if you printed var, but you don't. You print the eval of var. Try print(var, eval(var)) – munk Feb 23 '14 at 01:46
  • @usmcs Yes, but not user-declared. What's the issue - you have the values there now... – OJFord Feb 23 '14 at 01:48
  • 1
    @usmcs The question is to print all variable values. That's what my code does, and that's what you're sample output is. In fact, you know it works, because you've edited it into your own answer... – OJFord Feb 23 '14 at 01:50
  • @usmcs That remains untrue. It gets the variable names, and uses them to `eval`uate the variable's value. "your solution does answer the OPs question" so what's the issue? – OJFord Feb 23 '14 at 01:53