Zu diesem Buch – sowie zu vielen weiteren dpunkt.büchern – können Sie auch das entsprechende E-Book im PDF-Format herunterladen. Werden Sie dazu einfach Mitglied bei dpunkt.plus+:

www.dpunkt.plus

Al Sweigart

Der Weg zum Python-Profi

Ein Best-Practice-Buch für sauberes Programmieren

Al Sweigart

Lektorat: Gabriel Neumann

Bibliografische Information der Deutschen Nationalbibliothek

ISBN:

1. Auflage 2022

Copyright © 2021 by Al Sweigart. Title of English-language original: Beyond the Basic Stuff with Python: Best Practices for Writing Clean Code, ISBN 978-1-59327-966-0,

Hinweis:

Schreiben Sie uns:

Die vorliegende Publikation ist urheberrechtlich geschützt. Alle Rechte vorbehalten. Die Verwendung der Texte und Abbildungen, auch auszugsweise, ist ohne die schriftliche Zustimmung des Verlags urheberrechtswidrig und daher strafbar. Dies gilt insbesondere für die Vervielfältigung, Übersetzung oder die Verwendung in elektronischen Systemen.

5 4 3 2 1 0

Inhalt

Der Autor

Der Fachgutachter

Danksagung

Einleitung

Wer dieses Buch lesen sollte und warum

Über dieses Buch

Ihr Weg zur Programmierung

1Fehlermeldungen und Recherche

Python-Fehlermeldungen verstehen

Tracebacks untersuchen

Fehlermeldungen recherchieren

Fehler vermeiden mit Lintern

Um Hilfe bitten

Geben Sie gleich ausreichend Informationen, um Rückfragen zu vermeiden

Formulieren Sie Ihre Fragen als Fragen

Stellen Sie Ihre Fragen auf einer geeigneten Website

Geben Sie das Problem in der Überschrift an

Erklären Sie, was der Code tun soll

Geben Sie die vollständige Fehlermeldung an

Teilen Sie Ihren Code vollständig mit

Gestalten Sie Ihren Code durch saubere Formatierung lesbar

Beschreiben Sie, was Sie bereits versucht haben

Beschreiben Sie Ihre Ausstattung

Ein Beispiel für eine gut gestellte Frage

Zusammenfassung

2Die Einrichtung der Umgebung und die Befehlszeile

Das Dateisystem

Pfade in Python

Das Benutzerverzeichnis

Das aktuelle Arbeitsverzeichnis

Absolute und relative Pfade

Programme und Prozesse

Die Befehlszeile

Ein Terminalfenster öffnen

Programme an der Befehlszeile ausführen

Befehlszeilenargumente

Python-Code mit –c an der Befehlszeile ausführen

Python-Programme an der Befehlszeile ausführen

Py.exe

Befehle aus einem Python-Programm heraus ausführen

Tipparbeit durch Tabulatorvervollständigung sparen

Der Befehlsverlauf

Gebräuchliche Befehle

PATH und andere Umgebungsvariablen

Umgebungsvariablen anzeigen

Die Umgebungsvariable PATH

Die Umgebungsvariable PATH in der Befehlszeile ändern

Ordner in Windows dauerhaft zu PATH hinzufügen

Ordner in macOS und Linux dauerhaft zu PATH hinzufügen

Python-Programme außerhalb der Befehlszeile ausführen

Python-Programme in Windows ausführen

Python-Programme in macOS ausführen

Python-Programme in Ubuntu Linux ausführen

Zusammenfassung

3Codeformatierung mit Black

Wie man Freunde und Kollegen vergrault

PEP 8 und andere Stilrichtlinien

Horizontale Abstände

Leerzeichen zur Einrückung verwenden

Abstände innerhalb einer Zeile

Vertikale Abstände

Beispiel für vertikale Abstände

Empfohlene Vorgehensweisen für vertikale Abstände

Black: Der kompromisslose Codeformatierer

Black installieren

Black an der Befehlszeile ausführen

Black für einzelne Abschnitte Ihres Codes ausschalten

Zusammenfassung

4Aussagekräftige Namen

Groß- und Kleinschreibung

Namenskonventionen in PEP 8

Namen geeigneter Länge

Zu kurze Namen

Zu lange Namen

Leicht zu findende Namen

Scherze, Wortspiele und Anspielungen vermeiden

Integrierte Namen nicht überschreiben

Die allerschlechtesten Variablennamen

Zusammenfassung

5Codegerüche

Duplizierter Code

Magische Zahlen

Auskommentierter und toter Code

Print-Debugging

Variablen mit numerischen Suffixen

Klassen statt Funktionen oder Module

Verschachtelte Listennotation

Leere except-Blöcke und nichtssagende Fehlermeldungen

Legenden über Code Smells

Legende: Funktionen sollten nur eine return-Anweisung am Ende aufweisen

Legende: Funktionen mit einer try-Anweisung dürfen keine anderen Anweisungen enthalten

Legende: Flag-Argumente sind schlecht

Legende: Globale Variablen sind schlecht

Legende: Kommentare sind unnötig

Zusammenfassung

6Pythonischer Code

Python-Zen

Aussagekräftige Einrückungen

Leistung mit dem Modul timeit messen

Häufig falsch angewendete Syntax

Verwenden Sie enumerate() statt range()

Verwenden Sie with statt open() und close()

Verwenden Sie is statt == zum Vergleich mit None

Stringformatierung

Verwenden Sie Rohstrings bei einer großen Anzahl von Backslashes

F-Strings

Flache Kopien von Listen

Pythonischer Umgang mit Dictionarys

Verwenden Sie get() und setdefault() für Dictionarys

Verwenden Sie collections.defaultdict für Standardwerte

