标签归档:debugging

使用IPython进行分步调试

问题:使用IPython进行分步调试

根据我的阅读,有两种方法可以在Python中调试代码:

  • 使用传统的调试器,例如pdbipdb。它支持诸如cfor continuenfor step-oversfor step-into等命令,但是您没有直接访问IPython shell的权限,这对于对象检查非常有用。

  • 通过 IPython shell 嵌入代码中来使用 IPython。您可以这样做,然后在您的代码中使用。当您的程序/脚本命中一条语句时,您将进入IPython shell。这允许使用所有IPython好东西对对象进行全面检查并测试Python代码。但是,在使用时,您将无法通过便捷的键盘快捷键逐步完成代码。from ipython import embedembed()embed()embed()

有什么办法可以融合两全其美?即

  1. 能够 使用方便的pdb / ipdb键盘快捷键逐步完成代码。
  2. 在任何这样的步骤(例如,在给定的语句上),都可以访问成熟的IPython shell

如在 MATLAB中一样进行 IPython调试:

在MATLAB中可以找到这种“增强调试”类型的示例,在该示例中,用户始终可以完全访问MATLAB引擎/外壳,并且她仍然可以逐步完成代码,定义条件断点等。我已经与其他用户讨论过,这是人们从MATLAB转移到IPython时最想念的调试功能。

在Emacs和其他编辑器中进行IPython调试:

我不想让这个问题过于具体,但是我主要在Emacs中工作,所以我想知道是否有任何方法可以将此功能引入其中。理想情况下,Emacs(或编辑器)将允许程序员在代码上的任意位置设置断点,并与解释器或调试器进行通信,以使其在您选择的位置停止,并在该位置提供完整的IPython解释器。

From what I have read, there are two ways to debug code in Python:

  • With a traditional debugger such as pdb or ipdb. This supports commands such as c for continue, n for step-over, s for step-into etc.), but you don’t have direct access to an IPython shell which can be extremely useful for object inspection.

  • Using IPython by embedding an IPython shell in your code. You can do from IPython import embed, and then use embed() in your code. When your program/script hits an embed() statement, you are dropped into an IPython shell. This allows the full inspection of objects and testing of Python code using all the IPython goodies. However, when using embed() you can’t step-by-step through the code anymore with handy keyboard shortcuts.

Is there any way to combine the best of both worlds? I.e.

  1. Be able to step-by-step through your code with handy pdb/ipdb keyboard shortcuts.
  2. At any such step (e.g. on a given statement), have access to a full-fledged IPython shell.

IPython debugging as in MATLAB:

An example of this type of “enhanced debugging” can be found in MATLAB, where the user always has full access to the MATLAB engine/shell, and she can still step-by-step through her code, define conditional breakpoints, etc. From what I have discussed with other users, this is the debugging feature that people miss the most when moving from MATLAB to IPython.

IPython debugging in Emacs and other editors:

I don’t want to make the question too specific, but I work mostly in Emacs, so I wonder if there is any way to bring this functionality into it. Ideally, Emacs (or the editor) would allow the programmer to set breakpoints anywhere on the code and communicate with the interpreter or debugger to have it stop in the location of your choice, and bring to a full IPython interpreter on that location.


回答 0

您可以使用IPython的%pdb魔力。只需调用%pdbIPython,当发生错误时,您会自动转到ipdb。虽然您没有立即迈出一步,但您ipdb之后就进入了。

这使调试单个函数变得容易,因为您可以使用加载文件%load然后运行一个函数。您可以assert在正确的位置使用来强制执行错误。

%pdb是线魔术。呼之为%pdb on%pdb 1%pdb off%pdb 0。如果在不带参数的情况下调用它,则它将作为切换。

You can use IPython’s %pdb magic. Just call %pdb in IPython and when an error occurs, you’re automatically dropped to ipdb. While you don’t have the stepping immediately, you’re in ipdb afterwards.

This makes debugging individual functions easy, as you can just load a file with %load and then run a function. You could force an error with an assert at the right position.

%pdb is a line magic. Call it as %pdb on, %pdb 1, %pdb off or %pdb 0. If called without argument it works as a toggle.


回答 1

ipdb.set_trace()呢?在您的代码中:

import ipdb; ipdb.set_trace()

更新:现在在Python 3.7中,我们可以编写breakpoint()。它的工作原理相同,但也遵守PYTHONBREAKPOINT环境变量。此功能来自此PEP

这样可以对代码进行全面检查,并且您可以访问诸如c(继续),n(执行下一行),s(进入当前方法)之类的命令。

请参阅ipdb repo命令列表IPython现在称为Jupyter(的一部分)。


ps:请注意,ipdb命令优先于python代码。所以为了写,list(foo)你需要print list(foo)

另外,如果您喜欢ipython提示符(它的emacs和vim模式,历史记录,完成情况等),由于它基于python提示符工具包,因此很容易为您的项目获得相同的名称。

What about ipdb.set_trace() ? In your code :

import ipdb; ipdb.set_trace()

update: now in Python 3.7, we can write breakpoint(). It works the same, but it also obeys to the PYTHONBREAKPOINT environment variable. This feature comes from this PEP.

This allows for full inspection of your code, and you have access to commands such as c (continue), n (execute next line), s (step into the method at point) and so on.

See the ipdb repo and a list of commands. IPython is now called (edit: part of) Jupyter.


ps: note that an ipdb command takes precedence over python code. So in order to write list(foo) you’d need print(list(foo)), or !list(foo) .

Also, if you like the ipython prompt (its emacs and vim modes, history, completions,…) it’s easy to get the same for your project since it’s based on the python prompt toolkit.


回答 2

(2016年5月28日更新)在Emacs中使用RealGUD

对于Emacs中的任何人,此线程都说明了如何使用

  1. Emacs中一个称为RealGUD的新的重要调试器,可以与任何调试器(包括ipdb)一起使用。
  2. Emacs软件包isend-mode

这两个软件包的组合非常强大,可以使它们完全重新创建OP中描述的行为,甚至可以做更多的事情。

有关RealGUD for ipdb 的Wiki文章的更多信息。


原始答案:

在尝试了多种不同的调试Python方法(包括本线程中提到的所有内容)之后,我使用IPython调试Python的首选方法之一是使用嵌入式外壳程序。

定义定制的嵌入式IPython Shell:

将以下内容添加到脚本中PYTHONPATH,以使该方法ipsh()可用。

import inspect

# First import the embed function
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config

# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = '   .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '

# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")   
exit_msg = '**Leaving Nested interpreter'

# Wrap it in a function that gives me more context:
def ipsh():
    ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)

    frame = inspect.currentframe().f_back
    msg   = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)

    # Go back one level! 
    # This is needed because the call to ipshell is inside the function ipsh()
    ipshell(msg,stack_depth=2)

然后,每当我要调试代码中的某些内容时,就将其放置ipsh()在需要进行对象检查等的位置。例如,说我要在my_function下面调试

使用它:

def my_function(b):
  a = b
  ipsh() # <- This will embed a full-fledged IPython interpreter
  a = 4

然后my_function(2)以下列方式之一调用:

  1. 通过运行从Unix Shell调用此函数的Python程序
  2. 或直接从IPython调用

不管我如何调用它,解释器都会停在所说的行ipsh()。完成后,您可以执行操作Ctrl-D,Python将恢复执行(使用您所做的任何变量更新)。请注意,如果您从常规IPython IPython Shell(上面的案例2)运行代码,那么新的IPython Shell将嵌套在您从中调用它的外壳内,这很好,但是请注意。无论哪种方式,一旦解释器停在的位置ipsh,我都可以检查a2)的值,查看定义了哪些函数和对象,等等。

问题:

上面的解决方案可以使Python在代码中所需的任何位置停止,然后将您带入完整的IPython解释器。不幸的是,调用脚本后,它不允许您添加或删除断点,这非常令人沮丧。在我看来,这是阻止IPython成为Python出色的调试工具的唯一原因

您目前可以做的最好的事情是:

一种解决方法是ipsh()在要Python解释程序启动IPython Shell的不同位置(即breakpoint)放置先验先验。然后,您可以使用以下命令在不同的预定义,硬编码的“断点”之间“跳转”Ctrl-D,这将退出当前的嵌入式IPython shell,并且每当解释器单击下一个调用时再次停止ipsh()

如果走这条路线,退出“调试模式”并忽略所有后续断点的一种方法是使用ipshell.dummy_mode = True,这将使Python忽略ipshell我们在上面创建的对象的任何后续实例化。

(Update on May 28, 2016) Using RealGUD in Emacs

For anyone in Emacs, this thread shows how to accomplish everything described in the OP (and more) using

  1. a new important debugger in Emacs called RealGUD which can operate with any debugger (including ipdb).
  2. The Emacs package isend-mode.

The combination of these two packages is extremely powerful and allows one to recreate exactly the behavior described in the OP and do even more.

More info on the wiki article of RealGUD for ipdb.


Original answer:

After having tried many different methods for debugging Python, including everything mentioned in this thread, one of my preferred ways of debugging Python with IPython is with embedded shells.

Defining a custom embedded IPython shell:

Add the following on a script to your PYTHONPATH, so that the method ipsh() becomes available.

import inspect

# First import the embed function
from IPython.terminal.embed import InteractiveShellEmbed
from IPython.config.loader import Config

# Configure the prompt so that I know I am in a nested (embedded) shell
cfg = Config()
prompt_config = cfg.PromptManager
prompt_config.in_template = 'N.In <\\#>: '
prompt_config.in2_template = '   .\\D.: '
prompt_config.out_template = 'N.Out<\\#>: '

# Messages displayed when I drop into and exit the shell.
banner_msg = ("\n**Nested Interpreter:\n"
"Hit Ctrl-D to exit interpreter and continue program.\n"
"Note that if you use %kill_embedded, you can fully deactivate\n"
"This embedded instance so it will never turn on again")   
exit_msg = '**Leaving Nested interpreter'

# Wrap it in a function that gives me more context:
def ipsh():
    ipshell = InteractiveShellEmbed(config=cfg, banner1=banner_msg, exit_msg=exit_msg)

    frame = inspect.currentframe().f_back
    msg   = 'Stopped at {0.f_code.co_filename} at line {0.f_lineno}'.format(frame)

    # Go back one level! 
    # This is needed because the call to ipshell is inside the function ipsh()
    ipshell(msg,stack_depth=2)

Then, whenever I want to debug something in my code, I place ipsh() right at the location where I need to do object inspection, etc. For example, say I want to debug my_function below

Using it:

def my_function(b):
  a = b
  ipsh() # <- This will embed a full-fledged IPython interpreter
  a = 4

and then I invoke my_function(2) in one of the following ways:

  1. Either by running a Python program that invokes this function from a Unix shell
  2. Or by invoking it directly from IPython

Regardless of how I invoke it, the interpreter stops at the line that says ipsh(). Once you are done, you can do Ctrl-D and Python will resume execution (with any variable updates that you made). Note that, if you run the code from a regular IPython the IPython shell (case 2 above), the new IPython shell will be nested inside the one from which you invoked it, which is perfectly fine, but it’s good to be aware of. Eitherway, once the interpreter stops on the location of ipsh, I can inspect the value of a (which be 2), see what functions and objects are defined, etc.

The problem:

The solution above can be used to have Python stop anywhere you want in your code, and then drop you into a fully-fledged IPython interpreter. Unfortunately it does not let you add or remove breakpoints once you invoke the script, which is highly frustrating. In my opinion, this is the only thing that is preventing IPython from becoming a great debugging tool for Python.

The best you can do for now:

A workaround is to place ipsh() a priori at the different locations where you want the Python interpreter to launch an IPython shell (i.e. a breakpoint). You can then “jump” between different pre-defined, hard-coded “breakpoints” with Ctrl-D, which would exit the current embedded IPython shell and stop again whenever the interpreter hits the next call to ipsh().

If you go this route, one way to exit “debugging mode” and ignore all subsequent breakpoints, is to use ipshell.dummy_mode = True which will make Python ignore any subsequent instantiations of the ipshell object that we created above.


回答 3

您可以从pudb启动IPython会话,然后根据需要返回调试会话。

顺便说一句,ipdb在幕后使用IPython,您实际上可以使用IPython功能,例如TAB完成和魔术命令(以开头的命令%)。如果你是IPDB OK,你可以从IPython中使用命令,如启动%run%debug。从某种意义上讲,ipdb会话实际上比普通的IPython会话要好,因为您可以在堆栈跟踪中上下移动。ipdb中“对象检查”缺少什么?

另外,与Emacs> = 24.3捆绑在一起的python.el具有不错的ipdb支持。

You can start IPython session from pudb and go back to the debugging session as you like.

BTW, ipdb is using IPython behind the scenes and you can actually use IPython functionality such as TAB completion and magic commands (the one starts with %). If you are OK with ipdb you can start it from IPython using commands such as %run and %debug. ipdb session is actually better than plain IPython one in the sense you can go up and down in the stack trace etc. What is missing in ipdb for “object inspection”?

Also, python.el bundled with Emacs >= 24.3 has nice ipdb support.


回答 4

似乎@gaborous的答案中的方法已被弃用

新方法似乎是:

from IPython.core import debugger
debug = debugger.Pdb().set_trace

def buggy_method():
    debug()

Looks like the approach in @gaborous’s answer is deprecated.

The new approach seems to be:

from IPython.core import debugger
debug = debugger.Pdb().set_trace

def buggy_method():
    debug()

回答 5

