1

我正在实现一个事件系统:各种代码将事件发布到一个中心位置,在那里它们将分发给所有侦听器。这种方法的主要问题是:当事件处理过程中发生异常时,我无法再知道是谁发布了该事件。

所以我的问题是:有没有一种有效的方法来找出谁调用了构造函数并在 Python 2.5 中记住这一点?

更多信息:简单的方法是使用 traceback 模块在构造函数中获取堆栈的副本并记住这一点。唉,我很少需要这些信息,所以我想知道是否有办法缓存这些信息,或者我是否可以记住最顶层的堆栈帧并在我真正需要这些数据的极少数情况下工作。

4

4 回答 4

1
import sys
def get_caller(ext=False):
    """ Get the caller of the caller of this function. If the optional ext parameter is given, returns the line's text as well. """
    f=sys._getframe(2)
    s=(f.f_code.co_filename, f.f_lineno)
    del f
    if ext:
        import linecache
        s=(s[0], s[1], linecache.getline(s[0], s[1]))

    return s

def post_event(e):
    caller=get_caller(True)
    print "Event %r posted from %r"%(e, caller)

## Testing the functions.

def q():
    post_event("baz")

post_event("foo")
print "Hello!"
q()

结果是

Event 'foo' posted from ('getcaller.py', 20, 'post_event("foo")\n')
Hello!
Event 'baz' posted from ('getcaller.py', 17, '\tpost_event("baz")\n')
于 2009-04-04T09:41:55.083 回答
1

您可以简单地存储对调用者框架对象的引用,但这可能是个坏主意。这使帧保持活动状态,并且还保存对所有使用的局部变量的引用,因此如果它们碰巧使用大块内存,它可能会影响性能,并且如果它们(错误地)依赖于终结,则可能会产生更糟糕的影响超出范围时销毁锁和文件句柄等资源。

这意味着您需要保留堆栈跟踪的字符串表示形式,这对于您的目的来说并不理想(需要实际进行一些处理才能获得它,即使它很少需要)。不幸的是,似乎没有什么办法可以解决这个问题,尽管您可以考虑禁用它,直到您设置一些配置选项。这样,您可以在常见情况下获得更好的性能,但在尝试诊断故障时仍然可以启用该设置。

如果您的调用函数单独(或少数父调用者)足以区分路由(即通过 func1() 调用时跟踪始终相同,并且没有 func2 -> func1() vs func3() - > func1() 来区分),您可以根据调用帧(或最后两个调用帧等)的文件名和行号维护哈希。但是,这可能与您的情况不匹配,如果不匹配,您最终会得到虚假的堆栈跟踪。

请注意,如果您确实想要调用者的框架,使用inspect.currentframe(depth)可能是获取它的更好方法。

于 2009-04-04T10:15:51.460 回答
1

我认为最简单的方法是向相关事件添加一个 ID 字段,并让每个事件源(通过此处适当的“事件源”定义)在发布时提供唯一标识符事件。您确实会获得更多的开销,但可能不足以成为问题,而且我怀疑您会找到其他方法来了解事件的来源会有所帮助。

于 2009-04-05T02:37:33.830 回答
0

将堆栈跟踪的散列附加到事件的构造函数并将实际内容以散列作为键存储在内存缓存中可能是值得的。

于 2009-04-04T09:06:57.617 回答