gpt4 book ai didi

python - 确定特定功能是否在Python堆栈中的有效方法

转载 作者:太空狗 更新时间:2023-10-30 01:49:48 27 4
gpt4 key购买 nike

对于调试而言,通常可以判断一个特定的函数是否在调用栈中更高的位置。例如,当某个函数调用我们时,我们通常只想运行调试代码。

一种解决方案是检查所有更高级别的堆栈条目,但这是在堆栈深处且反复调用的函数中,这会导致过多的开销。问题是找到一种方法,使我们能够以合理有效的方式确定特定函数是否在调用堆栈中更高的位置。

类似的

  • Obtaining references to function objects on the execution stack from the frame object?-这个问题着重于获取函数对象,而不是确定我们是否在特定函数中。尽管可以应用相同的技术,但它们最终可能效率极低。
  • 最佳答案

    除非您要使用的功能做了非常特殊的标记以标记“我的一个实例在堆栈中处于事件状态”(爱荷华州:如果该功能是原始且不可触摸的,并且可能无法意识到您的这种特殊需求) ,没有办法想到逐帧向上堆栈,直到您击中顶部(且该功能不存在)或您感兴趣的功能的堆栈框架为止。正如对该问题的几条评论所表明的那样,是否值得努力优化这一点极其令人怀疑。但是,为了争论起见,认为这是值得的...:

    编辑:最初的答案(由OP提出)有很多缺陷,但是自那以后已经修复了一些缺陷,因此,我正在编辑以反射(reflect)当前的情况以及某些方面为何很重要。

    首先,至关重要的是在装饰器中使用try/exceptwith,以便正确地考虑从被监视功能中退出的任何情况,而不仅仅是正常的情况(就像OP本身答案的原始版本那样)。

    其次,每个装饰器都应确保保持装饰后的函数的__name____doc__完整无缺-这就是functools.wraps的目的(还有其他方法,但是wraps使它最简单)。

    第三,就像第一点一样重要,set是OP最初选择的数据结构,它是错误的选择:函数可以在堆栈上多次(直接或间接递归)。我们显然需要一个“多件套”(也称为“袋子”),它是一种类似套子的结构,可以跟踪每个物品出现“多少次”。在Python中,多集的自然实现是作为dict映射键到count的dict,而dict最容易实现为collections.defaultdict(int)

    第四,通用方法应该是线程安全的(至少可以轻松实现的;-)。幸运的是,在适用时,threading.local使它变得微不足道-在这里,它一定是(每个堆栈都有其自己的单独调用线程)。

    第五,一个有趣的问题,已经在一些评论中提到(注意到某些答案中所提供的装饰者与其他装饰者玩得多么糟糕:监视装饰者似乎必须是最后一个(最外面的)装饰者,否则检查会中断。这来自使用功能对象本身作为监视命令的键是自然而不幸的选择。

    我建议通过另一种不同的键选择来解决此问题:让装饰器采用一个(字符串)identifier参数,该参数必须是唯一的(在每个给定线程中),并使用标识符作为监视dict的键。当然,检查堆栈的代码必须知道标识符并也要使用它。

    在装饰时,装饰器可以检查uniqueness属性(通过使用单独的集合)。标识符可以保留为默认的函数名称(因此,仅在保持相同 namespace 中监视同名函数的灵活性时才明确要求使用该标识符);当出于监视目的将多个被监视函数视为“相同”时,可以显式放弃唯一性属性(如果给定的def语句打算在略有不同的上下文中多次执行以使多个函数对象程序员希望出于监视目的考虑“相同的功能”)。最后,对于那些不可能进行进一步修饰的罕见情况(因为在那些情况下,这可能是确保唯一性的最简便方法),应该可以有选择地还原为“作为标识符的功能对象”。

    因此,将所有这些考虑因素放在一起,我们可以拥有(例如,可能已经在工具箱模块中的threadlocal_var实用程序函数;-)类似以下内容...:

    import collections
    import functools
    import threading

    threadlocal = threading.local()

    def threadlocal_var(varname, factory, *a, **k):
    v = getattr(threadlocal, varname, None)
    if v is None:
    v = factory(*a, **k)
    setattr(threadlocal, varname, v)
    return v

    def monitoring(identifier=None, unique=True, use_function=False):
    def inner(f):
    assert (not use_function) or (identifier is None)
    if identifier is None:
    if use_function:
    identifier = f
    else:
    identifier = f.__name__
    if unique:
    monitored = threadlocal_var('uniques', set)
    if identifier in monitored:
    raise ValueError('Duplicate monitoring identifier %r' % identifier)
    monitored.add(identifier)
    counts = threadlocal_var('counts', collections.defaultdict, int)
    @functools.wraps(f)
    def wrapper(*a, **k):
    counts[identifier] += 1
    try:
    return f(*a, **k)
    finally:
    counts[identifier] -= 1
    return wrapper
    return inner

    我没有测试过此代码,因此它可能包含一些错字或类似内容,但我之所以提供它是因为我希望它确实涵盖了我上面解释的所有重要技术要点。

    值得吗?如前所述,可能不是。但是,我认为“如果值得做的话,那就值得做正确的事” ;-)。

    关于python - 确定特定功能是否在Python堆栈中的有效方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1403471/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com