前缀“!” 在pdb中键入命令的符号似乎与在IPython shell中执行操作具有相同的效果。这适用于访问某些功能甚至变量名的帮助。也许这会对您有所帮助。例如,

ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)

但是!help(numpy.transpose)将为您提供有关numpy.transpose的预期帮助页面。同样,对于变量名,假设您有一个变量l,在pdb中键入“ l”会列出代码,但是!l会打印出l的值。

Prefixing an “!” symbol to commands you type in pdb seems to have the same effect as doing something in an IPython shell. This works for accessing help for a certain function, or even variable names. Maybe this will help you to some extent. For example,

ipdb> help(numpy.transpose)
*** No help on (numpy.transpose)

But !help(numpy.transpose) will give you the expected help page on numpy.transpose. Similarly for variable names, say you have a variable l, typing “l” in pdb lists the code, but !l prints the value of l.


回答 6

您是否尝试过此技巧

或者更好的是,使用ipython并调用:

from IPython.Debugger import Tracer; debug_here = Tracer()

那你就可以用

debug_here()

每当你想设置一个断点

Did you try this tip?

Or better still, use ipython, and call:

from IPython.Debugger import Tracer; debug_here = Tracer()

then you can just use

debug_here()

whenever you want to set a breakpoint


回答 7

您可以IPython 从内部 开始ipdb

引入ipdb调试器1

import idpb; ipdb.set_trace()

输入IPython的从内部ipdb>控制台2

from IPython import embed; embed()

ipdb>从以下位置返回到控制台IPython

exit

如果您有幸使用Emacs,可以使事情变得更加便捷!

这需要使用M-x shell。使用yasnippetbm,定义以下代码段。这将用行替换ipdb编辑器中的文本set-trace。插入代码段后,该行将突出显示,以便易于观察和导航。使用M-x bm-next导航。

# -*- mode: snippet -*-
# name: ipdb
# key: ipdb
# expand-env: ((yas-after-exit-snippet-hook #'bm-toggle))
# --
import ipdb; ipdb.set_trace()

1全部一行,易于删除。由于imports仅发生一次,因此此表单确保ipdb将在您需要时将其导入,而不会产生额外的开销。

2,您可以通过导入自己节省一些打字IPython 的内.pdbrc文件

try:
    from IPython import embed
except:
    pass

这使您可以简单地embed()从内部进行调用ipdb(当然,仅在安装IPython时)。

You can start IPython from within ipdb!

Induce the ipdb debugger1:

import idpb; ipdb.set_trace()

Enter IPython from within in the ipdb> console2:

from IPython import embed; embed()

Return to the ipdb> console from within IPython:

exit

If you’re lucky enough to be using Emacs, things can be made even more convenient!

This requires using M-x shell. Using yasnippet and bm, define the following snippet. This will replace the text ipdb in the editor with the set-trace line. After inserting the snippet, the line will be highlighted so that it is easily noticeable and navigable. Use M-x bm-next to navigate.

# -*- mode: snippet -*-
# name: ipdb
# key: ipdb
# expand-env: ((yas-after-exit-snippet-hook #'bm-toggle))
# --
import ipdb; ipdb.set_trace()

1 All on one line for easy deletion. Since imports only happen once, this form ensures ipdb will be imported when you need it with no extra overhead.

2 You can save yourself some typing by importing IPython within your .pdbrc file:

try:
    from IPython import embed
except:
    pass

This allows you to simply call embed() from within ipdb (of course, only when IPython is installed).


回答 8

一种选择是使用像Spyder这样的IDE ,它应该允许您在调试时与代码进行交互(实际上是使用IPython控制台)。实际上,Spyder非常类似于MATLAB,我认为这是故意的。其中包括变量检查器,变量编辑,对文档的内置访问等。

One option is to use an IDE like Spyder which should allow you to interact with your code while debugging (using an IPython console, in fact). In fact, Spyder is very MATLAB-like, which I presume was intentional. That includes variable inspectors, variable editing, built-in access to documentation, etc.


回答 9

该问题的正确,简单,酷爽的准确答案是将%run宏与-d标志一起使用。

In [4]: run -d myscript.py
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.        
> /cygdrive/c/Users/mycodefolder/myscript.py(4)<module>()
      2                                                            
      3                        
----> 4 a=1                                            
      5 b=2

the right, easy, cool, exact answer for the question is to use %run macro with -d flag.

In [4]: run -d myscript.py
NOTE: Enter 'c' at the ipdb>  prompt to continue execution.        
> /cygdrive/c/Users/mycodefolder/myscript.py(4)<module>()
      2                                                            
      3                        
----> 4 a=1                                            
      5 b=2

回答 10

如果在embed()控制台中键入exit(),代码将继续并转到下一个embed()行。

If you type exit() in embed() console the code continue and go to the next embed() line.


回答 11

Pyzo IDE具有与OP问类似的功能。您不必以调试模式启动。与MATLAB相似,命令在shell中执行。在某些源代码行中设置断点时,IDE会在此处停止执行,并且您还可以调试和发出常规IPython命令。

但是,除非您设置了另一个断点,否则似乎单步执行(还好吗?)效果不佳(即在一行中停下来,然后步入另一功能)。

仍然来自MATLAB,这似乎是我找到的最佳解决方案。

The Pyzo IDE has similar capabilities as the OP asked for. You don’t have to start in debug mode. Similarly to MATLAB, the commands are executed in the shell. When you set up a break-point in some source code line, the IDE stops the execution there and you can debug and issue regular IPython commands as well.

It does seem however that step-into doesn’t (yet?) work well (i.e. stopping in one line and then stepping into another function) unless you set up another break-point.

Still, coming from MATLAB, this seems the best solution I’ve found.


回答 12

在python 3.2中,您具有interact命令,该命令可让您访问完整的python / ipython命令空间。

From python 3.2, you have the interact command, which gives you access to the full python/ipython command space.


回答 13

从Emacs的IPython-shell和通过pdb.set_trace()设置的断点运行应该可以。

与python-mode.el,Mx ipython RET等一起检查

Running from inside Emacs’ IPython-shell and breakpoint set via pdb.set_trace() should work.

Checked with python-mode.el, M-x ipython RET etc.


回答 14

开发新代码

在IPython中进行调试

  1. 使用Jupyter / IPython单元执行来加速实验迭代
  2. 使用%% debug逐步

单元格示例:

%%debug
...: for n in range(4):
...:    n>2

调试现有代码

IPython内部调试

  1. 调试损坏的单元测试: pytest ... --pdbcls=IPython.terminal.debugger:TerminalPdb --pdb
  2. 调试测试箱子外面:breakpoint()python -m ipdb,等。
  3. IPython.embed()用于在调试器中需要时具有完整的IPython功能

关于Python的想法

我同意OP的观点,MATLAB可以很好地完成许多事情,Python仍然没有,而且确实应该这样做,因为该语言中的几乎所有内容都偏重于开发速度而不是生产速度。也许有一天,我将为CPython贡献一些琐碎的错误修复。

https://github.com/ipython/ipython/commit/f042f3fea7560afcb518a1940daa46a72fbcfa68

另请参见是否可以通过调试在IPython中运行命令?

Developing New Code

Debugging inside IPython

  1. Use Jupyter/IPython cell execution to speed up experiment iterations
  2. Use %%debug for step through

Cell Example:

%%debug
...: for n in range(4):
...:    n>2

Debugging Existing Code

IPython inside debugging

  1. Debugging a broken unit test: pytest ... --pdbcls=IPython.terminal.debugger:TerminalPdb --pdb
  2. Debugging outside of test case: breakpoint(), python -m ipdb, etc.
  3. IPython.embed() for full IPython functionality where needed while in the debugger

Thoughts on Python

I agree with the OP that many things MATLAB does nicely Python still does not have and really should since just about everything in the language favors development speed over production speed. Maybe someday I will contribute more than trivial bug fixes to CPython.

https://github.com/ipython/ipython/commit/f042f3fea7560afcb518a1940daa46a72fbcfa68

See also Is it possible to run commands in IPython with debugging?


如何调试Flask应用

问题:如何调试Flask应用

您打算如何调试Flask中的错误?打印到控制台?向页面闪现消息?还是有一个更强大的选项可用来找出出现问题时发生的情况?

How are you meant to debug errors in Flask? Print to the console? Flash messages to the page? Or is there a more powerful option available to figure out what’s happening when something goes wrong?


回答 0

出现错误时,以开发模式运行该应用程序将在浏览器中显示交互式回溯和控制台。要在开发模式下运行,请设置FLASK_ENV=development环境变量,然后使用flask run命令(请记住也指向FLASK_APP您的应用程序)。

对于Linux,Mac,Windows的Linux子系统,Windows的Git Bash等:

export FLASK_APP=myapp
export FLASK_ENV=development
flask run

对于Windows CMD,使用set而不是导出:

set FLASK_ENV=development

对于PowerShell,请使用$env

$env:FLASK_ENV = "development"

在Flask 1.0之前,它是由FLASK_DEBUG=1环境变量控制的。

如果您使用的是app.run()方法而不是flask run命令,请传递debug=True以启用调试模式。

不管开发模式如何,都将回溯打印到运行服务器的终端。

如果您使用的是PyCharm,VS Code等,则可以利用其调试器逐步使用带有断点的代码。运行配置可以指向调用app.run(debug=True, use_reloader=False)venv/bin/flask脚本,也可以将其指向脚本并像在命令行中一样使用它。您可以禁用重新加载器,但是重新加载将终止调试上下文,并且您将不得不再次捕获断点。

您还可以通过set_trace在要开始调试的视图中调用来使用pdb,pudb或其他终端调试器。


确保不要使用太宽的积木。将所有代码都包含在“包罗万象”中try... except...将使您想要调试的错误静音。一般来说,这是不必要的,因为Flask已经可以通过显示调试器或500错误并将回溯打印到控制台来处理异常。

Running the app in development mode will show an interactive traceback and console in the browser when there is an error. To run in development mode, set the FLASK_ENV=development environment variable then use the flask run command (remember to point FLASK_APP to your app as well).

For Linux, Mac, Linux Subsystem for Windows, Git Bash on Windows, etc.:

export FLASK_APP=myapp
export FLASK_ENV=development
flask run

For Windows CMD, use set instead of export:

set FLASK_ENV=development

For PowerShell, use $env:

$env:FLASK_ENV = "development"

Prior to Flask 1.0, this was controlled by the FLASK_DEBUG=1 environment variable instead.

If you’re using the app.run() method instead of the flask run command, pass debug=True to enable debug mode.

Tracebacks are also printed to the terminal running the server, regardless of development mode.

If you’re using PyCharm, VS Code, etc., you can take advantage of its debugger to step through the code with breakpoints. The run configuration can point to a script calling app.run(debug=True, use_reloader=False), or point it at the venv/bin/flask script and use it as you would from the command line. You can leave the reloader disabled, but a reload will kill the debugging context and you will have to catch a breakpoint again.

You can also use pdb, pudb, or another terminal debugger by calling set_trace in the view where you want to start debugging.


Be sure not to use too-broad except blocks. Surrounding all your code with a catch-all try... except... will silence the error you want to debug. It’s unnecessary in general, since Flask will already handle exceptions by showing the debugger or a 500 error and printing the traceback to the console.


回答 1

您可以按如下所述app.run(debug=True)用于Werkzeug调试器 编辑,我应该知道。

You can use app.run(debug=True) for the Werkzeug Debugger edit as mentioned below, and I should have known.


回答 2

1.1.x文档中,您可以通过将环境变量导出到Shell提示符来启用调试模式:

export FLASK_APP=/daemon/api/views.py  # path to app
export FLASK_DEBUG=1
python -m flask run --host=0.0.0.0

From the 1.1.x documentation, you can enable debug mode by exporting an environment variable to your shell prompt:

export FLASK_APP=/daemon/api/views.py  # path to app
export FLASK_DEBUG=1
python -m flask run --host=0.0.0.0

回答 3

人们还可以使用Flask Debug Toolbar扩展程序来获取嵌入在渲染页面中的更多详细信息。

from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension
import logging

app = Flask(__name__)
app.debug = True
app.secret_key = 'development key'

toolbar = DebugToolbarExtension(app)

@app.route('/')
def index():
    logging.warning("See this message in Flask Debug Toolbar!")
    return "<html><body></body></html>"

启动应用程序,如下所示:

FLASK_APP=main.py FLASK_DEBUG=1 flask run

One can also use the Flask Debug Toolbar extension to get more detailed information embedded in rendered pages.

from flask import Flask
from flask_debugtoolbar import DebugToolbarExtension
import logging

app = Flask(__name__)
app.debug = True
app.secret_key = 'development key'

toolbar = DebugToolbarExtension(app)

@app.route('/')
def index():
    logging.warning("See this message in Flask Debug Toolbar!")
    return "<html><body></body></html>"

Start the application as follows:

FLASK_APP=main.py FLASK_DEBUG=1 flask run

回答 4

如果您使用的是Visual Studio Code,请替换

app.run(debug=True)

app.run()

当打开内部调试器禁用VS Code调试器时,它会出现。

If you’re using Visual Studio Code, replace

app.run(debug=True)

with

app.run()

It appears when turning on the internal debugger disables the VS Code debugger.


回答 5

如果要调试flask应用程序,则只需转到flask应用程序所在的文件夹。不要忘了激活您的虚拟环境,并将控制台行中的行更改“ mainfilename”粘贴到flask主文件。

export FLASK_APP="mainfilename.py"
export FLASK_DEBUG=1
python -m flask run --host=0.0.0.0

