PYTHON

Debuggen im gemischten Modus für Python - Visual Studio (Windows)

Inhaltsverzeichnis

Gleichzeitiges Debuggen von Python und C++

Artikel

01/31/2022

5 Minuten Lesedauer

2 Mitwirkende Ist diese Seite hilfreich? Yes No Haben Sie weiteres Feedback für uns? Feedback wird an Microsoft gesendet: Wenn Sie auf die Sendeschaltfläche klicken, wird Ihr Feedback verwendet, um Microsoft-Produkte und -Dienste zu verbessern. Datenschutzrichtlinie Übermitteln Vielen Dank.

In diesem Artikel

Die meisten Python-Debugger unterstützten das Debuggen nur von Python-Code. In der Praxis wird Python jedoch in Szenarien, in denen eine hohe Leistung erforderlich ist oder Plattform-APIs direkt aufgerufen werden müssen, zusammen mit C oder C++ verwendet. (Eine exemplarische Vorgehensweise finden Sie unter Erstellen einer C++-Erweiterung für Python.)

In Visual Studio ist das gleichzeitige Debuggen im gemischten Modus für Python und für die nativen Programmiersprachen C/C++ integriert. Voraussetzung dafür ist, dass Sie die Option Native Python-Entwicklungstools für die Workload für die Python-Entwicklung im Visual Studio-Installer auswählen.

Hinweis Das Debuggen im gemischten Modus steht für Python-Tools für Visual Studio 1.x in Visual Studio 2015 und niedrigeren Versionen nicht zur Verfügung.

Features für das Debuggen im gemischten Modus sind, wie in diesem Artikel beschrieben, die folgenden:

Kombinierte Aufruflisten

Abwechselnde Einzelschrittausführung zwischen Python und nativem Code

Haltepunkte in beiden Codetypen

Anzeigen von Python-Darstellungen von Objekten in nativen Frames und umgekehrt

Das Debuggen im Kontext eines Python-Projekts oder eines C++-Projekts

: Eine Einführung in das Erstellen, Testen und Debuggen von nativen C-Modulen mit Visual Studio sehen Sie im Video Deep Dive: Create Native Modules (Ausführliche Erläuterungen: Erstellen nativer Module) 9 Minuten, 9 Sekunden). Das Video gilt für Visual Studio 2015 und 2017.

Aktivieren des Debuggens im gemischten Modus in einem Python-Projekt

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das Python-Projekt, wählen Sie Eigenschaften und die Registerkarte Debuggen aus, und wählen Sie anschließend Debuggen von nativem Code aktivieren aus. Diese Option aktiviert den gemischten Modus für alle Debugsitzungen. Tipp Wenn Sie das Debuggen von nativem Code aktivieren, kann das Python-Ausgabefenster möglicherweise sofort verschwinden, wenn das Programm ohne die übliche Pause Drücken Sie eine beliebige Taste, um fortzufahren... abgeschlossen wurde. Um eine Pause zu erzwingen, fügen Sie die -i -Option dem Feld Ausführen > Interpreterargumente auf der Registerkarte Debuggen hinzu, wenn Sie das Debuggen von nativem Code aktivieren. Durch dieses Argument wird der Python-Interpreter in den interaktiven Modus versetzt, nachdem der Code beendet wurde. Zu diesem Zeitpunkt wartet er darauf, dass Sie zum Beenden STRG+Z > EINGABETASTE drücken. Wenn Sie den Debugger für den gemischten Modus an einen vorhandenen Prozess anhängen (Debuggen > An den Prozess anhängen), klicken Sie auf die Schaltfläche Auswählen, um das Dialogfeld Codetyp auswählen zu öffnen. Wählen Sie die Option Diese Codetypen debuggen aus, und wählen Sie in der Liste sowohl Nativ als auch Python aus: Die Einstellungen für den Codetyp bleiben sitzungsübergreifend bestehen. Wenn Sie also den gemischten Modus später beim Anfügen an einen anderen Prozess deaktivieren möchten, deaktivieren Sie den Codetyp Python. Sie können anstelle von oder zusätzlich zu Nativ auch weitere Codetypen auswählen. Wenn eine verwaltete Anwendung z.B. den Interpreter CPython hostet, der wiederum native Erweiterungsmodule verwendet, und Sie alle drei Typen debuggen möchten, können Sie die Optionen Python, Nativ und Verwaltet zusammen aktivieren. So erhalten Sie eine einheitliche Debugleistung einschließlich kombinierter Aufruflisten und abwechselnder Einzelschrittausführung zwischen allen drei Runtimes. Wenn Sie das Debuggen im gemischten Modus zum ersten Mal starten, wird womöglich das Dialogfeld Python-Symbole erforderlich angezeigt (Informationen finden Sie unter Symbole für Debuggen im gemischten Modus). Sie müssen Symbole für jede Python-Umgebung nur einmal installieren. Symbole sind automatisch enthalten, wenn Sie die Python-Unterstützung über den Visual Studio-Installer (Visual Studio 2017 und höher) installieren. Sie stellen den Quellcode für die Standardversion von Python beim Debuggen selbst zur Verfügung. Besuchen Sie hierzu Laden Sie anschließend die für Ihre Version geeignete Archivdatei herunter, und extrahieren Sie sie in einen Ordner. Sie verweisen Visual Studio dann auf bestimmte Dateien in diesem Ordner, egal zu welchem Punkt Sie aufgefordert werden.

