如何检测Python代码是否通过调试器执行?

36

有没有一种简单的方法可以在Python代码中检测到当前是否正在通过Python调试器执行代码?

我有一个小的Python应用程序,使用了Java代码(感谢JPype)。当我在调试Python部分时,我希望嵌入式JVM也能够传递调试选项。

10个回答

28

Python调试器(以及分析工具和覆盖率工具)使用sys.settrace函数(在sys模块中)注册回调函数,当有趣的事件发生时,该函数会被调用。

如果您使用的是Python 2.6,则可以调用sys.gettrace()来获取当前跟踪回调函数。 如果它不是None,那么您可以假定应该将调试参数传递给JVM。

在2.6之前如何实现这一点并不清楚。


5
虽然这似乎是一种更干净的方式,但如果没有设置断点,则在 pdb 中不起作用。 - OOO
嗯,你说得对 - 这一定是调试器使用的一种优化。话虽如此,在大多数情况下,当你在调试器中运行时,你会设置一个断点。 - babbageclunk
@babbageclunk,如果你只是想在程序崩溃时查看环境(这是我最常用的方法:python -m pdb <program>),那就不需要了。 - Casey Kuball
你可能想检查一下类似 pytest-cov 的备选跟踪用户... 如果它确实是一个调试器,那么它的名称应该包含 pydevd - Chris R. Donnelly

16

如果您使用Pydev并进行多线程处理,则另一种可行的替代方法是:

try:
    import pydevd
    DEBUGGING = True
except ImportError:
    DEBUGGING = False

除非在执行 pip install pydevd 命令后... - bers

15

这个解决方案适用于Python 2.4(它应该适用于任何版本大于2.1)和Pydev:

import inspect

def isdebugging():
  for frame in inspect.stack():
    if frame[1].endswith("pydevd.py"):
      return True
  return False
简洁地翻译如下:

同样的方法也适用于 pdb,只需用 pdb.py 替换 pydevd.py 即可。正如 do3cc 建议的那样,它会在调用者的堆栈中查找调试器。

有用的链接:


一行代码:any(True for frame in inspect.stack() if frame[1].endswith('pydevd.py')) - Mattwmaster58

9

另一种方法取决于您的 Python 解释器是如何启动的。它要求您在生产环境下使用 -O 开始 Python,在调试时不使用 -O。因此,它需要一个可能难以维护的外部纪律,但它也可能完全适合您的流程。

从 Python 文档中了解(请参阅“内置常量”这里这里):

__debug__
This constant is true if Python was not started with an -O option.

使用方法应该是这样的:

if __debug__:
    print 'Python started without optimization'

2
这并不是问题的真正答案 - 即使在没有运行调试器的情况下(但没有使用“-O”“优化”标志),你仍然会得到__debug__ - dsz
确实,这就是“需要外部纪律”的警告。 - Travelling Man

7
如果您正在使用Pydev,可以通过以下方式检测它:
import sys
if 'pydevd' in sys.modules: 
    print "Debugger"
else:
    print "commandline"

1
同样地,如果使用pdb,则可以使用if 'pdb' in sys.modules: ... - Jason R. Coombs
我发现在某些情况下,这种技术是不可行的,比如在使用pytest运行测试时 - Jason R. Coombs

2
在我的 perllib 中,我使用了以下检查:
if 'pdb' in sys.modules:
    # We are being debugged

它假设用户没有导入pdb


1

由于原问题并没有特别指出Python2 - 这是为了确认 @babbageclunk 建议使用 sys 同样 适用于Python3:

from sys import gettrace as sys_gettrace

DEBUG = sys_gettrace() is not None
print("debugger? %s" % DEBUG)

不幸的是,只有在使用“step”时才有效。如果使用“continue”,那么gettrace()将返回None。 - snoopyjc
我熟悉VSCode的Python调试器 - 你能详细说明如何使用“步进”或“继续”选项启动调试器吗? - Adam Smooch
python -m pdb Program.py - 我想知道用户是否使用了“-m pdb”选项。最终我检查了一下sys.modules中是否存在“pdb”。 - snoopyjc
2
你想在自己的回答中分享吗?我会在我的帖子中添加我的假设。 - Adam Smooch

1
从快速查看pdb文档和源代码来看,似乎没有内置的方法来实现这一点。我建议您设置一个环境变量,指示正在进行调试,并让您的应用程序对此做出响应。
$ USING_PDB=1 pdb yourprog.py

然后在yourprog.py中:

import os
if os.environ.get('USING_PDB'):
    # debugging actions
    pass

1

-1
我找到了一种更简洁的方法,
只需在您的manage.py中添加以下行即可。
#!/usr/bin/env python
import os
import sys

if __debug__:
    sys.path.append('/path/to/views.py')


if __name__ == "__main__":
    ....

然后在你调试时,它会自动添加进去。


2
不,这取决于你是否在运行 Python 时使用了 -o 标志。 - Christopher Barber

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接