启用flask应用程序的调试器后,几乎所有错误都会打印在控制台或浏览器窗口上。如果您想弄清楚发生了什么,可以使用简单的打印语句,也可以将console.log()用于javascript代码。

If you want to debug your flask app then just go to the folder where flask app is. Don’t forget to activate your virtual environment and paste the lines in the console change “mainfilename” to flask main file.

export FLASK_APP="mainfilename.py"
export FLASK_DEBUG=1
python -m flask run --host=0.0.0.0

After you enable your debugger for flask app almost every error will be printed on the console or on the browser window. If you want to figure out what’s happening, you can use simple print statements or you can also use console.log() for javascript code.


回答 6

python-dotenv在虚拟环境中安装。

在项目根目录中创建一个.flaskenv。用项目根目录,是指包含您的app.py文件的文件夹

在此文件中写入以下内容:

FLASK_APP=myapp 
FLASK_ENV=development

现在发出以下命令:

flask run

Install python-dotenv in your virtual environment.

Create a .flaskenv in your project root. By project root, I mean the folder which has your app.py file

Inside this file write the following:

FLASK_APP=myapp 
FLASK_ENV=development

Now issue the following command:

flask run

回答 7

要在Flask中激活调试模式,您只需FLASK_DEBUG=1CMDWindows 上键入set 并FLASK_DEBUG=1在Linux terminal上导出,然后重新启动您的应用程序就可以了!

To activate debug mode in flask you simply type set FLASK_DEBUG=1 on your CMD for windows and export FLASK_DEBUG=1 on Linux termial then restart your app and you are good to go!!


回答 8

快速提示-如果您使用的是PyCharm,请转到Edit Configurations=> Configurations并启用FLASK_DEBUG复选框,然后重新启动Run

Quick tip – if you use a PyCharm, go to Edit Configurations => Configurations and enable FLASK_DEBUG checkbox, restart the Run.


回答 9

在开发环境中使用记录器和打印语句,在生产环境中可以进行岗哨。

Use loggers and print statements in the Development Environment, you can go for sentry in case of production environments.


回答 10

对于Windows用户:

打开Powershell并cd进入您的项目目录。

在Powershell中使用这些突击队,其他所有东西在Powershell中将无法使用。

$env:FLASK_APP = "app"  
$env:FLASK_ENV = "development"

For Windows users:

Open Powershell and cd into your project directory.

Use these commandos in Powershell, all the other stuff won’t work in Powershell.

$env:FLASK_APP = "app"  
$env:FLASK_ENV = "development"

回答 11

如果您在本地运行它并希望能够逐步执行代码:

python -m pdb script.py

If you are running it locally and want to be able to step through the code:

python -m pdb script.py


Python 3.0、3.1、3.2中的“ ValueError:格式为零长度的字段名称”错误

问题:Python 3.0、3.1、3.2中的“ ValueError:格式为零长度的字段名称”错误

我正在尝试学习Python(具体来说是3),并且遇到了以下错误:

ValueError: zero length field name in format

我用谷歌搜索,发现需要指定数字:

a, b = 0, 1
if a < b:
     print('a ({0}) is less than b ({1})'.format(a, b))
else:
     print('a ({0}) is not less than b ({1})'.format(a, b))

而且不像本教程(来自lynda.com)实际所说的那样:

a, b = 0, 1
if a < b:
     print('a ({}) is less than b ({})'.format(a, b))
else:
     print('a ({}) is not less than b ({})'.format(a, b))

以下教程即时消息具有Python 3.1,即时消息使用3.2,而我读到的有关此错误的信息是,此错误仅发生在<3.1(3.0)中。他们在3.2中撤消了此操作,还是我做错了什么?

另外,说慢点;)从字面上看,这是我第一次学习Python,只是我用Python编写的第二个“脚本”。

I’m trying learn Python (3 to be more specific) and I’m getting this error:

ValueError: zero length field name in format

I googled it and I found out you need to specify the numbers:

a, b = 0, 1
if a < b:
     print('a ({0}) is less than b ({1})'.format(a, b))
else:
     print('a ({0}) is not less than b ({1})'.format(a, b))

And not like the tutorial (from lynda.com) actually says to do:

a, b = 0, 1
if a < b:
     print('a ({}) is less than b ({})'.format(a, b))
else:
     print('a ({}) is not less than b ({})'.format(a, b))

The tutorial im following has Python 3.1, and im using 3.2 and what i read about this error is that this only happens in <3.1 (3.0). Did they undo this in 3.2, or am i doing something wrong?

Also, speak slowly ;) this is literally my first night learning Python and only the 2nd “script” i’ve written in Python.


回答 0

我会猜测您偶然以某种方式运行了python 2.6。

如果您使用的是python 3,则此功能至少适用于3.1;如果您使用的是python 2,则此功能仅适用于2.7。

I’m gonna guess that you are running python 2.6 by accident somehow.

This feature is only available for at least 3.1 if you are using python 3, or 2.7 if you are using python 2.


回答 1

Python 2.6和3.0需要字段编号。在Python 2.7和更高版本以及3.1和更高版本中,可以忽略它们。

在2.7版中进行了更改:可以省略位置参数说明符,因此'{} {}’等同于'{0} {1}’。

python2.6.4>>> print '|{0:^12}|{1:^12}|'.format(3,4)
|     3      |     4     |

Python 2.6 and 3.0 require the field numbers. In Python 2.7 and later and 3.1 and later, they can be omitted.

Changed in version 2.7: The positional argument specifiers can be omitted, so ‘{} {}’ is equivalent to ‘{0} {1}’.

python2.6.4>>> print '|{0:^12}|{1:^12}|'.format(3,4)
|     3      |     4     |

回答 2

如果您使用的是Eclipse,则应查看Window-> Preferences-> PyDev-> Interpreter-Python。那里有口译员的名单(包括姓名和位置)。如果对于当前项目,您正在使用例如位于/ usr / bin / python中的解释器,则可能执行/ usr / bin / python -V whill会给您类似“ Python 2.6.6”的信息。就像Winston Ewert所写的那样,您的答案是正确的。