Verwenden Sie Dictionarys statt switch-Konstruktionen

Bedingte Ausdrücke: Pythons »hässlicher« ternärer Operator

Variablenwerte

Zuweisungs- und Vergleichsoperatoren verketten

Eine Variable auf Gleichheit mit mehreren Werten prüfen

Zusammenfassung

7Programmierjargon

Definitionen

Die Sprache Python und der Interpreter Python

Garbage Collection

Literale

Schlüsselwörter

Objekte, Werte und Identitäten

Elemente

Veränderbare und unveränderbare Objekte

Indizes, Schlüssel und Hashes

Container-, Folgen-, Maps- und Set-Datentypen

Dunder- oder magische Methoden

Module und Pakete

Aufrufbare Objekte und Objekte erster Klasse

Häufig verwechselte Begriffe

Anweisungen und Ausdrücke

Blöcke, Klauseln und Rümpfe

Variablen und Attribute

Funktionen und Methoden

Iterierbare Objekte und Iteratoren

Syntax-, Laufzeit- und semantische Fehler

Parameter und Argumente

Implizite und explizite Typumwandlung

Eigenschaften und Attribute

Bytecode und Maschinencode

Skripte und Programme, Skriptsprachen und Programmiersprachen

Bibliotheken, Frameworks, SDKs, Engines und APIs

Zusammenfassung

Literatur

8Häufige Fallstricke in Python

Elemente zu Listen hinzufügen und entfernen

Veränderbare Werte kopieren

Standardargumente

Strings zusammenbauen

Sortierung mit sort()

Genauigkeit von Fließkommazahlen

Verkettung von Ungleichheitsoperatoren

Das Komma in einelementigen Tupeln

Zusammenfassung

9Exotische Eigenarten von Python

256 ist 256, aber 257 ist nicht 257

String-Interning

Die Bedeutung von ++ und -- in Python

Alles von nichts

Boolesche Werte als Integer

Verkettung unterschiedlicher Operatoren

Schwerelosigkeit in Python

Zusammenfassung

10Zweckmäßige Funktionen

Funktionsnamen

Der Umfang von Funktionen

Funktionsparameter und -argumente

Standardargumente

Argumente mit * und ** an Funktionen übergeben

Variadische Funktionen mit * erstellen

Variadische Funktionen mit ** erstellen

Wrapper-Funktionen mit * und ** erstellen

Funktionale Programmierung

Nebenwirkungen

Funktionen höherer Ordnung

Lambda-Funktionen

Zuordnung und Filterung mit Listennotation

Der Datentyp von Rückgabewert

Ausnahmen auslösen oder Fehlercodes zurückgeben

Zusammenfassung

11Kommentare, Docstrings und Typhinweise

Kommentare

Formatierung von Kommentaren

Inline-Kommentare

Erklärende Kommentare

Kommentare zur Gliederung

»Lessons-Learned-Kommentare«

Rechtliche Hinweise

Professionelle Formulierung

Codetags und TODO-Kommentare

Magische Kommentare und Quelldateicodierung

Docstrings

Typhinweise

Tools zur statischen Analyse

Typhinweise für mehrere Typen

Typhinweise für Listen, Dictionarys u. Ä

Rückportierung von Typhinweisen mithilfe von Kommentaren

Zusammenfassung

12Versionssteuerung mit Git

Commits und Repositorys in Git

Neue Python-Projekte mit Cookiecutter erstellen

Git installieren

Git-Benutzername und E-Mail-Adresse angeben

GUI-Werkzeuge für Git installieren

Der Arbeitsablauf in Git

Der Dateistatus in Git

Wozu gibt es bereitgestellte Dateien?

Ein Git-Repository erstellen

Zu verfolgende Dateien hinzufügen

Einzelne Dateien ignorieren

Änderungen mit Commit bestätigen

Änderungen mit git diff vor dem Commit einsehen

Änderungen mit git difftool in einer GUI-Anwendung einsehen

Häufigkeit von Commits

Dateien löschen

Dateien umbenennen und verschieben

Das Commitprotokoll einsehen

Frühere Versionen wiederherstellen

Unbestätigte lokale Änderungen rückgängig machen

Bereitstellung einer Datei aufheben

Die letzten Commits zurücknehmen

Zurücksetzen einer einzelnen Datei zu einem bestimmten Commit

Den Commitverlauf ändern

GitHub und git push

Ein bestehendes Repository auf GitHub übertragen

Ein GitHub-Repository klonen

Zusammenfassung

13Leistungsmessung und Algorithmusanalyse

Das Modul timeit

Der Profiler cProfile

Komplexitätsanalyse

Ordnungen

Ein Bücherregal als Metapher für Ordnungen

Worst Case und Best Case

Die Ordnung Ihres Codes bestimmen

Warum Terme niedriger Ordnungen und Koeffizienten keine Rolle spielen

Beispiele für die Komplexitätsanalyse

Die Ordnung gängiger Funktionsaufrufe

Komplexitätsanalyse im Überblick

Die Ordnung spielt bei kleinem n keine Rolle – und n ist gewöhnlich klein

Zusammenfassung

14Praxisprojekte

Turm von Hanoi

Die Ausgabe

Der Quellcode

Den Code schreiben

Vier gewinnt

Die Ausgabe

Der Quellcode

Den Code schreiben

Zusammenfassung

15Klassen

Formulare als Veranschaulichung

Objekte aus Klassen erstellen

Eine einfache Klasse erstellen: WizCoin

Methoden, __init__() und der Parameter self

Attribute

Private Attribute und private Methoden

Die Funktion type() und das Attribut __qualname__

OOP- und Nicht-OOP-Code im Vergleich

Klassen für reale Objekte

Zusammenfassung

16Vererbung

Wie Vererbung funktioniert

