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

发布于 2024-08-10 03:53:31 字数 448 浏览 5 评论 0原文

我喜欢能够使用 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 你还能做哪些其他很酷的事情?

I love being able to modify the arguments the get sent to a function, using settrace, like :

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)

And this will print:

1
1
3
3
5

What other cool stuff can you do using settrace?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

别在捏我脸啦 2024-08-17 03:53:31

我强烈建议不要滥用 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 代码一样调用跟踪函数。太糟糕了,他们做得很糟糕

I would strongly recommend against abusing settrace. I'm assuming you understand this stuff, but others coming along later may not. There are a few reasons:

  1. Settrace is a very blunt tool. The OP's example is a simple one, but there's practically no way to extend it for use in a real system.

  2. It's mysterious. Anyone coming to look at your code would be completely stumped why it was doing what it was doing.

  3. It's slow. Invoking a Python function for every line of Python executed is going to slow down your program by many multiples.

  4. It's usually unnecessary. The original example here could have been accomplished in a few other ways (modify the function, wrap the function in a decorator, call it via another function, etc), any of which would have been better than settrace.

  5. It's hard to get right. In the original example, if you had not called f directly, but instead called g which called f, your trace function wouldn't have done its job, because you returned None from the trace function, so it's only invoked once and then forgotten.

  6. It will keep other tools from working. This program will not be debuggable (because debuggers use settrace), it will not be traceable, it will not be possible to measure its code coverage, etc. Part of this is due to lack of foresight on the part of the Python implementors: they gave us settrace but no gettrace, so it's difficult to have two trace functions that work together.

Trace functions make for cool hacks. It's fun to be able to abuse it, but please don't use it for real stuff. If I sound hectoring, I apologize, but this has been done in real code, and it's a pain. For example, DecoratorTools uses a trace function to perform the magic feat of making this syntax work in 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

A neat hack, but unfortunately, it meant that any code that used DecoratorTools wouldn't work with coverage.py (or debuggers, I guess). Not a good tradeoff if you ask me. I changed coverage.py to provide a mode that lets it work with DecoratorTools, but I wish I hadn't had to.

Even code in the standard library sometimes gets this stuff wrong. Pyexpat decided to be different than every other extension module, and invoke the trace function as if it were Python code. Too bad they did a bad job of it.

</rant>

韶华倾负 2024-08-17 03:53:31

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

I made a module called pycallgraph which generates call graphs using sys.settrace().

脱离于你 2024-08-17 03:53:31

当然,代码覆盖率是通过trace函数来完成的。我们以前没有过的一件很酷的事情是分支覆盖率测量,而且进展顺利,即将在 覆盖率.py

例如,考虑这个函数:

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

如果您使用此调用测试它:

assert foo(1) == 10

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

分支测量会告诉您代码中存在一个未完全执行的分支,因为只采用了该分支的一个分支。

Of course, code coverage is accomplished with the trace function. One cool thing we haven't had before is branch coverage measurement, and that's coming along nicely, about to be released in an alpha version of coverage.py.

So for example, consider this function:

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

if you test it with this call:

assert foo(1) == 10

then statement coverage will tell you that all the lines of the function were executed. But of course, there's a simple problem in that function: calling it with 0 raises a UnboundLocalError.

Branch measurement would tell you that there's a branch in the code that isn't fully exercised, because only one leg of the branch is ever taken.

一刻暧昧 2024-08-17 03:53:31

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

For example, get the memory consumption of Python code line-by-line: http://pypi.python.org/pypi/memory_profiler

影子是时光的心 2024-08-17 03:53:31

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

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

One latest project that uses settrace heavily is PySnooper

It helps new programmers to trace/log/monitor their program output. Cheers!

゛时过境迁 2024-08-17 03:53:31

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

I don't have an exhaustively comprehensive answer but one thing I did with it, with the help of another user on SO, was create a program that generates the trace tables of other Python programs.

怂人 2024-08-17 03:53:31

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

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

https://bitbucket.org/jagguli/cpdb

The python debugger Pdb uses sys.settrace to analyse lines to debug.

Here's an c optimization/extension for pdb that also uses sys.settrace

https://bitbucket.org/jagguli/cpdb

止于盛夏 2024-08-17 03:53:31

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

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< /a>

A really cool project using settrace adds the defer statement from go to the language in a cool way. It allows code like this:

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

This will output:

$ 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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文