(您可以通过单击“新建…”按钮并在/ usr / bin / python3中将其添加为“位置”来添加新的交互程序。然后,您可能必须更改项目设置(首选项-> PyDev-解释器/语法)。

If you’re using Eclipse you should look into Window -> Preferences -> PyDev -> Interpreter – Python. There you have a list of interpreters (with name and location). If for your current project you’re using interpreter which is located for example in /usr/bin/python then probably executing /usr/bin/python -V whill give you something like “Python 2.6.6”. And there is your answer like Winston Ewert wrote.

(you can add new interperter by simply clicking “New…” button and giving /usr/bin/python3 as “location”. Then you have probably to change your project settings (Preferences -> PyDev – Interpreter/Grammar).


python脚本的文件名和行号

问题:python脚本的文件名和行号

如何在python脚本中获取文件名和行号。

正是从异常回溯中获得的文件信息。在这种情况下不会引发异常。

How can I get the file name and line number in python script.

Exactly the file information we get from an exception traceback. In this case without raising an exception.


回答 0

感谢mcandre,答案是:

#python3
from inspect import currentframe, getframeinfo

frameinfo = getframeinfo(currentframe())

print(frameinfo.filename, frameinfo.lineno)

Thanks to mcandre, the answer is:

#python3
from inspect import currentframe, getframeinfo

frameinfo = getframeinfo(currentframe())

print(frameinfo.filename, frameinfo.lineno)

回答 1

是否使用currentframe().f_back取决于是否使用功能。

直接调用检查:

from inspect import currentframe, getframeinfo

cf = currentframe()
filename = getframeinfo(cf).filename

print "This is line 5, python says line ", cf.f_lineno 
print "The filename is ", filename

调用为您执行此操作的函数:

from inspect import currentframe

def get_linenumber():
    cf = currentframe()
    return cf.f_back.f_lineno

print "This is line 7, python says line ", get_linenumber()

Whether you use currentframe().f_back depends on whether you are using a function or not.

Calling inspect directly:

from inspect import currentframe, getframeinfo

cf = currentframe()
filename = getframeinfo(cf).filename

print "This is line 5, python says line ", cf.f_lineno 
print "The filename is ", filename

Calling a function that does it for you:

from inspect import currentframe

def get_linenumber():
    cf = currentframe()
    return cf.f_back.f_lineno

print "This is line 7, python says line ", get_linenumber()

回答 2

如果在公用文件中使用,则非常方便-打印文件名,行号和调用方法的功能:

import inspect
def getLineInfo():
    print(inspect.stack()[1][1],":",inspect.stack()[1][2],":",
          inspect.stack()[1][3])

Handy if used in a common file – prints file name, line number and function of the caller:

import inspect
def getLineInfo():
    print(inspect.stack()[1][1],":",inspect.stack()[1][2],":",
          inspect.stack()[1][3])

回答 3

档案名称

__file__
# or
sys.argv[0]

线

inspect.currentframe().f_lineno

(不是inspect.currentframe().f_back.f_lineno上面提到的)

Filename:

__file__
# or
sys.argv[0]

Line:

inspect.currentframe().f_lineno

(not inspect.currentframe().f_back.f_lineno as mentioned above)


回答 4

最好也使用sys-

print dir(sys._getframe())
print dir(sys._getframe().f_lineno)
print sys._getframe().f_lineno

输出为:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'f_back', 'f_builtins', 'f_code', 'f_exc_traceback', 'f_exc_type', 'f_exc_value', 'f_globals', 'f_lasti', 'f_lineno', 'f_locals', 'f_restricted', 'f_trace']
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
14

Better to use sys also-

print dir(sys._getframe())
print dir(sys._getframe().f_lineno)
print sys._getframe().f_lineno

The output is:

['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'f_back', 'f_builtins', 'f_code', 'f_exc_traceback', 'f_exc_type', 'f_exc_value', 'f_globals', 'f_lasti', 'f_lineno', 'f_locals', 'f_restricted', 'f_trace']
['__abs__', '__add__', '__and__', '__class__', '__cmp__', '__coerce__', '__delattr__', '__div__', '__divmod__', '__doc__', '__float__', '__floordiv__', '__format__', '__getattribute__', '__getnewargs__', '__hash__', '__hex__', '__index__', '__init__', '__int__', '__invert__', '__long__', '__lshift__', '__mod__', '__mul__', '__neg__', '__new__', '__nonzero__', '__oct__', '__or__', '__pos__', '__pow__', '__radd__', '__rand__', '__rdiv__', '__rdivmod__', '__reduce__', '__reduce_ex__', '__repr__', '__rfloordiv__', '__rlshift__', '__rmod__', '__rmul__', '__ror__', '__rpow__', '__rrshift__', '__rshift__', '__rsub__', '__rtruediv__', '__rxor__', '__setattr__', '__sizeof__', '__str__', '__sub__', '__subclasshook__', '__truediv__', '__trunc__', '__xor__', 'bit_length', 'conjugate', 'denominator', 'imag', 'numerator', 'real']
14

回答 5

只是为了贡献,

linecachepython中有一个模块,这里有两个链接可以提供帮助。

linecache模块文档
linecache源代码

从某种意义上讲,您可以将整个文件“转储”到其缓存中,并使用class中的linecache.cache数据读取它。

import linecache as allLines
## have in mind that fileName in linecache behaves as any other open statement, you will need a path to a file if file is not in the same directory as script
linesList = allLines.updatechache( fileName ,None)
for i,x in enumerate(lineslist): print(i,x) #prints the line number and content
#or for more info
print(line.cache)
#or you need a specific line
specLine = allLines.getline(fileName,numbOfLine)
#returns a textual line from that number of line

对于其他信息,为了进行错误处理,您可以简单地使用

from sys import exc_info
try:
     raise YourError # or some other error
except Exception:
     print(exc_info() )

Just to contribute,

there is a linecache module in python, here is two links that can help.

linecache module documentation
linecache source code

In a sense, you can “dump” a whole file into its cache , and read it with linecache.cache data from class.

import linecache as allLines
## have in mind that fileName in linecache behaves as any other open statement, you will need a path to a file if file is not in the same directory as script
linesList = allLines.updatechache( fileName ,None)
for i,x in enumerate(lineslist): print(i,x) #prints the line number and content
#or for more info
print(line.cache)
#or you need a specific line
specLine = allLines.getline(fileName,numbOfLine)
#returns a textual line from that number of line

For additional info, for error handling, you can simply use

from sys import exc_info
try:
     raise YourError # or some other error
except Exception:
     print(exc_info() )

回答 6

import inspect    

file_name = __FILE__
current_line_no = inspect.stack()[0][2]
current_function_name = inspect.stack()[0][3]

#Try printing inspect.stack() you can see current stack and pick whatever you want 
import inspect    

file_name = __FILE__
current_line_no = inspect.stack()[0][2]
current_function_name = inspect.stack()[0][3]

#Try printing inspect.stack() you can see current stack and pick whatever you want 

回答 7

在Python 3中,您可以在以下方面使用变体:

def Deb(msg = None):
  print(f"Debug {sys._getframe().f_back.f_lineno}: {msg if msg is not None else ''}")

在代码中,您可以使用:

Deb("Some useful information")
Deb()

生产:

123: Some useful information
124:

其中123和124是进行呼叫的线路。

In Python 3 you can use a variation on:

def Deb(msg = None):
  print(f"Debug {sys._getframe().f_back.f_lineno}: {msg if msg is not None else ''}")

In code, you can then use:

Deb("Some useful information")
Deb()

To produce:

123: Some useful information
124:

Where the 123 and 124 are the lines that the calls are made from.


回答 8

dmsg是我在VSCode 1.39.2中在Python 3.7.3中获取行号的方法(这是我的调试消息助记符):

import inspect

def dmsg(text_s):
    print (str(inspect.currentframe().f_back.f_lineno) + '| ' + text_s)

调用显示变量name_s及其值:

name_s = put_code_here
dmsg('name_s: ' + name_s)

输出看起来像这样:

37| name_s: value_of_variable_at_line_37

Here’s what works for me to get the line number in Python 3.7.3 in VSCode 1.39.2 (dmsg is my mnemonic for debug message):

import inspect

def dmsg(text_s):
    print (str(inspect.currentframe().f_back.f_lineno) + '| ' + text_s)

To call showing a variable name_s and its value:

name_s = put_code_here
dmsg('name_s: ' + name_s)

Output looks like this:

37| name_s: value_of_variable_at_line_37

从异常对象中提取回溯信息

问题:从异常对象中提取回溯信息

给定一个Exception对象(来源不明),有没有办法获取其回溯?我有这样的代码:

def stuff():
   try:
       .....
       return useful
   except Exception as e:
       return e

result = stuff()
if isinstance(result, Exception):
    result.traceback <-- How?

获得异常后,如何从Exception对象中提取回溯?

Given an Exception object (of unknown origin) is there way to obtain its traceback? I have code like this:

def stuff():
   try:
       .....
       return useful
   except Exception as e:
       return e

result = stuff()
if isinstance(result, Exception):
    result.traceback <-- How?

How can I extract the traceback from the Exception object once I have it?


回答 0

这个问题的答案取决于您使用的Python版本。

在Python 3中

很简单:异常附带了一个__traceback__包含回溯的属性。此属性也是可写的,并且可以使用with_traceback异常方法方便地设置:

raise Exception("foo occurred").with_traceback(tracebackobj)

这些功能在raise文档中作了最少描述。

这部分答案应归功于Vyctor,后者首先发布了此信息。我之所以将其包含在此处,仅是因为此答案停留在顶部,并且Python 3变得越来越普遍。

在Python 2中

这很烦人。回溯的麻烦在于它们具有对堆栈框架的引用,而堆栈框架具有对回溯的引用,这些回溯具有对引用了…的堆栈框架的引用。这给垃圾收集器带来了问题。(感谢ecatmur首先指出这一点。)

解决此问题的一种好方法是在离开该子句后以手术方式中断循环except,这就是Python 3所做的。Python 2解决方案更加丑陋:为您提供了一个即席函数sys.exc_info(),该函数仅在 except 子句中有效。它返回一个包含异常,异常类型和当前正在处理的异常的回溯的元组。

因此,如果您在except子句中,则可以将的输出sys.exc_info()traceback模块一起使用来做各种有用的事情:

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

但是,随着您的编辑表示,你正在试图获得该回溯,如果你的异常没有被处理的已打印,它之后已经被处理。这个问题要难得多。不幸的是,在不处理任何异常时sys.exc_info返回(None, None, None)。其他相关sys属性也无济于事。sys.exc_traceback不处理任何异常时不推荐使用且未定义;sys.last_traceback似乎很完美,但似乎仅在交互式会话中定义。

如果可以控制如何引发异常,则可以使用inspect自定义异常来存储某些信息。但是我不完全确定那将如何工作。

实话实说,捕获并返回异常是一件不寻常的事情。这可能表明您仍然需要进行重构。

The answer to this question depends on the version of Python you’re using.

In Python 3

It’s simple: exceptions come equipped with a __traceback__ attribute that contains the traceback. This attribute is also writable, and can be conveniently set using the with_traceback method of exceptions:

raise Exception("foo occurred").with_traceback(tracebackobj)

These features are minimally described as part of the raise documentation.

All credit for this part of the answer should go to Vyctor, who first posted this information. I’m including it here only because this answer is stuck at the top, and Python 3 is becoming more common.

In Python 2

It’s annoyingly complex. The trouble with tracebacks is that they have references to stack frames, and stack frames have references to the tracebacks that have references to stack frames that have references to… you get the idea. This causes problems for the garbage collector. (Thanks to ecatmur for first pointing this out.)

The nice way of solving this would be to surgically break the cycle after leaving the except clause, which is what Python 3 does. The Python 2 solution is much uglier: you are provided with an ad-hoc function,sys.exc_info(), which only works inside the except clause. It returns a tuple containing the exception, the exception type, and the traceback for whatever exception is currently being handled.

So if you are inside the except clause, you can use the output of sys.exc_info() along with the traceback module to do various useful things:

>>> import sys, traceback
>>> def raise_exception():
...     try:
...         raise Exception
...     except Exception:
...         ex_type, ex, tb = sys.exc_info()
...         traceback.print_tb(tb)
...     finally:
...         del tb
... 
>>> raise_exception()
  File "<stdin>", line 3, in raise_exception

But as your edit indicates, you’re trying to get the traceback that would have been printed if your exception had not been handled, after it has already been handled. That’s a much harder question. Unfortunately, sys.exc_info returns (None, None, None) when no exception is being handled. Other related sys attributes don’t help either. sys.exc_traceback is deprecated and undefined when no exception is being handled; sys.last_traceback seems perfect, but it appears only to be defined during interactive sessions.

If you can control how the exception is raised, you might be able to use inspect and a custom exception to store some of the information. But I’m not entirely sure how that would work.

To tell the truth, catching and returning an exception is kind of an unusual thing to do. This might be a sign that you need to refactor anyway.


回答 1

Python 3.0 [PEP 3109]开始,内置类Exception具有__traceback__包含的属性traceback object(对于Python 3.2.3):

>>> try:
...     raise Exception()
... except Exception as e:
...     tb = e.__traceback__
...
>>> tb
<traceback object at 0x00000000022A9208>

问题是,在谷歌搜索__traceback__一段时间后,我发现只有几篇文章,但是没有一篇描述您是否或为什么应该使用__traceback__

但是,针对的Python 3文档raise指出:

通常会在引发异常并将其附加__traceback__为可写属性的情况下自动创建回溯对象。

因此,我认为它应该被使用。

Since Python 3.0[PEP 3109] the built in class Exception has a __traceback__ attribute which contains a traceback object (with Python 3.2.3):

>>> try:
...     raise Exception()
... except Exception as e:
...     tb = e.__traceback__
...
>>> tb
<traceback object at 0x00000000022A9208>

The problem is that after Googling __traceback__ for a while I found only few articles but none of them describes whether or why you should (not) use __traceback__.

However, the Python 3 documentation for raise says that:

A traceback object is normally created automatically when an exception is raised and attached to it as the __traceback__ attribute, which is writable.

So I assume it’s meant to be used.


回答 2

一种从Python 3中的异常对象以字符串形式获取回溯的方法:

import traceback

# `e` is an exception object that you get from somewhere
traceback_str = ''.join(traceback.format_tb(e.__traceback__))

traceback.format_tb(...)返回字符串列表。''.join(...)将他们连接在一起。有关更多参考,请访问:https : //docs.python.org/3/library/traceback.html#traceback.format_tb

A way to get traceback as a string from an exception object in Python 3:

import traceback

# `e` is an exception object that you get from somewhere
traceback_str = ''.join(traceback.format_tb(e.__traceback__))

traceback.format_tb(...) returns a list of strings. ''.join(...) joins them together. For more reference, please visit: https://docs.python.org/3/library/traceback.html#traceback.format_tb


回答 3

顺便说一句,如果您希望像在终端上看到的那样真正获得完整的追溯,则需要这样做:

>>> try:
...     print(1/0)
... except Exception as e:
...     exc = e
...
>>> exc
ZeroDivisionError('division by zero')
>>> tb_str = traceback.format_exception(etype=type(exc), value=exc, tb=exc.__traceback__)
>>> tb_str
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: division by zero\n']
>>> print("".join(tb_str))
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

如果您使用format_tb上述答案,则建议您获得的信息较少:

>>> tb_str = "".join(traceback.format_tb(exc.__traceback__))
>>> print("".join(tb_str))
  File "<stdin>", line 2, in <module>

As an aside, if you want to actually get the full traceback as you would see it printed to your terminal, you want this:

>>> try:
...     print(1/0)
... except Exception as e:
...     exc = e
...
>>> exc
ZeroDivisionError('division by zero')
>>> tb_str = traceback.format_exception(etype=type(exc), value=exc, tb=exc.__traceback__)
>>> tb_str
['Traceback (most recent call last):\n', '  File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: division by zero\n']
>>> print("".join(tb_str))
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
ZeroDivisionError: division by zero

If you use format_tb as above answers suggest you’ll get less information:

>>> tb_str = "".join(traceback.format_tb(exc.__traceback__))
>>> print("".join(tb_str))
  File "<stdin>", line 2, in <module>

回答 4

有一个很好的理由是,回溯不存储在异常中。因为回溯保留对堆栈本地的引用,所以这将导致循环引用和(临时)内存泄漏,直到循环GC启动。(这就是为什么永远不要将回溯存储在局部变量中的原因。)

关于我,我唯一想到的就是您可以进行修补 stuff的全局变量,以便当它认为正在捕获时Exception,实际上是在捕获特殊类型,并且异常作为调用者传播给您:

module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
    stuff()
except Exception:
    import sys
    print sys.exc_info()

There’s a very good reason the traceback is not stored in the exception; because the traceback holds references to its stack’s locals, this would result in a circular reference and (temporary) memory leak until the circular GC kicks in. (This is why you should never store the traceback in a local variable.)

About the only thing I can think of would be for you to monkeypatch stuff‘s globals so that when it thinks it’s catching Exception it’s actually catching a specialised type and the exception propagates to you as the caller:

module_containing_stuff.Exception = type("BogusException", (Exception,), {})
try:
    stuff()
except Exception:
    import sys
    print sys.exc_info()

如何使用PyCharm调试Scrapy项目

问题:如何使用PyCharm调试Scrapy项目

我正在使用Python 2.7开发Scrapy 0.20。我发现PyCharm具有良好的Python调试器。我想使用它测试我的Scrapy蜘蛛。有人知道该怎么做吗?

我尝试过的

实际上,我尝试将Spider作为脚本运行。结果,我构建了该脚本。然后,我尝试将Scrapy项目添加到PyCharm中,如下所示:
File->Setting->Project structure->Add content root.

但是我不知道我还要做什么

I am working on Scrapy 0.20 with Python 2.7. I found PyCharm has a good Python debugger. I want to test my Scrapy spiders using it. Anyone knows how to do that please?

What I have tried

Actually I tried to run the spider as a script. As a result, I built that script. Then, I tried to add my Scrapy project to PyCharm as a model like this:
File->Setting->Project structure->Add content root.

But I don’t know what else I have to do


回答 0

scrapy命令是python脚本,这意味着您可以从PyCharm内部启动它。

当检查scrapy二进制文件(which scrapy)时,您会注意到这实际上是一个python脚本:

#!/usr/bin/python

from scrapy.cmdline import execute
execute()

这意味着scrapy crawl IcecatCrawler还可以像这样执行命令 :python /Library/Python/2.7/site-packages/scrapy/cmdline.py crawl IcecatCrawler

尝试找到scrapy.cmdline软件包。就我而言,位置在这里:/Library/Python/2.7/site-packages/scrapy/cmdline.py

使用该脚本作为脚本在PyCharm中创建运行/调试配置。用scrapy命令和Spider填充脚本参数。在这种情况下crawl IcecatCrawler

像这样:

将断点放在爬网代码中的任何位置,它应该可以正常工作。

The scrapy command is a python script which means you can start it from inside PyCharm.

When you examine the scrapy binary (which scrapy) you will notice that this is actually a python script:

#!/usr/bin/python

from scrapy.cmdline import execute
execute()

This means that a command like scrapy crawl IcecatCrawler can also be executed like this: python /Library/Python/2.7/site-packages/scrapy/cmdline.py crawl IcecatCrawler

Try to find the scrapy.cmdline package. In my case the location was here: /Library/Python/2.7/site-packages/scrapy/cmdline.py

Create a run/debug configuration inside PyCharm with that script as script. Fill the script parameters with the scrapy command and spider. In this case crawl IcecatCrawler.

Like this:

Put your breakpoints anywhere in your crawling code and it should work™.


回答 1

您只需要这样做。

在项目的搜寻器文件夹上创建一个Python文件。我使用了main.py。

  • 项目
    • 履带式
      • 履带式
        • 蜘蛛网
      • main.py
      • scrapy.cfg

在您的main.py内部,将下面的代码。

from scrapy import cmdline    
cmdline.execute("scrapy crawl spider".split())

并且您需要创建一个“运行配置”以运行您的main.py。

这样做,如果在代码上放置断点,它将在此处停止。

You just need to do this.

Create a Python file on crawler folder on your project. I used main.py.

  • Project
    • Crawler
      • Crawler
        • Spiders
      • main.py
      • scrapy.cfg

Inside your main.py put this code below.

from scrapy import cmdline    
cmdline.execute("scrapy crawl spider".split())

And you need to create a “Run Configuration” to run your main.py.

Doing this, if you put a breakpoint at your code it will stop there.


回答 2

截至2018.1,这变得容易得多。现在Module name,您可以在项目的中进行选择Run/Debug Configuration。将此设置为,scrapy.cmdline并将其设置Working directory为scrapy项目的根目录(其中有一个目录settings.py)。

像这样:

现在,您可以添加断点来调试代码。

As of 2018.1 this became a lot easier. You can now select Module name in your project’s Run/Debug Configuration. Set this to scrapy.cmdline and the Working directory to the root dir of the scrapy project (the one with settings.py in it).

Like so:

Now you can add breakpoints to debug your code.


回答 3

我正在使用Python 3.5.0在virtualenv中运行scrapy,并设置“ script”参数/path_to_project_env/env/bin/scrapy为我解决了该问题。

I am running scrapy in a virtualenv with Python 3.5.0 and setting the “script” parameter to /path_to_project_env/env/bin/scrapy solved the issue for me.


回答 4

intellij的想法也可以。

创建main.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#coding=utf-8
import sys
from scrapy import cmdline
def main(name):
    if name:
        cmdline.execute(name.split())



if __name__ == '__main__':
    print('[*] beginning main thread')
    name = "scrapy crawl stack"
    #name = "scrapy crawl spa"
    main(name)
    print('[*] main thread exited')
    print('main stop====================================================')

显示如下:

intellij idea also work.

create main.py:

#!/usr/bin/env python
# -*- coding: utf-8 -*-
#coding=utf-8
import sys
from scrapy import cmdline
def main(name):
    if name:
        cmdline.execute(name.split())



if __name__ == '__main__':
    print('[*] beginning main thread')
    name = "scrapy crawl stack"
    #name = "scrapy crawl spa"
    main(name)
    print('[*] main thread exited')
    print('main stop====================================================')

show below:


回答 5

要在可接受的答案中添加一点点,将近一个小时后,我发现必须从下拉列表(图标工具栏中央附近)中选择正确的“运行配置”,然后单击“调试”按钮才能使其正常工作。希望这可以帮助!

To add a bit to the accepted answer, after almost an hour I found I had to select the correct Run Configuration from the dropdown list (near the center of the icon toolbar), then click the Debug button in order to get it to work. Hope this helps!


回答 6

我也在使用PyCharm,但没有使用其内置的调试功能。

为了调试,我使用ipdb。我设置了键盘快捷键,可以import ipdb; ipdb.set_trace()在希望断点发生的任何行上插入。

然后,我可以键入n执行下s一条语句,以进入函数,键入任何对象名称以查看其值,更改执行环境,键入c以继续执行…

这非常灵活,可以在PyCharm之外的其他环境中使用,在这些环境中您无法控制执行环境。

只需输入您的虚拟环境,pip install ipdb然后放在import ipdb; ipdb.set_trace()您要暂停执行的行上即可。

I am also using PyCharm, but I am not using its built-in debugging features.

For debugging I am using ipdb. I set up a keyboard shortcut to insert import ipdb; ipdb.set_trace() on any line I want the break point to happen.

Then I can type n to execute the next statement, s to step into a function, type any object name to see its value, alter execution environment, type c to continue execution…

This is very flexible, works in environments other than PyCharm, where you don’t control the execution environment.

Just type in your virtual environment pip install ipdb and place import ipdb; ipdb.set_trace() on a line where you want the execution to pause.

UPDATE

You can also pip install pdbpp and use the standard import pdb; pdb.set_trace instead of ipdb. PDB++ is nicer in my opinion.


回答 7

根据该文件https://doc.scrapy.org/en/latest/topics/practices.html

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

process = CrawlerProcess({
    'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})

process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished

According to the documentation https://doc.scrapy.org/en/latest/topics/practices.html

import scrapy
from scrapy.crawler import CrawlerProcess

class MySpider(scrapy.Spider):
    # Your spider definition
    ...

process = CrawlerProcess({
    'USER_AGENT': 'Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1)'
})

process.crawl(MySpider)
process.start() # the script will block here until the crawling is finished

回答 8

我使用以下简单脚本:

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

process = CrawlerProcess(get_project_settings())

process.crawl('your_spider_name')
process.start()

I use this simple script:

from scrapy.crawler import CrawlerProcess
from scrapy.utils.project import get_project_settings

process = CrawlerProcess(get_project_settings())

process.crawl('your_spider_name')
process.start()

回答 9

扩展了@Rodrigo的答案版本,我添加了此脚本,现在我可以从配置中设置蜘蛛网名称,而不用更改字符串。

import sys
from scrapy import cmdline

cmdline.execute(f"scrapy crawl {sys.argv[1]}".split())

Extending @Rodrigo’s version of the answer I added this script and now I can set spider name from configuration instead of changing in the string.

import sys
from scrapy import cmdline

cmdline.execute(f"scrapy crawl {sys.argv[1]}".split())

如何运行Python程序?

问题:如何运行Python程序?

所以我有点像Python,但是我遇到了问题……运行它。大声笑

我现在正在使用IDLE,但是它没有任何用处,因为您一次只能运行几行。

我还使用Komodo Edit创建实际的.py文件。

我的问题是,如何运行.py文件来测试实际程序?

我正在使用Windows 7和Komodo Edit 5作为我的IDE。在Komodo中按F5根本不起作用。

So I’m starting like Python a bit, but I’m having trouble erm…running it. Lol

I’m using IDLE for now, but its no use whatsoever because you can only run a couple of lines at a time.

I’m also using Komodo Edit to create the actual .py files.

My question is, how can I run the .py files to test out the actual program?

I’m using Windows 7, and Komodo Edit 5 as my IDE. Pressing F5 in Komodo doesn’t do anythin at all.


回答 0

我很高兴你问!我只是在Wikibook中解释这件事(显然是不完整的)。我们正在与Python新手合作,并且必须完全按照您的要求提供一些帮助!

Windows中的命令行Python:

  1. 使用编辑器中的“保存”或“另存为”将python代码文件保存在某处。让我们在某些文件夹中将其称为“ first.py”,例如您在桌面上创建的“ pyscripts”。

  2. 打开提示(Windows’cmd’shell,它是计算机的文本界面):

    开始>运行>“ cmd”(在小框中)。好。

  3. 使用命令“ cd”(更改目录)和“ dir”(显示目录中的文件,以验证您的头)导航到python文件所在的位置。对于我们的示例,

    > CD C:\ Documents and Settings \ Gregg \ Desktop \ pyscripts

  4. 尝试:

    > python first.py

如果收到此消息:

无法将“ python”识别为内部或外部命令,可操作程序或批处理文件。

然后是python解释器可以将Python转换为“计算机指令”程序)不在您的路径上(请参见下面的将Python放入路径中)。然后尝试这样调用它(假设安装在通常位置的Python2.6):

> C:\ Python26 \ python.exe first.py

(高级用户:您可以写出first.py的C:\ Documents and Settings \ Gregg \ Desktop \ pyscripts \ first.py的完整路径,而不是first.py)

将Python放在您的路径上

视窗

为了运行程序,您的操作系统会在各个地方出现,并尝试将您键入的程序/命令的名称与过程中的某些程序进行匹配。

在Windows中:

控制面板>系统>高级> |环境变量| >系统变量->路径

这需要包括:C:\ Python26; (或同等学历)。如果将其放在最前面,它将是第一位。您也可以在末尾添加它,这可能会更好。

然后重新启动提示,并尝试键入“ python”。如果一切正常,您应该收到一个“ >>>”提示。

I’m very glad you asked! I was just working on explaining this very thing in our wikibook (which is obviously incomplete). We’re working with Python novices, and had to help a few through exactly what you’re asking!

Command-line Python in Windows:

  1. Save your python code file somewhere, using “Save” or “Save as” in your editor. Lets call it ‘first.py’ in some folder, like “pyscripts” that you make on your Desktop.

  2. Open a prompt (a Windows ‘cmd’ shell that is a text interface into the computer):

    start > run > “cmd” (in the little box). OK.

  3. Navigate to where your python file is, using the commands ‘cd’ (change directory) and ‘dir’ (to show files in the directory, to verify your head). For our example something like,

    > cd C:\Documents and Settings\Gregg\Desktop\pyscripts

  4. try:

    > python first.py

If you get this message:

‘python’ is not recognized as an internal or external command, operable program or batch file.

then python (the interpreter program that can translate Python into ‘computer instructions’) isn’t on your path (see Putting Python in Your Path below). Then try calling it like this (assuming Python2.6, installed in the usual location):

> C:\Python26\python.exe first.py

(Advanced users: instead of first.py, you could write out first.py’s full path of C:\Documents and Settings\Gregg\Desktop\pyscripts\first.py)

Putting Python In Your Path

Windows

In order to run programs, your operating system looks in various places, and tries to match the name of the program / command you typed with some programs along the way.

In windows:

control panel > system > advanced > |Environmental Variables| > system variables -> Path

this needs to include: C:\Python26; (or equivalent). If you put it at the front, it will be the first place looked. You can also add it at the end, which is possibly saner.

Then restart your prompt, and try typing ‘python’. If it all worked, you should get a “>>>” prompt.


回答 1

你可以打电话

python /path/to/filename.py

You can just call

python /path/to/filename.py

回答 2

在IDLE中按F5

您可以使用IDLE打开您的.py文件,然后按F5键运行它。

您可以使用其他编辑器(如您所说的Komodo)打开同一文件,然后保存并再次按F5。F5与IDLE一起使用(即使使用其他工具完成编辑)。

如果您想根据本文直接从Komodo运行它:在Komodo Edit中执行Python代码,您必须:

  1. 转到工具箱->添加->新命令…
  2. 在顶部字段中输入名称“运行Python文件”
  3. 在“命令”字段中输入以下文本:

    %(python)%F 3.a可选单击“键绑定”选项卡,然后为该命令分配一个键盘命令

  4. 单击确定。

In IDLE press F5

You can open your .py file with IDLE and press F5 to run it.

You can open that same file with other editor ( like Komodo as you said ) save it and press F5 again; F5 works with IDLE ( even when the editing is done with another tool ).

If you want to run it directly from Komodo according to this article: Executing Python Code Within Komodo Edit you have to:

  1. go to Toolbox -> Add -> New Command…
  2. in the top field enter the name ‘Run Python file’
  3. in the ‘Command’ field enter this text:

    %(python) %F 3.a optionall click on the ‘Key Binding’ tab and assign a key command to this command

  4. click Ok.

回答 3

Python本身带有一个编辑器,您可以从“ IDLE文件”>“新建文件”菜单选项进行访问。

将代码写入该文件,将其另存为[filename] .py,然后(在同一文件编辑器窗口中)按F5键执行在IDLE Shell窗口中创建的代码。

注意:到目前为止,这只是我最简单,最直接的方法。

Python itself comes with an editor that you can access from the IDLE File > New File menu option.

Write the code in that file, save it as [filename].py and then (in that same file editor window) press F5 to execute the code you created in the IDLE Shell window.

Note: it’s just been the easiest and most straightforward way for me so far.


回答 4

如果您不想通话filename.py,可以将其添加.PY到PATHEXT中,那样您就可以调用filename

if you dont want call filename.py you can add .PY to the PATHEXT, that way you will just call filename


回答 5

如果这对任何人都有用,则“ python [filename] .py”或“ python.exe [filename.py]”都不适合我,但“ start python [filename] .py”却没有帮助。如果其他任何人在使用前两个命令时遇到问题,请尝试使用后一个命令。

If this helps anyone, neither “python [filename].py” or “python.exe [filename.py]” worked for me, but “start python [filename].py” did. If anyone else is experiencing issues with the former two commands, try the latter one.


回答 6

我刚才所做的是,通过双击打开一个简单的python脚本。我刚刚将一个批处理文件添加到包含脚本的目录中:

@echo off
python exercise.py
pause>nul

(我的系统路径上有python可执行文件。如果不需要,当然要包括其完整路径。)

然后,我可以双击批处理文件来运行脚本。第三行防止脚本结束后立即关闭cmd窗口,因此您可以看到结果。:)完成后,只需关闭命令窗口即可。

What I just did, to open a simple python script by double clicking. I just added a batch file to the directory containing the script:

@echo off
python exercise.py
pause>nul

(I have the python executable on my system path. If not one would need include its complete path of course.)

Then I just can double click on the batch file to run the script. The third line keeps the cmd window from being dismissed as soon as the script ends, so you can see the results. :) When you’re done just close the command window.


回答 7

导航您的文件位置,只需按Shift按钮,然后单击文件名。单击选项卡,Open command window here然后在命令提示符下写入python file_name.py

Navigate your file location just press Shift button and click file name. Click tab Open command window here and write in your command prompt python file_name.py


回答 8

如果要运行#’。py’文件,只需在代码中写入print()即可实际看到它被打印出来。与python IDLE不同,您需要使用print()命令指定要打印的内容。例如。

import os
os.getcwd()
a=[1,2,3,4,5]
name= 'Python'
# Use print() function
print(a)
print(name)

输出[1、2、3、4、5] Python

If you want to run the #’.py’ file just write in print() in your code to actually see it get printed. Unlike python IDLE, you need to specify what you want to print using print() command. For eg.

import os
os.getcwd()
a=[1,2,3,4,5]
name= 'Python'
# Use print() function
print(a)
print(name)

OUTPUT [1, 2, 3, 4, 5] Python


回答 9

我已经尝试了上面列出的许多命令,但是即使将路径设置为包括我安装Python的目录之后,这些命令也没有起作用。

该命令py -3 file.py始终对我有用,如果我想运行Python 2代码,只要Python 2在我的路径中,只需将命令更改为py -2 file.py完美即可。

我正在使用Windows,因此我不太确定此命令是否可以在Linux或Mac上运行,但是值得一试。

I have tried many of the commands listed above, however none worked, even after setting my path to include the directory where I installed Python.

The command py -3 file.py always works for me, and if I want to run Python 2 code, as long as Python 2 is in my path, just changing the command to py -2 file.py works perfectly.

I am using Windows, so I’m not too sure if this command will work on Linux, or Mac, but it’s worth a try.


Python调试技巧

问题:Python调试技巧

您调试Python的最佳秘诀是什么?

请不要只列出特定的调试器而不必说出它实际上可以做什么。

有关

What are your best tips for debugging Python?

Please don’t just list a particular debugger without saying what it can actually do.

Related


回答 0

PDB

您可以使用pdb模块,将pdb.set_trace()其插入任何地方,它将用作断点。

>>> import pdb
>>> a="a string"
>>> pdb.set_trace()
--Return--
> <stdin>(1)<module>()->None
(Pdb) p a
'a string'
(Pdb)

要继续执行,请使用c(或contcontinue)。

可以使用pdb执行任意Python表达式。例如,如果发现错误,则可以更正代码,然后键入一个类型表达式以在运行的代码中产生相同的效果。

ipdb是用于IPython的pdb版本。它允许将pdb与所有IPython功能一起使用,包括制表符补全。

也可以将pdb设置为在未捕获的异常上自动运行

Pydb被编写为Pdb的增强版本。有好处吗?

PDB

You can use the pdb module, insert pdb.set_trace() anywhere and it will function as a breakpoint.

>>> import pdb
>>> a="a string"
>>> pdb.set_trace()
--Return--
> <stdin>(1)<module>()->None
(Pdb) p a
'a string'
(Pdb)

To continue execution use c (or cont or continue).

It is possible to execute arbitrary Python expressions using pdb. For example, if you find a mistake, you can correct the code, then type a type expression to have the same effect in the running code

ipdb is a version of pdb for IPython. It allows the use of pdb with all the IPython features including tab completion.

It is also possible to set pdb to automatically run on an uncaught exception.

Pydb was written to be an enhanced version of Pdb. Benefits?


回答 1

http://pypi.python.org/pypi/pudb,一个基于控制台的全屏Python调试器。

它的目标是以更加轻巧和键盘友好的软件包提供基于GUI的现代调试器的所有优点。PuDB允许您在终端中在编写和测试代码的地方调试代码。如果您使用过出色的(但时至今日仍是古老的)基于DOS的Turbo Pascal或C工具,那么PuDB的UI可能看起来很熟悉。

非常适合调试独立脚本,只需运行

python -m pudb.run my-script.py

http://pypi.python.org/pypi/pudb, a full-screen, console-based Python debugger.

Its goal is to provide all the niceties of modern GUI-based debuggers in a more lightweight and keyboard-friendly package. PuDB allows you to debug code right where you write and test it – in a terminal. If you’ve worked with the excellent (but nowadays ancient) DOS-based Turbo Pascal or C tools, PuDB’s UI might look familiar.

Nice for debugging standalone scripts, just run

python -m pudb.run my-script.py

回答 2

如果使用的是pdb,则可以定义快捷方式的别名。我用这些:

# Ned's .pdbrc

# Print a dictionary, sorted. %1 is the dict, %2 is the prefix for the names.
alias p_ for k in sorted(%1.keys()): print "%s%-15s= %-80.80s" % ("%2",k,repr(%1[k]))

# Print the instance variables of a thing.
alias pi p_ %1.__dict__ %1.

# Print the instance variables of self.
alias ps pi self

# Print the locals.
alias pl p_ locals() local:

# Next and list, and step and list.
alias nl n;;l
alias sl s;;l

# Short cuts for walking up and down the stack
alias uu u;;u
alias uuu u;;u;;u
alias uuuu u;;u;;u;;u
alias uuuuu u;;u;;u;;u;;u
alias dd d;;d
alias ddd d;;d;;d
alias dddd d;;d;;d;;d
alias ddddd d;;d;;d;;d;;d

If you are using pdb, you can define aliases for shortcuts. I use these:

# Ned's .pdbrc

# Print a dictionary, sorted. %1 is the dict, %2 is the prefix for the names.
alias p_ for k in sorted(%1.keys()): print "%s%-15s= %-80.80s" % ("%2",k,repr(%1[k]))

# Print the instance variables of a thing.
alias pi p_ %1.__dict__ %1.

# Print the instance variables of self.
alias ps pi self

# Print the locals.
alias pl p_ locals() local:

# Next and list, and step and list.
alias nl n;;l
alias sl s;;l

# Short cuts for walking up and down the stack
alias uu u;;u
alias uuu u;;u;;u
alias uuuu u;;u;;u;;u
alias uuuuu u;;u;;u;;u;;u
alias dd d;;d
alias ddd d;;d;;d
alias dddd d;;d;;d;;d
alias ddddd d;;d;;d;;d;;d

回答 3

记录中

Python已经有一个出色的内置日志记录模块。您可能要在此处使用日志记录模板

日志记录模块使您可以指定重要性级别;在调试期间,您可以记录所有内容,而在正常操作期间,您可能仅记录重要的内容。您可以关闭然后再打开。

大多数人只是使用基本的打印语句进行调试,然后删除打印语句。最好保留它们,但禁用它们;然后,当您遇到另一个错误时,只需重新启用所有功能并查看日志即可。

这是调试需要快速执行操作的程序的最佳方法,例如需要在网络连接的另一端超时并消失之前进行响应的网络程序。您可能没有太多时间单步调试器。但是您可以让代码运行并记录所有内容,然后仔细查看日志并弄清实际情况。

编辑:模板的原始URL为:http : //aymanh.com/python-debugging-techniques

该页面丢失了,因此我将其替换为对保存在archive.org上的快照的引用:http ://web.archive.org/web/20120819135307/http: //aymanh.com/python-debugging-techniques

万一它再次消失,这是我提到的模板。这是从博客获取的代码;我没写

import logging
import optparse

LOGGING_LEVELS = {'critical': logging.CRITICAL,
                  'error': logging.ERROR,
                  'warning': logging.WARNING,
                  'info': logging.INFO,
                  'debug': logging.DEBUG}

def main():
  parser = optparse.OptionParser()
  parser.add_option('-l', '--logging-level', help='Logging level')
  parser.add_option('-f', '--logging-file', help='Logging file name')
  (options, args) = parser.parse_args()
  logging_level = LOGGING_LEVELS.get(options.logging_level, logging.NOTSET)
  logging.basicConfig(level=logging_level, filename=options.logging_file,
                      format='%(asctime)s %(levelname)s: %(message)s',
                      datefmt='%Y-%m-%d %H:%M:%S')

  # Your program goes here.
  # You can access command-line arguments using the args variable.

if __name__ == '__main__':
  main()

这是他对上述用法的解释。同样,我对此没有功劳:


默认情况下,日志记录模块会打印严重,错误和警告消息。要更改此设置以打印所有级别,请使用:

$ ./your-program.py --logging=debug

要将日志消息发送到名为debug.log的文件,请使用:

$ ./your-program.py --logging-level=debug --logging-file=debug.log

Logging

Python already has an excellent built-in logging module. You may want to use the logging template here.

The logging module lets you specify a level of importance; during debugging you can log everything, while during normal operation you might only log critical things. You can switch things off and on.

Most people just use basic print statements to debug, and then remove the print statements. It’s better to leave them in, but disable them; then, when you have another bug, you can just re-enable everything and look your logs over.

This can be the best possible way to debug programs that need to do things quickly, such as networking programs that need to respond before the other end of the network connection times out and goes away. You might not have much time to single-step a debugger; but you can just let your code run, and log everything, then pore over the logs and figure out what’s really happening.

EDIT: The original URL for the templates was: http://aymanh.com/python-debugging-techniques

This page is missing so I replaced it with a reference to the snapshot saved at archive.org: http://web.archive.org/web/20120819135307/http://aymanh.com/python-debugging-techniques

In case it disappears again, here are the templates I mentioned. This is code taken from the blog; I didn’t write it.

import logging
import optparse

LOGGING_LEVELS = {'critical': logging.CRITICAL,
                  'error': logging.ERROR,
                  'warning': logging.WARNING,
                  'info': logging.INFO,
                  'debug': logging.DEBUG}

def main():
  parser = optparse.OptionParser()
  parser.add_option('-l', '--logging-level', help='Logging level')
  parser.add_option('-f', '--logging-file', help='Logging file name')
  (options, args) = parser.parse_args()
  logging_level = LOGGING_LEVELS.get(options.logging_level, logging.NOTSET)
  logging.basicConfig(level=logging_level, filename=options.logging_file,
                      format='%(asctime)s %(levelname)s: %(message)s',
                      datefmt='%Y-%m-%d %H:%M:%S')

  # Your program goes here.
  # You can access command-line arguments using the args variable.

if __name__ == '__main__':
  main()

And here is his explanation of how to use the above. Again, I don’t get the credit for this:


By default, the logging module prints critical, error and warning messages. To change this so that all levels are printed, use:

$ ./your-program.py --logging=debug

To send log messages to a file called debug.log, use:

$ ./your-program.py --logging-level=debug --logging-file=debug.log


回答 4

可以打印执行了哪些Python行(感谢Geo!)。它具有许多应用程序,例如,您可以对其进行修改以检查何时调用了特定功能,或者添加诸如##之类的内容使其仅跟踪特定行。

code.interact带您进入交互式控制台

import code; code.interact(local=locals())

如果您希望能够轻松访问控制台历史记录,请查看:“ 我可以在shell中使用历史记录机制吗? ”(将不得不查找它)。

可以为解释器启用自动完成功能。

It is possible to print what Python lines are executed (thanks Geo!). This has any number of applications, for example, you could modify it to check when particular functions are called or add something like ## make it only track particular lines.

code.interact takes you into a interactive console

import code; code.interact(local=locals())

If you want to be able to easily access your console history look at: “Can I have a history mechanism like in the shell?” (will have to look down for it).

Auto-complete can be enabled for the interpreter.


回答 5

ipdb就像pdb一样,具有ipython的强大功能。

ipdb is like pdb, with the awesomeness of ipython.


回答 6

print 陈述

  • 有人建议使用debug_print功能而不是打印功能来轻松禁用
  • pprint模块对于复杂的结构是无价的

print statements

  • Some people recommend a debug_print function instead of print for easy disabling
  • The pprint module is invaluable for complex structures

回答 7

调试脚本的明显方法

python -m pdb script.py
  • 该脚本引发异常时很有用
  • 当使用virtualenv和pdb命令未与venvs python版本一起运行时很有用。

如果您不确切知道该脚本在哪里

python -m pdb ``which <python-script-name>``

the obvious way to debug a script

python -m pdb script.py
  • useful when that script raises an exception
  • useful when using virtualenv and pdb command is not running with the venvs python version.

if you don’t know exactly where that script is

python -m pdb ``which <python-script-name>``

回答 8

佩德夫

PyDev有一个很好的交互式调试器。它具有监视表达式,求值悬停,线程和堆栈列表,以及(几乎)您希望从现代视觉调试器获得的所有常用功能。您甚至可以附加到正在运行的进程并进行远程调试。

但是,像其他可视调试器一样,我发现它主要用于简单的问题,或者在尝试了所有其他方法之后对非常复杂的问题很有用。我仍然会进行大部分繁重的伐木工作。

PyDev

PyDev has a pretty good interactive debugger. It has watch expressions, hover-to-evaluate, thread and stack listings and (almost) all the usual amenities you expect from a modern visual debugger. You can even attach to a running process and do remote debugging.

Like other visual debuggers, though, I find it useful mostly for simple problems, or for very complicated problems after I’ve tried everything else. I still do most of the heavy lifting with logging.


回答 9

如果您熟悉Visual Studio,那么您要找的是Visual Studio的Python工具

If you are familiar with Visual Studio, Python Tools for Visual Studio is what you look for.


回答 10

Winpdb非常好,与它的名称相反,它是完全跨平台的。

它有一个非常好的提示,基于 GUI调试器,并支持远程调试。

Winpdb is very nice, and contrary to its name it’s completely cross-platform.

It’s got a very nice prompt-based and GUI debugger, and supports remote debugging.


回答 11

在Vim中,我具有以下三个绑定:

map <F9> Oimport rpdb2; rpdb2.start_embedded_debugger("asdf") #BREAK<esc>
map <F8> Ofrom nose.tools import set_trace; set_trace() #BREAK<esc>
map <F7> Oimport traceback, sys; traceback.print_exception(*sys.exc_info()) #TRACEBACK<esc>

rpdb2是一个远程Python调试器,可与可靠的图形调试器WinPDB一起使用。因为我知道您会问,所以它可以完成我期望图形调试器完成的所有工作:)