Methoden überschreiben

Die Funktion super()

Komposition statt Vererbung

Nachteile der Vererbung

Die Funktionen isinstance() und issubclass()

Klassenmethoden

Klassenattribute

Statische Methoden

Wann brauchen Sie Klassenmerkmale und statische Methoden?

Schlagwörter der objektorientierten Programmierung

Kapselung

Polymorphismus

Wann Sie die Vererbung nicht nutzen sollten

Mehrfachvererbung

Die Reihenfolge der Methodenauflösung

Zusammenfassung

17Pythonische OOP: Eigenschaften und Dunder-Methoden

Eigenschaften

Attribute in Eigenschaften umwandeln

Set-Methoden zur Datenvalidierung

Schreibgeschützte Eigenschaften

Wann Sie Eigenschaften verwenden sollten

Dunder-Methoden

Dunder-Methoden zur Stringdarstellung

Numerische Dunder-Methoden

Reflektierte numerische Dunder-Methoden

Direkte Dunder-Methoden für erweiterte Zuweisungsoperatoren

Dunder-Methoden für Vergleiche

Zusammenfassung

Stichwortverzeichnis

Für meinen Neffen Jack

Der Autor

Al Sweigart ist Softwareentwickler und Fachbuchautor und lebt in Seattle. Python ist seine bevorzugte Programmiersprache, für die er bereits mehrere Open-Source-Module entwickelt hat. Er hat mehrere Programmierbücher für Einsteiger geschrieben, darunter Routineaufgaben mit Python automatisieren und Coole Spiele mit Scratch 3, die ebenfalls beim dpunkt.verlag erschienen sind. Die englische Originalversion seiner Bücher steht unter einer Creative-Commons-Lizenz kostenlos auf seiner Website https://www.inventwithpython.com/ zur Verfügung. Seine Katze Zophie wiegt 11 Pfund.

Der Fachgutachter

Kenneth Love ist Programmierer und Lehrer und richtet Konferenzen aus. Er ist Mitarbeiter von Django und ein PSF Fellow. Zurzeit arbeitet er als technischer Leiter und Softwareingenieur für O’Reilly Media.

Danksagung

Es ist irreführend, dass nur mein Name auf dem Titelbild steht, denn ohne die Bemühungen vieler anderer Personen hätte es dieses Buch nie gegeben. Ich möchte meinem Herausgeber Bill Pollock, meinen Lektoren Frances Saux, Annie Choi, Meg Sneeringer und Jan Cash, Herstellungsleiterin Maureen Forys, Korrektorin Anne Marie Walker und Chefredakteurin Barbara Yien danken. Ein weiteres Dankeschön geht an Josh Ellingson für ein weiteres hervorragendes Titelbild, an meinen Fachgutachter Kenneth Love und an all die großartigen Freunde, die ich in der Python-Community kennengelernt habe.

Einleitung

Hello again, world! In den späten 90er-Jahren habe ich als programmierender Teenager und Möchtegernhacker immer die neueste Ausgabe von 2600: The Hacker Quarterly studiert. Eines Tages fand ich endlich den Mut, an dem von der Zeitschrift organisierten monatlichen Treffen in meiner Heimatstadt teilzunehmen, und war beeindruckt davon, wie viel diese Leute alle wussten! (Später erkannte ich jedoch, dass viele von ihnen über weit mehr Selbstvertrauen als echte Kenntnisse verfügten.) Das ganze Treffen über lauschte ich ehrfürchtig nickend dem, was die anderen zu sagen hatten, und versuchte, den Unterhaltungen zu folgen. Danach war ich entschlossen, jede Gelegenheit zu nutzen, um mehr über Computer, Programmierung und Netzwerksicherheit zu lernen, sodass ich mich beim nächsten Treffen an den Gesprächen beteiligen konnte.

Beim nächsten Treffen hörte ich jedoch weiterhin nur zu und fühlte mich im Vergleich zu allen anderen minderbemittelt. Also fasste ich erneut den Vorsatz, zu lernen und klug genug zu werden, um mitzuhalten. Ich vertiefte mein Wissen Monat für Monat, hatte aber immer das Gefühl, hinterherzuhinken. Schließlich erkannte ich, wie umfangreich das Gebiet der Informatik war, und befürchtete, niemals genug wissen zu können.

Ich wusste damals zwar schon mehr als meine Schulfreunde, doch meine Kenntnisse reichten mit Sicherheit nicht aus, um als Softwareentwickler arbeiten zu können. In den 90er-Jahren gab es Google, YouTube und Wikipedia noch nicht, aber ich hätte auch gar nicht gewusst, wie ich sie hätte nutzen sollen. Es war mir nie klar, womit ich mich als Nächstes befassen sollte. Stattdessen lernte ich, Hallo-Welt-Programme in verschiedenen Programmiersprachen zu schreiben. Dabei hatte ich jedoch nie das Gefühl, echte Fortschritte zu machen. Ich wusste nicht, wie ich jemals über die Grundlagen hinauskommen sollte.

Zur Softwareentwicklung gehört weit mehr als Schleifen und Funktionen. Wenn Sie einen Anfängerkurs absolviert oder ein Programmierbuch für Einsteiger gelesen haben und sich nach weiterführenden Informationen umsehen, landen Sie aber leider meistens nur bei weiteren Hallo-Welt-Tutorials. Programmierer nennen diese Phase die Wüste der Verzweiflung: Sie bewegen sich ziellos durch unterschiedliche Lernstoffe, ohne das Gefühl zu haben, Fortschritte zu machen. Für Material, das sich an Anfänger richtet, wissen Sie schon zu viel, aber es fehlt Ihnen an Erfahrung, um sich den komplizierteren Themen zu widmen.

