55

I want to retrieve the local variables from Python from a called function. Is there any way to do this? I realize this isn't right for most programming, but I am basically building a debugger. For example:

def show_locals():
  # put something in here that shows local_1.

local_1 = 123
show_locals()  # I want this to show local_1.

What do I put in the body of show_locals? If I have to modify the calling statement, what is the minimal modification I can make?

Note: this must work when show_locals is in a different module to its caller.

0

3 Answers 3

97

If you're writing a debugger, you'll want to make heavy use of the inspect module:

def show_callers_locals():
    """Print the local variables in the caller's frame."""
    import inspect
    frame = inspect.currentframe()
    try:
        print(frame.f_back.f_locals)
    finally:
        del frame
Sign up to request clarification or add additional context in comments.

9 Comments

Yay! I found your solution after running into significant performance issues with an alternative solution: caller = inspect.stack()[1][0]; myvars = caller.f_locals. Your way is MUCH faster.
Why is deleting the frame in the finally block necessary? Is keeping the frame object in memory somehow expensive? This is a minor point, of course, but it left me confused. Also, thank you, this is very helpful!
The inspect documentation explains the del frame.
@user21952-is-a-great-name and Gareth, it seems to me the del frame (and thus the try block) is actually a no-op, since the frame variable is about to go out of scope anyway. No?
Ah wait, I get it. "go out of scope" means, literally, that the stack frame that owns the local variable is about to be released. But, 'frame' points to exactly that stack frame. That's the cycle they are talking about. Ok, I concede the del frame is useful. OTOH I'm not sure the variable is necessary at all. I think the function body could be print(inspect.currentframe().f_back.f_locals)
|
7

Perhaps it is worth pointing out that the technique from the accepted answer that reads from the caller's stack frame:

import inspect
def read_from_caller(varname):
    frame = inspect.currentframe().f_back
    try:
        v = frame.f_locals[varname]
        return v
    finally:
        del frame

can also write into the caller's namespace:

import inspect
def write_in_caller(varname, v):
    frame = inspect.currentframe().f_back
    try:
        frame.f_locals[varname] = v
    finally:
        del frame

If you put that in a module called "access_caller", then

import access_caller
access_caller.write_in_caller('y', x)

is an elaborate way of writing

y = x

(I am writing this as a fresh answer because I don't have enough reputation points to write a comment.)

2 Comments

Hi @daniel, it seems it does not work in python3.8 at least. The setitem call on f_locals has no effect
Hi @grégoire-roussel, Can you share a code example? For me, writing "x = 45", then "write_in_caller('y', x)", then "print(y)" reports 45 as expected. I am using python 3.8.5 in linux.
0

You use the python builtin, dir() or vars():

vars(object)

For examples using dir(), see: this post

Examples using vars:

>>> class X:
...     a=1
...     def __init__(self):
...         b=2
... 
>>> 
>>> vars(X)
{'a': 1, '__module__': '__main__', '__doc__': None, '__init__': <function __init__ at 0x100488848>}
>>> 
>>> vars(X())
{}

A potentially problematic fact: New style classes not return the same result

>>> class X(object):
...     a=1
...     def __init__(self):
...         b=2
... 
>>> 
>>> vars(X)
<dictproxy object at 0x1004a1910>
>>> vars(X())
{}

Also: for an instantiated class (new and old style), if you add a variable after instantiating, vars will return the object's dict like this:

>>> x = X() 
>>> x.c = 1
>>> vars(x)
{'c': 1}
>>> 

See: http://docs.python.org/library/functions.html#vars

1 Comment

This doesn't answer the question, the OP wants the oppersite where inside of func_1, if you call func_2 you can see all the locals from func_1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.