我使用pdbfrom nose.tools来调试单元测试和普通代码。

最后,F7映射将打印回溯(类似于异常冒泡到堆栈顶部时所得到的那种)。我发现它确实有用了很多次。

In Vim, I have these three bindings:

map <F9> Oimport rpdb2; rpdb2.start_embedded_debugger("asdf") #BREAK<esc>
map <F8> Ofrom nose.tools import set_trace; set_trace() #BREAK<esc>
map <F7> Oimport traceback, sys; traceback.print_exception(*sys.exc_info()) #TRACEBACK<esc>

rpdb2 is a Remote Python Debugger, which can be used with WinPDB, a solid graphical debugger. Because I know you’ll ask, it can do everything I expect a graphical debugger to do :)

I use pdb from nose.tools so that I can debug unit tests as well as normal code.

Finally, the F7 mapping will print a traceback (similar to the kind you get when an exception bubbles to the top of the stack). I’ve found it really useful more than a few times.


回答 12

为类定义有用的repr()方法(以便您可以看到对象是什么),并使用repr()或“%r”%(…)或“ … {0!r} ..” .. format (…)在您的调试消息/日志中,恕我直言,这是高效调试的关键。

另外,其他答案中提到的调试器将使用repr()方法。

Defining useful repr() methods for your classes (so you can see what an object is) and using repr() or “%r” % (…) or “…{0!r}..”.format(…) in your debug messages/logs is IMHO a key to efficient debugging.