Wenn Sie sich in dieser Wüste befinden, kommen Sie sich wie ein Hochstapler vor. Sie haben nicht das Gefühl, ein »richtiger« Programmierer zu sein oder Code so schreiben zu können, wie »richtige« Programmierer es tun. Dieses Buch habe ich für Personen geschrieben, denen es genau so geht. Wenn Sie die Grundlagen von Python kennen, hilft es Ihnen, ein besserer Softwareentwickler zu werden und dieses Gefühl der Verzweiflung zu überwinden.

Wer dieses Buch lesen sollte und warum

Dieses Buch richtet sich an Leser, die bereits einen Grundkurs in Python absolviert haben und mehr lernen möchten. Bei diesem Grundkurs kann es sich um mein Buch Routineaufgaben mit Python automatisieren (dpunkt.verlag, 2020), das Buch Python 3 Crashkurs von Eric Matthes (dpunkt.verlag, 2020) oder auch eine Onlineschulung handeln.

Solche Einführungen können Ihre Begeisterung für die Programmierung wecken, allerdings gibt es danach immer noch viel zu lernen. Wenn Sie das Gefühl haben, noch nicht das Niveau eines professionellen Programmierers erreicht zu haben, und nicht wissen, wie Sie dorthin gelangen sollen, ist dies das richtige Buch für Sie.

Vielleicht haben Sie ja auch in einer anderen Sprache zu programmieren gelernt und möchten nun unmittelbar in das Python-Umfeld mit allen seinen Tools wechseln, ohne die typischen Hello-World-Grundlagen wiederzukäuen. In diesem Fall brauchen Sie nicht erst Hunderte von Seiten durchzuarbeiten, die die grundlegende Syntax erklären. Es reicht, wenn Sie sich den Artikel »Learn Python in Y Minutes« auf https://learnxinyminutes.com/docs/python ansehen oder Eric Matthes’ Python-Spickzettel von »Python Crash Course – Cheat Sheet« auf https://ehmatthes.github.io/pcc/cheatsheets/README.html herunterladen, bevor Sie dieses Buch in Angriff nehmen.

Über dieses Buch

In diesem Buch geht es nicht nur um Python-Syntax für Fortgeschrittene, sondern auch um die Verwendung der Befehlszeile und von Tools wie Codeformatierern, Lintern und Versionssteuerung, die auch professionelle Entwickler einsetzen.

Ich erkläre Ihnen, was Code gut lesbar macht und wie Sie sauberen Code schreiben können. Zur Veranschaulichung dieser Prinzipien stelle ich einige Programmierprojekte vor. Dies soll zwar kein Lehrbuch in Informatik werden, aber dennoch werden wir uns auch mit der O-Notation und objektorientierter Entwicklung beschäftigen.

Ein Buch allein reicht nicht aus, um jemanden zu einem professionellen Softwareentwickler zu machen. Ich habe dieses Buch geschrieben, um Ihre Kenntnisse zu vertiefen und Ihnen dadurch auf diesem Weg weiterzuhelfen. Dabei spreche ich auch einige Themen an, die Sie anderenfalls nur nach und nach durch Erfahrung lernen würden. Dieses Buch verschafft Ihnen eine solide Grundlage, sodass Sie gut für neue Herausforderungen gerüstet sind.

Ich rate Ihnen zwar dazu, das Buch von vorn bis hinten zu lesen, aber wenn ein Thema Sie besonders interessiert, können Sie auch gern zu dem betreffenden Kapitel vorblättern.

Teil I: Erste Schritte

  • Kapitel 1: Fehlermeldungen und RechercheZeigt Ihnen, wie Sie erfolgreich Fragen stellen und selbstständig Lösungen finden können. Außerdem erfahren Sie hier, wie Fehlermeldungen zu lesen sind und welche Verhaltensregeln Sie beachten müssen, wenn Sie online um Hilfe bitten.
  • Kapitel 2: Die Einrichtung der Umgebung und die BefehlszeileErklärt, wie Sie sich an der Befehlszeile zurechtfinden und wie Sie Ihre Entwicklungsumgebung sowie die Umgebungsvariable PATH einrichten.

