【问题标题】:What cool hacks can be done using sys.settrace?使用 sys.settrace 可以完成哪些很酷的 hack?
【发布时间】:2009-11-07 12:25:47
【问题描述】:

我喜欢使用 settrace 修改 get 发送到函数的参数,例如:

import sys

def trace_func(frame,event,arg):
    value = frame.f_locals["a"]
    if value % 2 == 0:
        value += 1
        frame.f_locals["a"] = value

def f(a):
    print a

if __name__ == "__main__":
    sys.settrace(trace_func)
    for i in range(0,5):
        f(i)

这将打印出来:

1
1
3
3
5

您还可以使用settrace 做哪些其他很酷的事情?

【问题讨论】:

    标签: python


    【解决方案1】:

    我强烈建议不要滥用 settrace。我假设您了解这些内容,但稍后出现的其他人可能不会。有几个原因:

    1. Settrace 是一个非常生硬的工具。 OP 的示例是一个简单的示例,但实际上无法扩展它以在实际系统中使用。

    2. 这很神秘。任何来查看您的代码的人都会完全困惑为什么它会这样做。

    3. 速度很慢。为所执行的每一行 Python 调用一个 Python 函数会使你的程序慢很多倍。

    4. 通常没有必要。这里的原始示例可以通过其他几种方式完成(修改函数、将函数包装在装饰器中、通过另一个函数调用它等),其中任何一种方式都比 settrace 更好。

      李>
    5. 很难做到正确。在最初的例子中,如果你没有直接调用 f,而是调用了调用 f 的 g,那么你的跟踪函数就不会完成它的工作,因为你从跟踪函数返回 None,所以它只被调用一次然后被遗忘。

    6. 它将阻止其他工具工作。该程序将不可调试(因为调试器使用 settrace),不可跟踪,无法测量其代码覆盖率等。部分原因是 Python 实现者缺乏远见:他们给了我们 settrace 但没有 gettrace,所以很难让两个跟踪函数一起工作。

    Trace 函数可用于很酷的 hack。能够滥用它很有趣,但请不要将它用于真实的东西。如果我听起来很吓人,我很抱歉,但这已经用真实的代码完成了,这很痛苦。例如,DecoratorTools 使用跟踪函数来执行使该语法在 Python 2.3 中工作的神奇壮举:

    # Method decorator example
    from peak.util.decorators import decorate
    
    class Demo1(object):
        decorate(classmethod)   # equivalent to @classmethod
        def example(cls):
            print "hello from", cls
    

    一个巧妙的 hack,但不幸的是,这意味着任何使用 DecoratorTools 的代码都不能与 coverage.py(或者调试器,我猜)一起工作。如果你问我,这不是一个好的权衡。我更改了coverage.py 以提供一种允许它与DecoratorTools 一起使用的模式,但我希望我不必这样做。

    即使是标准库中的代码有时也会出错。 Pyexpat 决定与其他所有扩展模块不同,并像调用 Python 代码一样调用跟踪函数。太糟糕了他们did a bad job of it

    【讨论】:

    • sys.gettrace 自 Python 2.6 (docs.python.org/library/sys.html#sys.gettrace) 以来就存在,但由于 settrace 的设计方式,处理程序在每次调用时返回一个新的处理程序函数,它并没有真正的帮助。我完全同意你的主要观点——settrace 不能用于(慢)调试以外的任何东西。
    • 这个答案写于 2009 年,我应该说作者提出的所有观点都不再适用。 sys.settrace() 和其他调试器可以共存,具体取决于实现(例如 ipdb.set_trace())。还有 is gettrace() 函数实现了......同样取决于实现,您的代码不一定要运行“慢很多倍”。它永远不会更快,是的,但这仍然是一个严重的过度概括。
    • @aarslan 这不是一个过度概括:添加代码总是慢。此外,调试工具不是为了性能,而是为了调试。最后,将调试工具用作功能代码是我遇到过的最糟糕的做法之一。
    • @Tim 我清楚地说代码运行较慢,但不一定“慢很多倍”。此外,我批评了 settrace 不能用于除缓慢调试之外的任何东西的绝对声明。除此之外,当然还有一些有用的实践,它们与调试没有任何关系。它只是一个跟踪函数调用和文件的工具。我已经看到它使用自动存档工具将包含分析管道的快速变化的代码库与其输出配对,以确保轻松准确地再现相同的输出。
    • @aarslan,好吧,如果你的观点是 sys.settrace() 可用于代码覆盖工具或测试,我同意,但你没有明确表示。我的观点是始终将sys.settrace() 用于元-编程,而不是用于编程,@Ned's 也是如此。
    【解决方案2】:

    我制作了一个名为pycallgraph 的模块,它使用sys.settrace() 生成调用图。

    【讨论】:

    • 我看不到与 gprof2dot 相比的附加值,它多年来产生完全相同的图表(自 2007-03-30 起,完全见 the GitHub project),除了它添加了关于每个被调用的函数(自身时间、总时间、调用次数)。不过干得不错。
    【解决方案3】:

    当然,代码覆盖是通过跟踪功能完成的。我们以前没有过的一件很酷的事情是分支覆盖率测量,而且进展顺利,即将在 coverage.py 的 alpha 版本中发布。

    例如,考虑这个函数:

    def foo(x):
        if x:
            y = 10
        return y
    

    如果你用这个调用测试它:

    assert foo(1) == 10
    

    then 语句覆盖率将告诉您函数的所有行都已执行。但当然,该函数有一个简单的问题:使用 0 调用它会引发 UnboundLocalError。

    分支测量会告诉您代码中有一个分支没有完全执行,因为只占用了分支的一个分支。

    【讨论】:

      【解决方案4】:

      例如逐行获取Python代码的内存消耗:http://pypi.python.org/pypi/memory_profiler

      【讨论】:

        【解决方案5】:

        一个大量使用settrace 的最新项目是PySnooper

        它可以帮助新程序员跟踪/记录/监控他们的程序输出。干杯!

        【讨论】:

          【解决方案6】:

          我没有详尽全面的答案,但在另一位 SO 用户的帮助下,我用它做的一件事是 create a program that generates the trace tables of other Python programs

          【讨论】:

            【解决方案7】:

            python 调试器 Pdb 使用 sys.settrace 分析要调试的行。

            这是 pdb 的 c 优化/扩展,它也使用 sys.settrace

            https://bitbucket.org/jagguli/cpdb

            【讨论】:

              猜你喜欢
              • 2010-12-27
              • 2011-09-25
              • 1970-01-01
              • 2011-03-14
              • 1970-01-01
              • 2012-01-12
              • 1970-01-01
              • 1970-01-01
              • 2011-04-22
              相关资源
              最近更新 更多