使用 sys.settrace 可以完成哪些很酷的技巧?

问题描述 投票:0回答:8

我喜欢能够使用

settrace
修改发送到函数的参数,例如:

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 sys python-internals
8个回答
30
投票

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

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

  2. 这很神秘。任何人来看你的代码都会完全困惑为什么它正在做它正在做的事情。

  3. 速度很慢。为执行的每一行 Python 代码调用一个 Python 函数将使您的程序速度减慢许多倍。

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

  5. 很难做到正确。在最初的示例中,如果您没有直接调用 f ,而是调用 g 来调用 f,则您的跟踪函数将无法完成其工作,因为您从跟踪函数返回 None ,因此它只被调用一次,然后就被忘记了。

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

跟踪函数可以带来很酷的技巧。能够滥用它很有趣,但请不要将它用于真实的东西。如果我听起来像是在恐吓,我很抱歉,但这已经是在真实的代码中完成的,而且很痛苦。例如,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

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

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


26
投票

我制作了一个名为

pycallgraph
的模块,它使用
sys.settrace()
生成调用图。


12
投票

当然,代码覆盖率是通过trace函数完成的。我们以前没有过的一件很酷的事情是分支覆盖率测量,而且进展顺利,即将在 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


3
投票

大量使用

settrace
的最新项目是 PySnooper

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


1
投票

我没有一个详尽全面的答案,但我用它做的一件事是,在另一位用户的帮助下,创建一个程序来生成其他Python程序的跟踪表


1
投票

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

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

https://bitbucket.org/jagguli/cpdb


0
投票

使用 settrace 的一个非常酷的项目以一种很酷的方式将 defer 语句从 go 添加到语言中。它允许这样的代码:

def foo():
  print(", world!") in defer
  print("Hello", end="")
  # do something that might fail...
  assert 1 + 1 == 3

这将输出:

$ python foo.py
Hello, World!
Traceback (most recent call last):
  File "foo.py", line 7, in <module>
    assert 1 + 1 == 3
AssertionError

https://github.com/yasyf/python-defer

© www.soinside.com 2019 - 2024. All rights reserved.