Teil II: Werkzeuge, Techniken und bewährte Vorgehensweisen

  • Kapitel 3: Codeformatierung mit BlackBeschreibt die Stilrichtlinie PEP 8 und erklärt, wie Sie Ihren Code formatieren sollten, um ihn besser lesbar zu machen. Sie erfahren hier auch, wie Sie diesen Vorgang mit dem Codeformatierungswerkzeug Black automatisieren können.
  • Kapitel 4: Aussagekräftige NamenErklärt, wie Sie Variablen und Funktionen benennen sollten, um Ihren Code übersichtlicher zu gestalten.
  • Kapitel 5: CodegerücheBeschreibt Warnzeichen, die auf mögliche Bugs in Ihrem Code hinweisen.
  • Kapitel 6: Pythonischer CodeErklärt, was Code pythonisch macht, und zeigt Vorgehensweisen auf, um solchen idiomatischen Python-Code zu schreiben.
  • Kapitel 7: ProgrammierjargonErklärt Fachbegriffe, die in der Programmierung verwendet werden, sowie Begriffe, die oft verwechselt werden.
  • Kapitel 8: Häufige Fallstricke in PythonBeschreibt Aspekte von Python, die oft zu Missverständnissen oder zu Bugs führen, und zeigt Korrekturmaßnahmen sowie Möglichkeiten auf, solche Schwierigkeiten zu vermeiden.
  • Kapitel 9: Exotische Eigenarten von PythonBehandelt einige seltsame Eigenheiten von Python wie String-Interning oder das Schwerelosigkeits-Easter-Egg, auf die Sie sonst kaum stoßen würden. Vor allem aber erfahren Sie, warum sich einige Datentypen und Operatoren unerwartet verhalten, und erlangen dadurch ein tieferes Verständnis der Funktionsweise von Python.
  • Kapitel 10: Zweckmäßige FunktionenZeigt, wie Sie Funktionen strukturieren sollten, um sie zweckmäßig und übersichtlich zu gestalten. Sie lernen hier die Verwendung von * und ** in der Syntax für Argumente, die Vor- und Nachteile von umfangreichen und kleinen Funktionen sowie funktionale Programmiertechniken wie Lambda-Funktionen kennen.
  • Kapitel 11: Kommentare, Docstrings und TyphinweiseErklärt, warum die nicht funktionalen Bestandteile von Programmen wichtig sind und wie sie dazu beitragen, dass sich der Code besser pflegen lässt. Sie erfahren hier, wie dicht Kommentare und Docstrings gesät sein sollten und wie Sie sie möglichst informativ gestalten können. Außerdem geht es in diesem Kapitel um Typhinweise und um die Verwendung von statischen Analysatoren wie Mypy zum Aufspüren von Bugs.
  • Kapitel 12: Versionssteuerung mit GitErklärt, wie Sie mit dem Versionssteuerungssystem Git den Verlauf von Änderungen am Quellcode aufzeichnen und zu früheren Versionen zurückkehren oder das erste Auftreten eines Bugs aufspüren können. Des Weiteren wird beschrieben, wie Cookiecutter Ihnen hilft, die Dateien für Ihre Codeprojekte zu strukturieren.
  • Kapitel 13: Leistungsmessung und AlgorithmusanalyseErklärt, wie Sie die Geschwindigkeit Ihres Codes mithilfe der Module timeit und cProfile objektiv messen können. Darüber hinaus lernen Sie die Algorithmusanalyse mit der O-Notation kennen, mit der Sie vorhersagen können, wie sich die Codeausführung mit zunehmender Datenmenge verlangsamt.
  • Kapitel 14: PraxisprojekteHier wenden Sie die in Teil II erlernten Techniken in der Praxis an, indem Sie zwei Befehlszeilenspiele schreiben, nämlich Turm von Hanoi, bei dem es darum geht, Scheiben von einem Turm auf einen anderen umzustapeln, und Vier gewinnt.

Teil III: Objektorientiertes Python

  • Kapitel 15: KlassenErläutert die Bedeutung der objektorientierten Programmierung (OOP), da sie oft missverstanden wird. Viele Entwickler wenden OOP-Techniken im Übermaß an, da sie glauben, dies wäre die übliche Vorgehensweise, und machen ihren Code dadurch unnötig kompliziert. In diesem Kapitel erfahren Sie, wie Klassen geschrieben werden, aber vor allem, wann Sie es tun sollten und wann nicht.
  • Kapitel 16: VererbungErklärt die Vererbung von Klassen und deren praktischen Nutzen für die Wiederverwendung von Code.
  • Kapitel 17: Pythonische OOP: Eigenschaften und Dunder-MethodenBeschreibt Python-spezifische Merkmale für objektorientierte Programmierung wie Eigenschaften, Dunder-Methoden und Operatorüberladung.

Ihr Weg zur Programmierung

Auf dem Weg vom Anfänger zum erfahrenen Programmierer fühlt man sich oft so, als ob man versucht, aus einem unter hohem Druck stehenden Feuerwehrschlauch zu trinken. Angesichts des großen Angebots an Lernstoff sorgen sich viele, ihre Zeit mit ungeeigneten Programmieranleitungen zu vergeuden.

Nachdem Sie dieses Buch gelesen haben (oder vielleicht sogar schon während der Lektüre), sollten Sie sich die folgenden weiteren einführenden Werke ansehen:

  • Python 3 Crashkurs (dpunkt.verlag, 2020) von Eric Matthes richtet sich zwar an Anfänger, vermittelt dank seines projektgestützten Lehransatzes aber auch erfahrenen Programmierern eine Vorstellung der Python-Bibliotheken Pygame, Matplotlib und Django.
  • Impractical Python Projects (No Starch Press, 2018) von Lee Vaughan erweitert Ihre Python-Fertigkeiten anhand von Projekten. Die Programme, die Sie aufgrund der Anleitungen in diesem Buch erstellen, machen Spaß und stellen eine großartige Übung dar.
  • Serious Python (No Starch Press, 2018) von Julien Danjos erklärt, was Sie tun müssen, um sich von einem Hobbyprogrammierer zu einem erfahrenen Softwareentwickler zu mausern, die empfohlenen Vorgehensweisen der Branche zu befolgen und skalierbaren Code zu schreiben.

Die technischen Aspekte sind aber nur eine Stärke von Python. Rund um diese Programmiersprache ist auch eine bunte Community gewachsen. Sie ist für die gut zugängliche Dokumentation und den Support verantwortlich, die unter Programmiersprachen ihres Gleichen suchen. Es gibt jährliche PyCon-Konferenzen sowie viele regionale Zusammenkünfte mit vielfältigen Vorträgen, die sich an Programmierer mit unterschiedlicher Erfahrung richten. Diese Vorträge können Sie sich auch kostenlos online auf https://pyvideo.org/ ansehen. Um Vorträge zu Ihren Interessengebieten zu finden, schlagen Sie auf der Seite Tags nach.

