(Update am 28. Mai 2016) Verwenden von RealGUD in Emacs
Für jeden in Emacs zeigt dieser Thread , wie man alles erreicht, was im OP (und mehr) beschrieben ist
- Ein neuer wichtiger Debugger in Emacs namens RealGUD, der mit jedem Debugger (einschließlich
ipdb
) betrieben werden kann.
- Das Emacs-Paket
isend-mode
.
Die Kombination dieser beiden Pakete ist äußerst leistungsfähig und ermöglicht es, genau das im OP beschriebene Verhalten wiederherzustellen und noch mehr zu tun.
Weitere Infos zum Wiki-Artikel von RealGUD für ipdb.
Ursprüngliche Antwort:
Nachdem ich viele verschiedene Methoden zum Debuggen von Python ausprobiert habe, einschließlich aller in diesem Thread erwähnten Methoden, ist eine meiner bevorzugten Methoden zum Debuggen von Python mit IPython eingebettete Shells.
Definieren einer benutzerdefinierten eingebetteten IPython-Shell:
Fügen Sie Ihrem Skript Folgendes hinzu PYTHONPATH
, damit die Methode ipsh()
verfügbar wird.
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)
Wenn ich dann etwas in meinem Code debuggen möchte, platziere ich es ipsh()
genau an der Stelle, an der ich eine Objektinspektion usw. durchführen muss. Angenommen, ich möchte my_function
unten debuggen
Es benutzen:
def my_function(b):
a = b
ipsh() # <- This will embed a full-fledged IPython interpreter
a = 4
und dann rufe ich auf my_function(2)
eine der folgenden Arten auf:
- Entweder durch Ausführen eines Python-Programms, das diese Funktion von einer Unix-Shell aus aufruft
- Oder indem Sie es direkt von IPython aus aufrufen
Unabhängig davon, wie ich es aufrufe, bleibt der Dolmetscher an der Zeile stehen, in der steht ipsh()
. Sobald Sie fertig sind, können Sie dies tun Ctrl-D
und Python setzt die Ausführung fort (mit allen von Ihnen vorgenommenen Variablenaktualisierungen). Beachten Sie, dass, wenn Sie den Code von einem regulären IPython aus ausführen, der IPython-Shell (Fall 2 oben), die neue IPython-Shell in derjenige verschachtelt ist, von der aus Sie sie aufgerufen haben. Dies ist vollkommen in Ordnung, aber es ist gut, sich dessen bewusst zu sein. Sobald der Interpreter an der Stelle von anhält ipsh
, kann ich den Wert von a
(welche sein 2
) überprüfen , sehen, welche Funktionen und Objekte definiert sind usw.
Das Problem:
Die obige Lösung kann verwendet werden, um Python an einer beliebigen Stelle in Ihrem Code anzuhalten und Sie dann in einen vollwertigen IPython-Interpreter zu verschieben. Leider können Sie nach dem Aufrufen des Skripts keine Haltepunkte hinzufügen oder entfernen, was sehr frustrierend ist. Meiner Meinung nach ist dies das einzige, was IPython daran hindert, ein großartiges Debugging-Tool für Python zu werden.
Das Beste, was Sie jetzt tun können:
Eine Problemumgehung besteht darin, ipsh()
a priori an den verschiedenen Stellen zu platzieren, an denen der Python-Interpreter eine IPython-Shell starten soll (z. B. a breakpoint
). Sie können dann zwischen verschiedenen vordefinierten, fest codierten "Haltepunkten" mit "springen" Ctrl-D
, wodurch die aktuell eingebettete IPython-Shell verlassen und erneut gestoppt wird, wenn der Interpreter den nächsten Aufruf von anruft ipsh()
.
Wenn Sie diesen Weg gehen, können Sie den "Debugging-Modus" beenden und alle nachfolgenden Haltepunkte ipshell.dummy_mode = True
ignorieren, ipshell
indem Python alle nachfolgenden Instanziierungen des oben erstellten Objekts ignoriert .
!
Befehl, der jeden Python-Befehl am Haltepunkt ausführt