【问题标题】:Locating (file/line) the invocation of a constructor in python在python中定位(文件/行)构造函数的调用
【发布时间】:2024-01-21 17:23:01
【问题描述】:

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

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

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

【问题讨论】:

    标签: python exception event-handling stack-trace


    【解决方案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')
    

    【讨论】:

    • 谢谢,但是当 init 超载时,这对于类来说并不可靠。
    • 啊,好吧。没有测试那个案例,但我想它可以修改为在 f.f_locals 中找到“self”并保存它的值......
    【解决方案2】:

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

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

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

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

    【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

      • 但是要创建哈希,我仍然需要在调用构造函数时处理整个堆栈跟踪:/
      最近更新 更多