Also, the debuggers mentioned in other answers will make use of the repr() methods.


回答 13

从正在运行的Python应用程序获取堆栈跟踪

有几个窍门在这里。这些包括

  • 通过发送信号进入解释器/打印堆栈跟踪
  • 从未经准备的Python流程中获取堆栈跟踪
  • 运行带有标志的解释器以使其对调试有用

Getting a stack trace from a running Python application

There are several tricks here. These include

  • Breaking into an interpreter/printing a stack trace by sending a signal
  • Getting a stack trace out of an unprepared Python process
  • Running the interpreter with flags to make it useful for debugging

回答 14

如果您不喜欢花时间在调试器上(并且不喜欢pdb命令行界面的可用性很差),则可以转储执行跟踪并在以后进行分析。例如:

python -m trace -t setup.py install > execution.log

这会将所有setup.py install执行源代码转储到execution.log

为了使自定义跟踪输出和编写自己的跟踪器更加容易,我将一些代码放到了xtrace模块(公共域)中。

If you don’t like spending time in debuggers (and don’t appreciate poor usability of pdb command line interface), you can dump execution trace and analyze it later. For example:

python -m trace -t setup.py install > execution.log

This will dump all source line of setup.py install execution to execution.log.

To make it easier to customize trace output and write your own tracers, I put together some pieces of code into xtrace module (public domain).


