在Python中获取调用函数的模块__name__

135 投票
4 回答
81542 浏览
提问于 2025-04-15 12:45

假设 myapp/foo.py 文件里有:

def info(msg):
    caller_name = ????
    print '[%s] %s' % (caller_name, msg)

myapp/bar.py 文件里有:

import foo
foo.info('Hello') # => [myapp.bar] Hello

我想让 caller_name 这个变量的值设置为调用这个函数的模块的 __name__ 属性(在这个例子中是 'myapp.foo')。我该怎么做呢?

4 个回答

8

我不太建议这样做,但你可以用下面的方法来实现你的目标:

def caller_name():
    frame=inspect.currentframe()
    frame=frame.f_back.f_back
    code=frame.f_code
    return code.co_filename

然后把你现有的方法更新成这样:

def info(msg):
    caller = caller_name()
    print '[%s] %s' % (caller, msg)
31

遇到类似的问题时,我发现来自sys模块的sys._current_frames()提供了一些有趣的信息,可以帮助你,而不需要导入inspect模块,至少在特定的情况下是这样。

>>> sys._current_frames()
{4052: <frame object at 0x03200C98>}

然后你可以通过f_back来“向上移动”:

>>> f = sys._current_frames().values()[0]
>>> # for python3: f = list(sys._current_frames().values())[0]

>>> print f.f_back.f_globals['__file__']
'/base/data/home/apps/apricot/1.6456165165151/caller.py'

>>> print f.f_back.f_globals['__name__']
'__main__'

对于文件名,你也可以使用f.f_back.f_code.co_filename,正如Mark Roddy上面提到的。我不太确定这种方法的限制和注意事项(多个线程可能会是个问题),但我打算在我的情况下使用它。

173

看看这个叫做 inspect 的模块:

inspect.stack() 这个命令可以返回当前的调用栈信息。

在一个函数内部,使用 inspect.stack()[1] 可以得到调用这个函数的地方的信息。通过这些信息,你可以了解到调用者的函数名、模块等更多内容。

想了解更多细节,可以查看文档:

http://docs.python.org/library/inspect.html

另外,Doug Hellmann 在他的 PyMOTW 系列中对 inspect 模块也有很好的介绍:

http://pymotw.com/2/inspect/index.html#module-inspect

编辑:这里有一些代码,应该可以实现你想要的功能:

import inspect 

def info(msg):
    frm = inspect.stack()[1]
    mod = inspect.getmodule(frm[0])
    print '[%s] %s' % (mod.__name__, msg)

撰写回答