Aktivieren des Debuggens im gemischten Modus in einem C/C++-Projekt

Visual Studio (2017, Version 15.5 und höher) unterstützt das Debuggen im gemischten Modus von einem C/C++-Projekt aus (wenn z.B. Python in einer anderen Anwendung, wie auf beschrieben, eingebettet wird). Konfigurieren Sie das C/C++-Projekt, um Python-/Natives Debuggen zu starten, um das Debuggen im gemischten Modus zu aktivieren:

Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf das C/C++-Projekt, und wählen Sie Eigenschaften aus. Klicken Sie auf die Registerkarte Debuggen, wählen Sie aus dem Debugger Python-/Natives Debuggen unter Zu startender Debugger aus, und klicken Sie auf OK.

Hinweis Wenn Sie nicht die Möglichkeit haben, Python/Natives Debuggen auszuwählen, müssen Sie zunächst die nativen Python-Entwicklungstools mit dem VS-Installationsprogramm installieren. Sie finden es als Option unter der Python-Entwicklungsworkload. Weitere Informationen finden Sie unter Installieren von Python-Unterstützung für Visual Studio unter Windows.

Beachten Sie bei Verwendung dieser Methode, dass Sie das Startprogramm selbst nicht debuggen können, da dieses einen untergeordneten erzeugt, an den der Debugger nicht angehängt wird. Wenn Sie direkt mit Argumenten starten möchten, ändern Sie die Option Befehl in den Eigenschaften Python-/Natives Debuggen (in der vorherigen Abbildung dargestellt), um den vollständigen Pfad zu anzugeben. Geben Sie anschließend Argumente unter Befehlsargumente an.

Anfügen des Debuggers im gemischten Modus

Für alle vorherigen Versionen von Visual Studio ist das Debuggen im gemischten Modus nur aktiviert, wenn ein Python-Projekt in Visual Studio gestartet wird, da C/C++-Projekte nur den nativen Debugger verwenden. Sie können den Debugger jedoch separat anfügen:

Starten Sie das C++-Projekt ohne Debuggen (Debuggen > Starten ohne Debugging oder STRG+F5). Wählen Sie Debuggen > An den Prozess anhängen aus. Wählen Sie im angezeigten Dialogfeld den passenden Prozess aus, und klicken Sie anschließend auf die Schaltfläche Auswählen, um das Dialogfeld Codetyp auswählen zu öffnen, in dem Sie Python auswählen können: Klicken Sie auf OK, um das Dialogfeld zu schließen, dann auf Anfügen, um den Debugger zu starten. Beachten Sie, dass Sie möglicherweise eine angemessene Pause oder Verzögerung in die C++-App integrieren müssen, um sicherzustellen, dass diese den Python-Code, den Sie debuggen möchten, nicht aufruft, bevor Sie den Debugger anfügen können.

Spezifische Funktionen des gemischten Modus

Kombinierte Aufrufliste

Das Aufruflistenfenster zeigt die Stapelrahmen für den nativen und den Python-Code überlappend und mit markierten Übergängen zwischen beiden Codetypen an:

Übergänge werden ohne Angabe der Übergangsrichtung als [Externer Code] angezeigt, wenn die Option Extras > Optionen > Debuggen > Allgemein > Nur meinen Code aktivieren festgelegt ist.

Durch Doppelklicken auf einen beliebigen Aufruflistenrahmen wird dieser Rahmen aktiv, und es wird der entsprechende Quellcode geöffnet, sofern möglich. Wenn kein Quellcode verfügbar ist, wird der Rahmen dennoch aktiv, und die lokalen Variablen können überprüft werden.

Abwechselnde Einzelschrittausführung zwischen Python und nativem Code

Beim Verwenden der Befehle Einzelschritt (F11) oder Ausführen bis Rücksprung (UMSCHALTTASTE+F11) verarbeitet der Debugger im gemischten Modus Änderungen zwischen Codetypen ordnungsgemäß. Ein Beispiel: Wenn Python eine Methode eines Typs aufruft, der in C implementiert ist, wird die Einzelschrittausführung eines Aufrufs dieser Methode am Beginn der nativen Funktion angehalten, die die Methode implementiert. Gleiches gilt, wenn nativer Code eine Python-API-Funktion aufruft, die zu einem Aufruf von Python-Code führt. Die Einzelschrittausführung eines PyObject_CallObject -Objekts in einem Funktionswert, der ursprünglich in Python definiert wurde, wird am Beginn der Python-Funktion angehalten. Die Einzelschrittausführung von nativem Code aus Python heraus wird ebenfalls für native Funktionen unterstützt, die über ctypes von Python aufgerufen wurden.

Ansicht der PyObject-Werte im nativen Code

Wenn ein nativer Frame (C oder C++) aktiv ist, werden die zugehörigen lokalen Variablen im Lokalfenster des Debuggers angezeigt. In nativen Python-Erweiterungsmodulen weisen viele dieser Variablen den Typ PyObject (eine typedef für _object ) oder einen anderen grundlegenden Python-Typ auf (siehe unten stehende Liste). Beim Debuggen im gemischten Modus zeigen diese Werte einen zusätzlichen untergeordneten Knoten mit der Bezeichnung [Python-Ansicht] an. Nach Erweitern zeigt dieser Knoten die Python-Darstellung der Variablen an – wenn eine lokale Variable, die auf dasselbe Objekt verweist, in einem Python-Rahmen vorhanden wäre, wäre die Darstellung die gleiche. Die untergeordneten Elemente dieses Knotens können bearbeitet werden.

Um diese Funktion zu deaktivieren, klicken Sie mit der rechten Maustaste auf eine beliebige Stelle im Lokalfenster, und deaktivieren Sie die Menüoption Python > Python-Ansichtsknoten anzeigen:

C-Typen, die [Python-Ansicht] -Knoten anzeigen (sofern aktiviert):

PyObject

PyVarObject

PyTypeObject

PyByteArrayObject

PyBytesObject

PyTupleObject

PyListObject

PyDictObject

PySetObject

PyIntObject

PyLongObject

PyFloatObject

PyStringObject

PyUnicodeObject

[Python-Ansicht] wird nicht automatisch für Typen angezeigt, die Sie selbst erstellen. Wenn Sie Erweiterungen für Python 3.x erstellen, ist dieser Mangel in der Regel kein Problem, da jedes Objekt letztlich über ein ob_base -Feld für einen der oben genannten Typen verfügt, wodurch [Python-Ansicht] angezeigt wird.

Bei Python 2.x allerdings deklariert jeder Objekttyp seinen Header üblicherweise als Auflistung von Inlinefeldern, und es gibt keine Verknüpfung auf Typsystemebene im C/C++-Code zwischen benutzerdefiniert erstellten Typen und PyObject . Um [Python-Ansicht]-Knoten für solche benutzerdefinierten Typen zu aktivieren, bearbeiten Sie die Datei im Installationsverzeichnis für Python Tools, und fügen Sie im XML-Code ein weiteres Element für Ihre C-Struktur oder C++-Klasse hinzu. Eine alternative (und bessere) Möglichkeit ist es, den Anweisungen unter PEP 3123 zu folgen und statt PyObject_HEAD ein explizites PyObject ob_base; -Feld zu verwenden. Allerdings ist dieses Vorgehen aus Gründen der Abwärtskompatibilität nicht immer möglich.

Ansicht der nativen Werte im Python-Code

Ähnlich wie im vorherigen Abschnitt können Sie eine [C++ View] -Ansicht für native Werte im Lokalfenster aktivieren, wenn ein Python-Frame aktiv ist. Diese Funktion ist nicht standardmäßig aktiviert. Klicken Sie mit der rechten Maustaste auf das Lokalfenster, und aktivieren Sie die Menüoption Python > C++-Ansichtsknoten anzeigen.

Der [C++ View]-Knoten bietet eine Darstellung der zugrunde liegenden C/C++-Struktur für einen Wert. Dies entspricht der Darstellung, die in einem nativen Frame angezeigt werden würde. Der Knoten zeigt eine Instanz von _longobject (wofür PyLongObject eine typedef ist) für einen langen ganzzahligen Python-Wert an und versucht, Typen für native Klassen abzuleiten, die Sie selbst erstellt haben. Die untergeordneten Elemente dieses Knotens können bearbeitet werden.

Wenn ein untergeordnetes Feld eines Objekts den Typ PyObject oder einen der anderen unterstützten Typen aufweist, enthält es einen [Python-Ansicht] -Darstellungsknoten (sofern diese Darstellungen aktiviert sind). Auf diese Weise können Sie in Objektdiagrammen navigieren, wenn Links nicht direkt in Python verfügbar sind.

Anders als bei [Python-Ansicht] -Knoten, die Python-Objektmetadaten zum Ermitteln des Objekttyps verwenden, gibt es keinen ähnlich zuverlässigen Mechanismus für [C++ View] . Allgemein gesagt: Es ist nicht möglich, für einen bestimmten Python-Wert (also einen PyObject -Verweis) zuverlässig zu ermitteln, welche C/C++-Struktur diesem zugrunde liegt. Der Debugger im gemischten Modus versucht, den Typ zu „erraten“. Dazu durchsucht der Debugger verschiedene Felder des Objekttyps (z.B. dem PyTypeObject , auf das durch das Feld ob_type verwiesen wird), die über Funktionszeigertypen verfügen. Wenn einer dieser Funktionszeiger auf eine Funktion verweist, die aufgelöst werden kann, und wenn diese Funktion über einen self -Parameter verfügt, dessen Typ spezifischer ist als PyObject* , wird angenommen, dass es sich bei diesem um den zugrunde liegenden Typ handelt. Ein Beispiel: ob_type->tp_init für ein bestimmtes Objekt zeigt auf die folgende Funktion:

static int FobObject_init(FobObject* self, PyObject* args, PyObject* kwds) { return 0; }

In diesem Fall kann der Debugger ordnungsgemäß herleiten, dass der C-Typ des Objekts FobObject lautet. Wenn kein genauerer Typ aus tp_init ermittelt werden kann, sucht der Debugger in anderen Feldern weiter. Wenn aus keinem der Felder ein Typ hergeleitet werden kann, zeigt der [C++ View] -Knoten das Objekt als PyObject -Instanz an.

Um jederzeit eine sinnvolle Darstellung für benutzerdefiniert erstellte Typen zu erzielen, empfiehlt es sich, beim Registrieren des Typs mindestens eine Sonderfunktion zu registrieren und einen stark typisierten self -Parameter zu verwenden. Die meisten Typen erfüllen diese Voraussetzung von Natur aus. Sollte dies nicht der Fall sein, eignet sich tp_init in der Regel am besten für diesen Zweck. Eine Dummyimplementierung von tp_init für einen Typ, der nur dafür da ist, den Typrückschluss für den Debugger zu ermöglichen, kann sofort Null zurückgeben, wie in obigem Codebeispiel veranschaulicht.

Unterschiede zum standardmäßigen Debuggen in Python

Der Debugger für den gemischten Modus unterscheidet sich vom Python-Standarddebugger insofern, als einige zusätzliche Funktionen eingeführt werden, dafür aber einige Python-bezogene Funktionen fehlen:

Nicht unterstützte Funktionen: Bedingte Haltepunkte, Fenster zum interaktiven Debuggen und plattformübergreifendes Remotedebuggen.

und plattformübergreifendes Remotedebuggen. Direktfenster : Ist verfügbar, allerdings mit eingeschränkter Funktionalität – einschließlich aller hier aufgeführten Einschränkungen.

: Ist verfügbar, allerdings mit eingeschränkter Funktionalität – einschließlich aller hier aufgeführten Einschränkungen. Unterstützte Python-Versionen: Nur CPython 2.7 und 3.3+.

Visual Studio Shell: Bei Verwendung von Python mit Visual Studio Shell (wenn Sie Python beispielsweise mithilfe des integrierten Installationsprogramms installiert haben) kann Visual Studio keine C++-Projekte öffnen, und für C++-Dateien stehen nur die Bearbeitungsfunktionen eines einfachen Text-Editors zur Verfügung. Das C/C++-Debuggen und das Debuggen im gemischten Modus werden in Shell jedoch vollständig unterstützt, einschließlich Quellcode, Einzelschrittausführung im nativen Code und C++-Ausdrucksauswertung in Debuggerfenstern.

Anzeigen und Erweitern von Objekten: Beim Anzeigen von Python-Objekten in den Toolfenstern Lokal und Überwachung des Debuggers zeigt der Debugger im gemischten Modus nur die Struktur der Objekte an. Es werden weder automatisch Eigenschaften ausgewertet noch berechnete Attribute angezeigt. Bei Auflistungen werden nur Elemente für integrierte Auflistungstypen angezeigt ( tuple , list , dict , set ). Benutzerdefinierte Auflistungstypen werden nur dann als Auflistungen visualisiert, wenn sie von einem integrierten Auflistungstyp vererbt werden.

und des Debuggers zeigt der Debugger im gemischten Modus nur die Struktur der Objekte an. Es werden weder automatisch Eigenschaften ausgewertet noch berechnete Attribute angezeigt. Bei Auflistungen werden nur Elemente für integrierte Auflistungstypen angezeigt ( , , , ). Benutzerdefinierte Auflistungstypen werden nur dann als Auflistungen visualisiert, wenn sie von einem integrierten Auflistungstyp vererbt werden. Ausdrucksauswertung: Siehe oben.

Ausdrucksauswertung

Der Python-Standarddebugger ermöglicht die Auswertung beliebiger Python-Ausdrücke in Überwachungs- und Direktfenstern, wenn der Debuggingprozess an einem beliebigen Punkt im Code angehalten wird, sofern der Prozess nicht durch einen E/A-Vorgang oder einen anderen ähnlichen Systemaufruf blockiert wird. Beim Debuggen im gemischten Modus können beliebige Ausdrücke nur ausgewertet werden, wenn sie im Python-Code nach einem Haltepunkt beendet wurden oder Sie den Code schrittweise ausführen. Ausdrücke können nur in dem Thread ausgewertet werden, in dem der Haltepunkt oder die Ausführung in Einzelschritten aufgetreten ist.

Wenn die Ausdrucksauswertung im nativen Code oder im Python-Code angehalten wird, sofern die oben genannten Bedingungen nicht zutreffen (z.B. nach einem „Ausführen bis Rücksprung“-Vorgang oder in einem anderen Thread), ist die Auswertung auf Folgendes beschränkt: Zugriff auf lokale und globale Variablen im Geltungsbereich des aktuell ausgewählten Rahmens, Zugriff auf die zugehörigen Felder und Indizierung integrierter Auflistungstypen mit Literalen. Der folgende Ausdruck kann z.B. in jedem Kontext ausgewertet werden (vorausgesetzt, dass alle Bezeichner auf vorhandene Variablen und Felder mit geeigneten Typen verweisen):

foo.bar[0].baz['key']

Der Debugger für den gemischten Modus löst solche Ausdrücke ebenfalls anders auf. Alle Vorgänge mit Memberzugriff schlagen nur Felder nach, die ein direkter Teil des Objekts sind (z.B. ein Eintrag in __dict__ - oder __slots__ -Elementen oder einem Feld der nativen Struktur, die über tp_members für Python verfügbar gemacht wurde), und ignorieren alle __getattr__ - und __getattribute__ -Elemente sowie jegliche Deskriptorlogik. Alle Indizierungsvorgänge ignorieren __getitem__ und greifen direkt auf die inneren Datenstrukturen von Auflistungen zu.

Aus Gründen der Konsistenz wird dieses Namensauflösungsschema für alle Ausdrücke verwendet, die die Bedingungen der eingeschränkten Ausdrucksauswertung erfüllen, unabhängig davon, ob beliebige Ausdrücke am aktuellen Haltepunkt zulässig sind. Um eine ordnungsgemäße Python-Semantik zu erzwingen, wenn ein Auswerter mit vollständigem Funktionsumfang verfügbar ist, schließen Sie den Ausdruck in Klammern ein:

Andreas Müller

LEAVE A REVIEW