Um sich intensiver mit den anspruchsvolleren Aspekten der Syntax von Python und der Standardbibliothek zu beschäftigen, empfehle ich Ihnen die Lektüre der folgenden Titel:

  • Effektiv Python programmieren (mitp, 2020) von Brett Slatkin bietet eine beeindruckende Zusammenstellung von empfohlenen pythonischen Vorgehensweisen und Sprachmerkmalen.
  • Python Cookbook (O’Reilly Media, 2013) von David Beazley und Brian K. Jones wartet mit einer umfangreichen Menge von Codebausteinen auf, mit denen Python-Neulinge ihr Repertoire erweitern können.
  • Fluent Python (O’Reilly Media, 2021) von Luciano Ramalho ist ein Meisterwerk, das die Feinheiten von Python erklärt. Sein Umfang von fast 800 Seiten mag abschreckend wirken, aber die Lektüre ist mit Sicherheit der Mühe wert.

Viel Glück auf Ihrem Weg zur besseren Programmierung! Fangen wir an!

1

Fehlermeldungen und Recherche

Vermenschlichen Sie niemals Computer – das können die nämlich überhaupt nicht leiden! Aber im Ernst: Wenn Ihnen ein Computer eine Fehlermeldung präsentiert, dann liegt das nicht daran, dass Sie ihn beleidigt hätten. Computer sind zwar die anspruchsvollsten Werkzeuge, mit denen die meisten von uns jemals zu tun bekommen, aber sie sind und bleiben nun mal nichts anderes als Werkzeuge.

Dennoch sind wir schnell geneigt, diesen Werkzeugen Schuld zuzuschieben. Wenn Sie programmieren lernen, sind Sie dabei zum größten Teil auf sich selbst gestellt. Dabei kann man sich schnell als Versager fühlen, wenn man immer noch mehrmals täglich im Internet nachforscht, auch wenn man sich bereits seit Monaten mit Python beschäftigt. Aber selbst professionelle Softwareentwickler suchen im Internet oder schlagen in der Dokumentation nach, um Fragen zur Programmierung zu klären.

Sofern Sie nicht über die Geldmittel oder die guten Kontakte verfügen, um einen Privatlehrer zu engagieren, der Ihnen alle Fragen rund ums Programmieren beantwortet, stehen Ihnen nur Ihr Computer, die Suchmaschinen im Internet und Ihre eigene Geschicklichkeit zur Verfügung. Glücklicherweise aber wurden die Fragen, die Sie haben, mit hoher Wahrscheinlichkeit schon einmal gestellt. Für Programmierer ist es viel wichtiger, selbstständig Antworten zu finden, als irgendwelche Algorithmen oder Datenstrukturen zu kennen. In diesem Kapitel erfahren Sie, wie Sie sich diese unverzichtbare Fähigkeit aneignen können.

Python-Fehlermeldungen verstehen

Bei der Konfrontation mit einer Fehlermeldung, die einen Riesenwust von Technoblabla enthält, neigen viele Programmierer in einem ersten Impuls heraus dazu, sie völlig zu ignorieren. Allerdings versteckt sich in dieser Meldung die Antwort auf die Frage, was bei dem Programm schiefläuft. Um diese Antwort zu finden, sind zwei Schritte erforderlich: Sie müssen die Ablaufverfolgung (Traceback) untersuchen und die Fehlermeldung im Internet recherchieren.

Tracebacks untersuchen

Python-Programme stürzen ab, wenn der Code eine Ausnahme auslöst, die nicht von einer except-Anweisung behandelt wird. Wenn das geschieht, zeigt Python die Meldung dieser Ausnahme und ein Traceback (oder auch Stacktrace oder Ablaufverfolgung) an. Darin ist die Stelle in dem Programm angegeben, an der die Ausnahme ausgelöst wurde, sowie der Ablauf der Funktionsaufrufe, die dorthin geführt haben.

Um das Lesen von Tracebacks zu üben, geben Sie das folgende fehlerhafte Programm ein und speichern es als abcTraceback.py. Die Zeilennummern dienen hier nur zur Orientierung und gehören nicht mit zu dem Programm.

1. def a():

2. print('Start of a()')

3. b() # Ruft b() auf.

4.

5. def b():

6. print('Start of b()')

7. c() # Ruft c() auf.

8.

9. def c():

10. print('Start of c()')

11. 42 / 0 # Verursacht eine Division durch null.

12.

13. a() # Ruft a() auf.

In diesem Programm ruft a() die Funktion b() auf und diese wiederum c() . Innerhalb von c() aber führt der Ausdruck 42 / 0 zu einem Fehler aufgrund der Division durch null. Wenn Sie dieses Programm ausführen, erhalten Sie folgende Ausgabe:

Start of b()

Start of c()

Traceback (most recent call last):

File "abcTraceback.py", line 13, in <module>

a() # Ruft a() auf.

File "abcTraceback.py", line 3, in a

b() # Ruft b() auf.

File "abcTraceback.py", line 7, in b

c() # Ruft c() auf.

File "abcTraceback.py", line 11, in c

42 / 0 # Verursacht eine Division durch null.

ZeroDivisionError: division by zero

Sehen wir uns diese Ablaufverfolgung nun Zeile für Zeile an. Dabei fangen wir mit der folgenden Zeile an:

Traceback (most recent call last):

Diese Meldung besagt, dass als Nächstes ein Traceback folgt. Die Angabe most recent call last bedeutet, dass die Funktionsaufrufe in chronologischer Reihenfolge aufgeführt werden, also von der zuerst bis zu der zuletzt aufgerufenen Funktion.

Die nächste Zeile gibt dann den ersten Funktionsaufruf aus:

File "abcTraceback.py", line 13, in <module>

a() # Ruft a() auf.