回答 15

如果可能,我会M-x pdb在emacs中进行调试以进行源代码级调试。

When possible, I debug using M-x pdb in emacs for source level debugging.


回答 16

Andreas Zeller在Udacity上提供了名为“ 软件调试 ” 的完整在线类,其中包含有关调试的提示:

类总结

在本类中,您将学习如何系统地调试程序,如何自动化调试过程以及如何在Python中构建一些自动化调试工具。

为什么要上这门课?

在本类的最后,您将对系统调试有深入的了解,将了解如何实现自动化调试,并且将使用Python构建一些功能调试工具。

先决条件和要求

需要具有Udacity CS101或更高级别的编程和Python的基础知识。对面向对象编程的基本理解会有所帮助。

强烈推荐。

There is a full online course called “Software Debugging” by Andreas Zeller on Udacity, packed with tips about debugging:

Course Summary

In this class you will learn how to debug programs systematically, how to automate the debugging process and build several automated debugging tools in Python.

Why Take This Course?

At the end of this course you will have a solid understanding about systematic debugging, will know how to automate debugging and will have built several functional debugging tools in Python.

Prerequisites and Requirements

Basic knowledge of programming and Python at the level of Udacity CS101 or better is required. Basic understanding of Object-oriented programming is helpful.

Highly recommended.


回答 17

如果您想要一种很好的图形方式以一种可读的方式打印您的调用堆栈,请查看此实用程序:https : //github.com/joerick/pyinstrument

从命令行运行:

python -m pyinstrument myscript.py [args...]

作为模块运行:

from pyinstrument import Profiler

profiler = Profiler()
profiler.start()

# code you want to profile

profiler.stop()
print(profiler.output_text(unicode=True, color=True))

用django运行:

只需添加pyinstrument.middleware.ProfilerMiddlewareMIDDLEWARE_CLASSES,然后添加?profile到请求URL的末尾以激活分析器。

if you want a nice graphical way to print your call stack in a readable fashion, check out this utility: https://github.com/joerick/pyinstrument

Run from command line:

python -m pyinstrument myscript.py [args...]

Run as a module:

from pyinstrument import Profiler

profiler = Profiler()
profiler.start()

# code you want to profile

profiler.stop()
print(profiler.output_text(unicode=True, color=True))

Run with django:

Just add pyinstrument.middleware.ProfilerMiddleware to MIDDLEWARE_CLASSES, then add ?profile to the end of the request URL to activate the profiler.


错误时自动启动python调试器

问题:错误时自动启动python调试器

这是我很长时间以来一直想知道的一个问题,但是我从未找到合适的解决方案。如果我运行了一个脚本并且碰到了一个类似IndexError的错误,python将打印错误的行,位置和快速描述,然后退出。遇到错误是否可以自动启动pdb?我不反对在文件顶部添加多余的import语句,也不反对添加几行代码。

This is a question I have wondered about for quite some time, yet I have never found a suitable solution. If I run a script and I come across, let’s say an IndexError, python prints the line, location and quick description of the error and exits. Is it possible to automatically start pdb when an error is encountered? I am not against having an extra import statement at the top of the file, nor a few extra lines of code.


回答 0

您可以使用traceback.print_exc打印异常跟踪。然后使用sys.exc_info提取回溯,最后使用该回溯调用pdb.post_mortem

import pdb, traceback, sys

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        extype, value, tb = sys.exc_info()
        traceback.print_exc()
        pdb.post_mortem(tb)

如果要使用产生异常的框架的局部语言使用code.interact启动交互式命令行,可以执行

import traceback, sys, code

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        type, value, tb = sys.exc_info()
        traceback.print_exc()
        last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb
        frame = last_frame().tb_frame
        ns = dict(frame.f_globals)
        ns.update(frame.f_locals)
        code.interact(local=ns)

You can use traceback.print_exc to print the exceptions traceback. Then use sys.exc_info to extract the traceback and finally call pdb.post_mortem with that traceback

import pdb, traceback, sys

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        extype, value, tb = sys.exc_info()
        traceback.print_exc()
        pdb.post_mortem(tb)

If you want to start an interactive command line with code.interact using the locals of the frame where the exception originated you can do

import traceback, sys, code

def bombs():
    a = []
    print a[0]

if __name__ == '__main__':
    try:
        bombs()
    except:
        type, value, tb = sys.exc_info()
        traceback.print_exc()
        last_frame = lambda tb=tb: last_frame(tb.tb_next) if tb.tb_next else tb
        frame = last_frame().tb_frame
        ns = dict(frame.f_globals)
        ns.update(frame.f_locals)
        code.interact(local=ns)

回答 1

python -m pdb -c continue myscript.py

如果不提供-c continue标志,则在执行开始时需要输入“ c”(代表“继续”)。然后它将运行到错误点,并在那里给您控制。如eqzx所述,此标志是python 3.2中的新增功能,因此,对于早期的Python版本,请输入’c’(请参阅https://docs.python.org/3/library/pdb.html)。

python -m pdb -c continue myscript.py

If you don’t provide the -c continue flag then you’ll need to enter ‘c’ (for Continue) when execution begins. Then it will run to the error point and give you control there. As mentioned by eqzx, this flag is a new addition in python 3.2 so entering ‘c’ is required for earlier Python versions (see https://docs.python.org/3/library/pdb.html).


回答 2

使用以下模块:

import sys

def info(type, value, tb):
    if hasattr(sys, 'ps1') or not sys.stderr.isatty():
    # we are in interactive mode or we don't have a tty-like
    # device, so we call the default hook
        sys.__excepthook__(type, value, tb)
    else:
        import traceback, pdb
        # we are NOT in interactive mode, print the exception...
        traceback.print_exception(type, value, tb)
        print
        # ...then start the debugger in post-mortem mode.
        # pdb.pm() # deprecated
        pdb.post_mortem(tb) # more "modern"

sys.excepthook = info

命名debug(或您喜欢的任何名称)并将其放在python路径中的某个位置。

现在,在脚本的开头,只需添加一个即可import debug

Use the following module:

import sys

def info(type, value, tb):
    if hasattr(sys, 'ps1') or not sys.stderr.isatty():
    # we are in interactive mode or we don't have a tty-like
    # device, so we call the default hook
        sys.__excepthook__(type, value, tb)
    else:
        import traceback, pdb
        # we are NOT in interactive mode, print the exception...
        traceback.print_exception(type, value, tb)
        print
        # ...then start the debugger in post-mortem mode.
        # pdb.pm() # deprecated
        pdb.post_mortem(tb) # more "modern"

sys.excepthook = info

Name it debug (or whatever you like) and put it somewhere in your python path.

Now, at the start of your script, just add an import debug.


回答 3

Ipython有一个用于切换此行为的命令:%pdb。它的功能完全符合您的描述,甚至可能更多(通过语法高亮和代码完成为您提供更多有用的回溯信息)。绝对值得一试!

Ipython has a command for toggling this behavior: %pdb. It does exactly what you described, maybe even a bit more (giving you more informative backtraces with syntax highlighting and code completion). It’s definitely worth a try!


回答 4

这不是调试器,但可能同样有用(?)

我知道我听到Guido在某处的演讲中提到了这一点。

我刚刚检查了python-?,如果您使用-i命令,则可以在脚本停止的地方进行交互。

因此,鉴于此脚本:

testlist = [1,2,3,4,5, 0]

prev_i = None
for i in testlist:
    if not prev_i:
        prev_i = i
    else:
        result = prev_i/i

您可以获得此输出!

PS D:\> python -i debugtest.py
Traceback (most recent call last):
  File "debugtest.py", line 10, in <module>
    result = prev_i/i
ZeroDivisionError: integer division or modulo by zero
>>>
>>>
>>> prev_i
1
>>> i
0
>>>

老实说,我没有使用过,但是应该使用,这似乎很有用。

This isn’t the debugger, but probably just as useful(?)

I know I heard Guido mention this in a speech somewhere.

I just checked python -?, and if you use the -i command you can interact where your script stopped.

So given this script:

testlist = [1,2,3,4,5, 0]

prev_i = None
for i in testlist:
    if not prev_i:
        prev_i = i
    else:
        result = prev_i/i

You can get this output!

PS D:\> python -i debugtest.py
Traceback (most recent call last):
  File "debugtest.py", line 10, in <module>
    result = prev_i/i
ZeroDivisionError: integer division or modulo by zero
>>>
>>>
>>> prev_i
1
>>> i
0
>>>

To be honest I haven’t used this, but I should be, seems very useful.


回答 5

IPython在命令行上使这一过程变得简单:

python myscript.py arg1 arg2

可以重写为

ipython --pdb myscript.py -- arg1 arg2

或者,类似地,如果调用模块:

python -m mymodule arg1 arg2

可以重写为

ipython --pdb -m mymodule -- arg1 arg2

请注意,--以阻止IPython读取脚本的自变量。

这也具有调用增强的IPython调试器(ipdb)而不是pdb的优势。

IPython makes this simple on the command line:

python myscript.py arg1 arg2

can be rewritten to

ipython --pdb myscript.py -- arg1 arg2

Or, similarly, if calling a module:

python -m mymodule arg1 arg2

can be rewritten to

ipython --pdb -m mymodule -- arg1 arg2

Note the -- to stop IPython from reading the script’s arguments as its own.

This also has the advantage of invoking the enhanced IPython debugger (ipdb) instead of pdb.


回答 6

如果您使用ipython,请在启动后输入%pdb

In [1]: %pdb
Automatic pdb calling has been turned ON

If you are using ipython, after launching type %pdb

In [1]: %pdb
Automatic pdb calling has been turned ON

回答 7

如果您使用的是IPython环境,则可以只使用%debug,外壳程序会将您带回到ipdb环境进行检查等问题。如上所述,另一种选择是使用iPython魔术%pdb,它可以有效地相同。

If you are using the IPython environment, you can just use the %debug and the shell will take you back to the offending line with the ipdb environment for inspections etc. Another option as pointed above is to use the iPython magic %pdb which effectively does the same.


回答 8

您可以将以下行放入代码中:

import pdb ; pdb.set_trace()

更多信息:在任意行启动python调试器

You can put this line in your code:

import pdb ; pdb.set_trace()

More info: Start the python debugger at any line


回答 9

要使其运行而不必在开始使用时键入c:

python -m pdb -c c <script name>

Pdb有其自己的命令行参数:-cc将在执行开始时执行c(ontinue)命令,并且程序将不间断运行直至出现错误。

To have it run without having to type c at the beginning use:

python -m pdb -c c <script name>

Pdb has its own command line arguments: -c c will execute c(ontinue) command at start of execution and the program will run uninterrupted until the error.


回答 10

python2.7中的python -m pdb script.py按继续启动,它将运行到错误并在此处中断以进行调试。

python -m pdb script.py in python2.7 press continue to start and it will run to the error and break there for debug.


回答 11

如果您正在运行模块:

python -m mymodule

现在,您想pdb在发生异常时输入信息,请执行以下操作:

PYTHONPATH="." python -m pdb -c c mymodule/__main__.py

(或扩展您的PYTHONPATH)。的PYTHONPATH需要,使模块在路径中发现,因为你运行的是pdb现在的模块。

If you are running a module:

python -m mymodule

And now you want to enter pdb when an exception occurs, do this:

PYTHONPATH="." python -m pdb -c c mymodule/__main__.py

(or extend your PYTHONPATH). The PYTHONPATH is needed so that the module is found in the path, since you are running the pdb module now.


回答 12

在层次结构中最顶层异常类的构造函数中放置一个断点,大多数情况下,您将看到引发错误的位置。

放置断点意味着您想要表达的含义:您可以使用IDE或pdb.set_trace,或任何其他方式

Put a breakpoint inside the constructor of topmost exception class in the hierarchy, and most of the times you will see where the error was raised.

Putting a breakpoint means whatever you want it to mean : you can use an IDE, or pdb.set_trace, or whatever


如何逐步处理Python代码以帮助调试问题?

问题:如何逐步处理Python代码以帮助调试问题?

在Java / C#中,您可以轻松地逐步执行代码以查找可能出了问题的地方,而IDE使此过程非常人性化。

您能以类似的方式跟踪python代码吗?

In Java/C# you can easily step through code to trace what might be going wrong, and IDE’s make this process very user friendly.

Can you trace through python code in a similar fashion?


回答 0

是! 有一个Python调试器pdb就是为了这样做!

您可以pdb使用pdb myscript.py或通过启动Python程序python -m pdb myscript.py

然后,您可以发出一些命令,这些命令已在pdb页面中记录。

需要记住的一些有用的是:

  • b:设置一个断点
  • c:继续调试,直到遇到断点
  • s:单步执行代码
  • n:转到下一行代码
  • l:列出当前文件的源代码(默认值:11行,包括正在执行的行)
  • u:浏览堆栈框架
  • d:向下浏览堆栈框架
  • p:在当前上下文中打印表达式的值

如果您不想使用命令行调试器,则某些IDE(例如PydevWing IDEPyCharm)都具有GUI调试器。Wing和PyCharm是商业产品,但是Wing具有免费的“个人”版本,PyCharm具有免费的社区版本。

Yes! There’s a Python debugger called pdb just for doing that!

You can launch a Python program through pdb by using pdb myscript.py or python -m pdb myscript.py.

There are a few commands you can then issue, which are documented on the pdb page.

Some useful ones to remember are:

  • b: set a breakpoint
  • c: continue debugging until you hit a breakpoint
  • s: step through the code
  • n: to go to next line of code
  • l: list source code for the current file (default: 11 lines including the line being executed)
  • u: navigate up a stack frame
  • d: navigate down a stack frame
  • p: to print the value of an expression in the current context

If you don’t want to use a command line debugger, some IDEs like Pydev, Wing IDE or PyCharm have a GUI debugger. Wing and PyCharm are commercial products, but Wing has a free “Personal” edition, and PyCharm has a free community edition.


回答 1

通过使用Python交互式调试器’pdb’

第一步是使Python解释器进入调试模式。

A.从命令行

从python解释器的命令行运行的最直接的方法

$ python -m pdb scriptName.py
> .../pdb_script.py(7)<module>()
-> """
(Pdb)

B.口译员

在开发模块的早期版本并进行更多迭代实验时。

$ python
Python 2.7 (r27:82508, Jul  3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb_script
>>> import pdb
>>> pdb.run('pdb_script.MyObj(5).go()')
> <string>(1)<module>()
(Pdb)

C.从您的程序内部

对于大型项目和长时间运行的模块,可以使用import pdbset_trace()从程序内部启动调试, 如下所示:

#!/usr/bin/env python
# encoding: utf-8
#

import pdb

class MyObj(object):
    count = 5
    def __init__(self):
        self.count= 9

    def go(self):
        for i in range(self.count):
            pdb.set_trace()
            print i
        return

if __name__ == '__main__':
    MyObj(5).go()

分步调试进入更多内部

  1. “ n”执行下一条语句(下一个)

  2. 重复最后的调试命令与ENTER

  3. “ q”退出所有… (退出)

  4. 用“ p”打印变量的值…(打印)

    a) pa

  5. “ c”关闭(Pdb)提示(继续)

  6. 通过“ l”查看您的位置… (列表)

  7. 进入子程序…用“ s”(进入)

  8. 继续…但是直到当前子例程的结尾…用“ r”(返回)

  9. 分配新值

    a) !b =“ B”

  10. 设置断点

    a) 中断行号

    b) 中断函数名

    c) 中断filename:linenumber

  11. 临时断点

    a) 中断行号

  12. 条件断点

    a) 中断行号,条件

注意:**所有这些命令应从** pdb执行

有关深入的知识,请参阅:-

https://pymotw.com/2/pdb/

https://pythonconquerstheuniverse.wordpress.com/2009/09/10/debugging-in-python/

By using Python Interactive Debugger ‘pdb’

First step is to make the Python interpreter to enter into the debugging mode.

A. From the Command Line

Most straight forward way, running from command line, of python interpreter

$ python -m pdb scriptName.py
> .../pdb_script.py(7)<module>()
-> """
(Pdb)

B. Within the Interpreter

While developing early versions of modules and to experiment it more iteratively.

$ python
Python 2.7 (r27:82508, Jul  3 2010, 21:12:11)
[GCC 4.0.1 (Apple Inc. build 5493)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import pdb_script
>>> import pdb
>>> pdb.run('pdb_script.MyObj(5).go()')
> <string>(1)<module>()
(Pdb)

C. From Within Your Program

For a big project and long-running module, can start the debugging from inside the program using import pdb and set_trace() like this :

#!/usr/bin/env python
# encoding: utf-8
#

import pdb

class MyObj(object):
    count = 5
    def __init__(self):
        self.count= 9

    def go(self):
        for i in range(self.count):
            pdb.set_trace()
            print i
        return

if __name__ == '__main__':
    MyObj(5).go()

Step-by-Step debugging to go into more internal

  1. Execute the next statement… with “n” (next)

  2. Repeating the last debugging command… with ENTER

  3. Quitting it all… with “q” (quit)

  4. Printing the value of variables… with “p” (print)

    a) p a

  5. Turning off the (Pdb) prompt… with “c” (continue)

  6. Seeing where you are… with “l” (list)

  7. Stepping into subroutines… with “s” (step into)

  8. Continuing… but just to the end of the current subroutine… with “r” (return)

  9. Assign a new value

    a) !b = “B”

  10. Set a breakpoint

    a) break linenumber

    b) break functionname

    c) break filename:linenumber

  11. Temporary breakpoint

    a) tbreak linenumber

  12. Conditional breakpoint

    a) break linenumber, condition

Note:**All these commands should be execute from **pdb

For in-depth knowledge, refer:-

https://pymotw.com/2/pdb/

https://pythonconquerstheuniverse.wordpress.com/2009/09/10/debugging-in-python/


回答 2

python中有一个名为“ pdb”的模块。在python脚本的顶部,您可以执行

import pdb
pdb.set_trace()

您将进入调试模式。您可以使用’s’步进,’n’跟随下一行,类似于使用’gdb’调试器进行的操作。

There is a module called ‘pdb’ in python. At the top of your python script you do

import pdb
pdb.set_trace()

and you will enter into debugging mode. You can use ‘s’ to step, ‘n’ to follow next line similar to what you would do with ‘gdb’ debugger.


回答 3

从Python 3.7开始,您可以使用breakpoint()内置函数进入调试器:

foo()
breakpoint()  # drop into the debugger at this point
bar()

默认情况下,breakpoint()将导入pdb并调用pdb.set_trace()。但是,您可以通过sys.breakpointhook()使用环境变量来控制调试行为PYTHONBREAKPOINT

有关更多信息,请参见PEP 553

Starting in Python 3.7, you can use the breakpoint() built-in function to enter the debugger:

foo()
breakpoint()  # drop into the debugger at this point
bar()

By default, breakpoint() will import pdb and call pdb.set_trace(). However, you can control debugging behavior via sys.breakpointhook() and use of the environment variable PYTHONBREAKPOINT.

See PEP 553 for more information.


回答 4

ipdb(IPython调试器)

ipdb在pdb中添加了IPython功能,提供了以下巨大改进:

  • 制表符完成
  • 显示更多上下文行
  • 语法高亮

就像pdg一样,与GDB相比,ipdb仍然远远不够完善和完全初级,但是与pdb相比已经有了很大的改进。

用法类似于pdb,只需使用以下命令进行安装:

python3 -m pip install --user ipdb

然后添加到您要从中逐步调试的行:

__import__('ipdb').set_trace(context=21)

您可能想从编辑器中为其添加快捷方式,例如,对于我拥有的Vim片段

snippet ipd
    __import__('ipdb').set_trace(context=21)

这样我就可以输入,ipd<tab>并且它会扩展到断点。dd由于所有内容都包含在一行中,因此删除它很容易。

context=21增加了上下文行的数量,如下所述:在调试时如何使ipdb显示更多上下文行?

另外,您也可以从头开始调试程序:

ipdb3 main.py

但是您通常不想这样做,因为:

  • 您将必须遍历所有函数和类的定义,因为Python会读取这些行
  • 我不知道如何在不入侵ipdb的情况下设置上下文大小。补丁以允许它:https : //github.com/gotcha/ipdb/pull/155

或者,就像在原始pdb 3.2+中一样,您可以从命令行设置一些断点:

ipdb3 -c 'b 12' -c 'b myfunc' ~/test/a.py

虽然-c c由于某种原因而损坏了:https : //github.com/gotcha/ipdb/issues/156

python -m module在以下位置询问了调试问题:如何从命令行调试使用python -m运行的Python模块?由于Python 3.7可以通过以下方式完成:

python -m pdb -m my_module

与GDB相比,pdb和ipdb严重缺少的功能:

ipdb的烦恼:

已在Ubuntu 16.04,ipdb == 0.11,Python 3.5.2中进行了测试。

ipdb (IPython debugger)

ipdb adds IPython functionality to pdb, offering the following HUGE improvements:

  • tab completion
  • show more context lines
  • syntax highlight

Much like pdg, ipdb is still far from perfect and completely rudimentary if compared to GDB, but it is already a huge improvement over pdb.

Usage is analogous to pdb, just install it with:

python3 -m pip install --user ipdb

and then add to the line you want to step debug from:

__import__('ipdb').set_trace(context=21)

You likely want to add a shortcut for that from your editor, e.g. for Vim snipmate I have:

snippet ipd
    __import__('ipdb').set_trace(context=21)

so I can type just ipd<tab> and it expands to the breakpoint. Then removing it is easy with dd since everything is contained in a single line.

context=21 increases the number of context lines as explained at: How can I make ipdb show more lines of context while debugging?

Alternatively, you can also debug programs from the start with:

ipdb3 main.py

but you generally don’t want to do that because:

  • you would have to go through all function and class definitions as Python reads those lines
  • I don’t know how to set the context size there without hacking ipdb. Patch to allow it: https://github.com/gotcha/ipdb/pull/155

Or alternatively, as in raw pdb 3.2+ you can set some breakpoints from the command line:

ipdb3 -c 'b 12' -c 'b myfunc' ~/test/a.py

although -c c is broken for some reason: https://github.com/gotcha/ipdb/issues/156

python -m module debugging has been asked at: How to debug a Python module run with python -m from the command line? and since Python 3.7 can be done with:

python -m pdb -m my_module

Serious missing features of both pdb and ipdb compared to GDB:

ipdb specific annoyances:

Tested in Ubuntu 16.04, ipdb==0.11, Python 3.5.2.


回答 5

breakpoint()如今有一种方法可以代替import pdb; pdb.set_trace()

它还具有一些新功能,例如可能的环境变量。

There exist breakpoint() method nowadays, which replaces import pdb; pdb.set_trace().

It also has several new features, such as possible environment variables.


回答 6

如果您来自Java / C#背景,那么我猜您最好的选择是将EclipsePydev一起使用。这为您提供了一个内置调试器的功能齐全的IDE。我也将其与django一起使用。

If you come from Java/C# background I guess your best bet would be to use Eclipse with Pydev. This gives you a fully functional IDE with debugger built in. I use it with django as well.


回答 7

如果您想要具有集成调试器的IDE,请尝试PyScripter

If you want an IDE with integrated debugger, try PyScripter.


回答 8

https://wiki.python.org/moin/PythonDebuggingTools

pudb是pdb的很好的替代品


回答 9

Python Tutor是面向新手的在线单步调试器。您可以在编辑页面上放入代码,然后单击“可视化执行”以开始运行。

除其他外,它支持:

但是它也不支持很多东西,例如:

  • 读取/写入文件-使用io.StringIOio.BytesIO代替:演示
  • 代码太大,运行时间太长或定义了太多变量或对象
  • 命令行参数
  • 很多标准库模块,例如argparse,csv,枚举,html,os,struct,weakref …

Python Tutor is an online single-step debugger meant for novices. You can put in code on the edit page then click “Visualize Execution” to start it running.

Among other things, it supports:

However it also doesn’t support a lot of things, for example:

  • Reading/writing files – use io.StringIO and io.BytesIO instead: demo
  • Code that is too large, runs too long, or defines too many variables or objects
  • Command-line arguments
  • Lots of standard library modules like argparse, csv, enum, html, os, struct, weakref…

回答 10

也可以以编程方式步进和跟踪python代码(而且很简单!)。有关更多详细信息,请参见sys.settrace()文档。另外,这里还有一个入门指南。

Programmatically stepping and tracing through python code is possible too (and its easy!). Look at the sys.settrace() documentation for more details. Also here is a tutorial to get you started.


回答 11


回答 12

PyCharm是适用于Python的IDE,其中包含调试器。观看此YouTube视频,以获取有关使用PyCharm调试器逐步执行代码的介绍。

PyCharm教程-使用PyCharm调试python代码

注意:这并不是要背书或评论。PyCharm是一种需要付费的商业产品,但该公司确实向学生和教师提供了免费许可,以及免费和开放源代码的“轻量级”社区版本。

PyCharm is an IDE for Python that includes a debugger. Watch this YouTube video for an introduction on using PyCharm’s debugger to step through code.

PyCharm Tutorial – Debug python code using PyCharm

Note: This is not intended to be an endorsement or review. PyCharm is a commercial product that one needs to pay for, but the company does provide a free license to students and teachers, as well as a “lightweight” Community version that is free and open-source.