从调用命名空间获取局部变量在Python中

52 投票
3 回答
13695 浏览
提问于 2025-04-16 21:04

我想从一个被调用的函数中获取Python的局部变量。有没有什么办法可以做到这一点?我知道这样做在大多数编程场景中并不合适,但我基本上是在构建一个调试工具。例如:

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

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

我在show_locals的主体中应该写什么?如果我需要修改调用语句,最小的修改是什么?

注意:这必须在show_locals和它的调用者不在同一个模块时也能工作。

3 个回答

0

你可以使用Python内置的函数,dir()或者vars():

vars(对象)

想看看dir()的用法,可以参考这个帖子:这篇文章

使用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())
{}

有一个可能会让人困惑的地方:新风格的类返回的结果可能和旧风格的不一样

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

另外:对于一个已经实例化的类(无论是新风格还是旧风格),如果你在实例化后添加一个变量,vars会像这样返回对象的字典

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

更多信息请见:http://docs.python.org/library/functions.html#vars

7

也许值得提一下,接受的答案中提到的那种从调用者的栈帧读取数据的技巧:

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

其实也可以往调用者的命名空间写数据:

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

如果你把这个放在一个叫做“access_caller”的模块里,那么

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

其实就是一种复杂的写法:

y = x

(我写这个作为一个新的回答,因为我没有足够的声望分数来写评论。)

94

如果你在写一个调试器,你会需要大量使用inspect这个模块:

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

撰写回答