Diese beiden Zeilen bilden eine Frame-Übersicht und geben die Informationen an, die sich in einem Frame-Objekt befinden. Beim Aufruf einer Funktion werden die Daten der lokalen Variablen sowie die Stelle im Code, zu der nach dem Ende des Funktionsaufrufs zurückgesprungen werden soll, in einem solchen Objekt gespeichert. Frame-Objekte enthalten also die Daten der lokalen Variablen und weitere Daten, die im Zusammenhang mit einem Funktionsaufruf stehen. Sie werden erstellt, wenn eine Funktion aufgerufen wird, und zerstört, wenn die Funktion die Steuerung zurückgibt. Das Traceback enthält eine Frame-Übersicht für jeden Frame bis zum Absturz. Dieser Übersicht können wir entnehmen, dass der Funktionsaufruf in Zeile 13 von abcTracebyck.py erfolgte. Die Angabe <module> teilt uns außerdem mit, dass sich die Zeile im globalen Gültigkeitsbereich befindet. Mit einer Einrückung um zwei Stellen wird außerdem die Zeile 13 ausgegeben.

Die nächsten vier Zeilen enthalten zwei weitere Frame-Übersichten:

File "abcTraceback.py", line 3, in a

b() # Ruft b() auf.

File "abcTraceback.py", line 7, in b

c() # Ruft c() auf.

Die Angabe line 3, in a sagt uns, dass b() in Zeile 3 innerhalb der Funktion a() aufgerufen wurde. Das wiederum führte dazu, dass in Zeile 7 innerhalb von b() die Funktion c() aufgerufen wurde. Beachten Sie, dass die Aufrufe von print() in Zeile 2, 6 und 10 im Traceback nicht erscheinen, obwohl sie vor den Funktionsaufrufen ausgeführt wurden. In einer Ablaufverfolgung werden nur die Zeilen mit den Funktionsaufrufen bis zum Auslösen der Ausnahme ausgegeben.

Die letzte Frame-Übersicht gibt die Zeile an, in der die nicht behandelte Ausnahme ausgelöst wurde, gefolgt vom Namen und der Meldung dieser Ausnahme:

File "abcTraceback.py", line 11, in c

42 / 0 # Verursacht eine Division durch null.

ZeroDivisionError: division by zero

Die angegebene Nummer ist diejenige der Zeile, in der Python den Fehler bemerkt hat. Die eigentliche Ursache des Fehlers kann sich jedoch durchaus weiter vorn befinden.

Fehlermeldungen sind berüchtigt für ihre Kürze und Rätselhaftigkeit. Die drei Wörter division by zero werden Ihnen nicht viel sagen, sofern Sie nicht wissen, dass eine Division durch null mathematisch unmöglich ist und einen häufigen Bug in Software darstellt. In diesem Programm ist der Fehler nicht sehr schwer zu finden. Ein Blick auf die Codezeile in der Frame-Übersicht genügt, um zu erkennen, wo in dem Code 42 / 0 die Division durch null erfolgt.

Sehen wir uns nun aber ein kniffligeres Beispiel an. Geben Sie den folgenden Code in einen Texteditor ein und speichern Sie ihn als zeroDevideTraceback.py:

def spam(number1, number2):

return number1 / (number2 - 42)

spam(101, 42)

Wenn Sie dieses Programm ausführen, erhalten Sie folgende Ausgabe:

Traceback (most recent call last):

File "zeroDivideTraceback.py", line 4, in <module>

spam(101, 42)

File "zeroDivideTraceback.py", line 2, in spam

return number1 / (number2 - 42)

ZeroDivisionError: division by zero

Die Fehlermeldung ist die gleiche wie zuvor, aber die Division durch null in return number1 / (number2 - 42) lässt sich nicht so leicht erkennen. Der Operator / zeigt Ihnen, dass hier eine Division erfolgt, und offensichtlich wird der Ausdruck (number2 - 42) zu 0 ausgewertet. Daraus können Sie schließen, dass die Funktion spam() fehlschlägt, wenn der Parameter number2 auf 42 gesetzt wird.

Manchmal gibt ein Traceback auch eine Zeile aus, die hinter der eigentlichen Ursache des Bugs liegt. Betrachten Sie dazu das folgende Programm, bei dem in der ersten Zeile die schließende Klammer fehlt:

print('Hello.'

print('How are you?')

Die Fehlermeldung aber weist auf ein Problem in der zweiten Zeile hin:

File "example.py", line 2

print('How are you?')

^

SyntaxError: invalid syntax

Der Grund dafür ist, dass der Python-Interpreter den Syntaxfehler erst bemerkt, wenn er die zweite Zeile liest. Das Traceback zeigt Ihnen, wo etwas schiefgeht, aber dort liegt nicht immer die Ursache des Fehlers. Wenn die Frame-Übersicht Ihnen nicht genügend Informationen gibt, um den Bug zu erkennen, oder wenn die wahre Ursache in einer vorherigen Zeile steckt, dann müssen Sie das Programm mit einem Debugger durchgehen oder Protokollmeldungen durchsuchen, um den Fehler zu finden. Eine Internetrecherche der Fehlermeldung kann Ihnen dabei entscheidende Hinweise geben.

Fehlermeldungen recherchieren

Fehlermeldungen sind sehr kurz und oft nicht einmal ganze Sätze. Da Programmierer sie häufiger zu Gesicht bekommen, sind sie eher als Gedächtnisstützen gedacht und weniger als ausführliche Erklärungen. Wenn Sie eine neue Fehlermeldung zum ersten Mal sehen, können Sie sie kopieren und in eine Suchmaschine einfügen. Dadurch erhalten Sie oft ausführliche Erklärungen darüber, was die Meldung besagt und was die möglichen Ursachen sein können. Abbildung 1–1 zeigt die Ergebnisse einer Suche nach python »ZeroDivisonError: division by zero«. Die Anführungszeichen sorgen dafür, dass Vorkommen der genauen Formulierung gefunden werden, und der Zusatz python engt die Suche sinnvoll ein.

Abb. 1–1Durch das Kopieren einer Fehlermeldung in eine Suchmaschine können Sie Erklärungen und Lösungsvorschläge schnell finden.

Fehlermeldungen zu recherchieren, hat nichts mit Schummeln zu tun. Niemand kann sich sämtliche Fehlermeldungen merken, die in einer Programmiersprache auftreten können. Professionelle Softwareentwickler nutzen täglich das Internet, um Fragen zur Programmierung zu klären.

Es ist sinnvoll, bei der Suche den Teil der Fehlermeldung auszuschließen, der sich ausschließlich auf Ihren Code bezieht. Betrachten Sie zum Beispiel die folgenden Fehlermeldungen:

>>> print(employeRecord)

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

NameError: name 'employeRecord' is not defined

>>> 42 - 'hello'

Traceback (most recent call last):

File "<stdin>", line 1, in <module>

TypeError: unsupported operand type(s) for -: 'int' and 'str'

In diesem Beispiel wurde eine Variable als employeRecord falsch geschrieben, was einen Fehler hervorruft . Da der Bezeichner employeRecord in der Meldung NameError: name 'employeRecord' is not defined nur in Ihrem Code eine Bedeutung hat, sollten Sie nicht nach dem gesamten Text der Meldung suchen, sondern nur nach python »NameError: name« »is not defined«. In der letzten Zeile beziehen sich die Angaben 'int' und 'str' in der Fehlermeldung auf die Werte 42 und 'hello', weshalb es sinnvoll ist, nur nach python »TypeError: unsupported operand type(s)« zu suchen. Wenn Sie mit solchen verkürzten Suchbegriffen keinen Erfolg haben, können Sie versuchen, nach dem kompletten Text der Fehlermeldung zu forschen.

Fehler vermeiden mit Lintern

Besser, als Fehler zu beheben, ist es natürlich, sie von vornherein zu vermeiden. Sogenannte Linter sind Anwendungen, die Ihren Quellcode analysieren und Sie auf mögliche Fehler hinweisen. Der Name ist übrigens von den Fusselsieben von Waschmaschinen und Trocknern abgeleitet. Auch wenn Linter nicht sämtliche Fehler finden können, sind sie doch in der Lage, mithilfe einer statischen Analyse (also einer Untersuchung des Quellcodes, ohne ihn auszuführen) gängige Probleme etwa aufgrund von falschen Schreibungen aufzuspüren. (In Kapitel 11 werden wir uns ansehen, wie Sie Typhinweise zur statischen Analyse einsetzen können.) Viele Texteditoren und integrierte Entwicklungsumgebungen (IDEs) verfügen über einen Linter, der im Hintergrund läuft und Probleme in Echtzeit aufzeigen kann (siehe Abb. 1–2).

Abb. 1–2Ein Linter weist auf eine nicht definierte Variable hin – in Mu (oben), PyCharm (Mitte) und Sublime Text (unten).

Da Linter Sie fast sofort auf Fehler hinweisen, tragen sie zu einer erheblichen Steigerung Ihrer Produktivität bei. Ohne sie müssten Sie das Programm erst ausführen, um festzustellen, dass es abstürzt, und dann das Traceback lesen und die Zeile in Ihrem Quellcode finden, in der sich der Tippfehler befindet. Ein solcher Ausführungs-Korrektur-Zyklus kann außerdem immer nur einen solchen Fehler auf einmal finden. Ein Linter dagegen macht Sie auf mehrere Fehler zugleich aufmerksam, und zwar direkt im Editor, sodass Sie sofort die Zeile sehen, um die es geht.

Wenn Ihr Editor oder Ihre IDE nicht über einen Linter verfügt, aber Plug-ins unterstützt, gibt es mit hoher Wahrscheinlichkeit einen Linter dafür. Solche Plug-ins nutzen für die Analyse gewöhnlich ein Lintingmodul wie Pyflakes o. Ä. Pyflakes können Sie auf https://pypi.org/project/pyflakes/ oder mit pip install --user pyflakes installieren. Die Mühe lohnt sich.

Hinweis

Unter Windows können Sie die Befehle python und pip verwenden, aber unter macOS und Linux gelten diese Befehle nur für Python Version 2. Für Version 3 müssen Sie dort python3 und pip3 schreiben. Denken Sie daran, wenn in diesem Buch python oder pip erwähnt werden.

IDLE, die im Lieferumfang von Python enthaltene IDE, hat keinen Linter und bietet auch nicht die Möglichkeit, einen zu installieren.

Um Hilfe bitten

Wenn Sie ein Problem weder durch eine Recherche im Internet noch mithilfe eines Linters lösen können, bleibt Ihnen noch die Möglichkeit, im Internet um Hilfe zu bitten. Dabei müssen Sie jedoch die Etikette beachten und Ihre Fragen möglichst effizient stellen. Wenn sich erfahrene Softwareentwickler schon bereit erklären, Ihre Fragen kostenlos zu beantworten, dann sollten Sie deren Zeit tunlichst nicht verschwenden.

Fremde um Hilfe beim Programmieren zu bitten, sollte immer die letzte Möglichkeit sein. Es können Stunden oder gar Tage vergehen, bis jemand auf Ihre Frage antwortet – wenn überhaupt. Es geht viel schneller, im Web danach zu suchen, ob andere bereits die gleiche Frage gestellt haben, und dann die Antworten zu lesen. Onlinedokumentation und Suchmaschinen wurden schließlich erfunden, um den Aufwand für die Beantwortung von Fragen zu reduzieren.

Wenn Sie aber bereits alle anderen Möglichkeiten ausgeschöpft haben und andere Menschen um Hilfe bei Ihren Programmierproblemen bitten müssen, sollten Sie unbedingt die folgenden häufig zu beobachtenden Fehler vermeiden: