114

假设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

3 回答 3

143

查看检查模块:

inspect.stack()将返回堆栈信息。

在函数内部,inspect.stack()[1]将返回调用者的堆栈。从那里,您可以获得有关调用者的函数名称、模块等的更多信息。

有关详细信息,请参阅文档:

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

此外,Doug Hellmann 在他的 PyMOTW 系列中对检查模块进行了很好的描述:

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)
于 2009-07-08T01:03:42.510 回答
24

面对类似的问题,我发现sys 模块中的sys._current_frames()包含可以帮助您的有趣信息,而无需导入检查,至少在特定用例中是这样。

>>> 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 所建议的那样。我不确定这种方法的限制和注意事项(多线程很可能是一个问题),但我打算在我的情况下使用它。

于 2011-02-21T21:35:29.210 回答
3

我不建议这样做,但您可以通过以下方法实现您的目标:

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)
于 2009-07-08T01:32:12.330 回答