Home | Lehre | Videos | Texte | Vorträge | Software | Person | Impressum, Datenschutzerklärung | Blog RSS

Stand: 2025-04-14, erzeugt von ChatGPT DeepResearch, redigiert/korrigiert/ergänzt von Jörn Loviscach und ChatGPT 4o, überprüft mit Gemini 2.5 Pro Experimental 03-25

Unterschiede zwischen C, C++ und Python

Aspekt C C++ Python
Grundprinzip C ist eine kompakte, prozedurale, typischerweise kompilierte Sprache ohne Klassen oder Objekte. Variablen müssen vor der Nutzung typisiert und deklariert werden. C ist sehr nahe an der Art, wie der Prozessor die Programme ausführt, was typischerweise zu kleineren, schnelleren und in Rechenleistung und Speicherplatz sparsamen Programmen führt, aber beim Programmieren Komfort kostet. C++ erweitert C um Objektorientierung (Klassen, Vererbung, Polymorphie). Es ist ebenfalls kompiliert und erlaubt sowohl prozedurales als auch OOP-Paradigma. C++ kann in Ausführungsgeschwindigkeit und Speicherbedarf oft mit C konkurrieren, unterstützt aber wesentlich elegantere Programmierstile. Python ist eine typischerweise interpretierte, dynamisch typisierte Skriptsprache. (Allerdings wird es je nach Implementierung auch kompiliert.) Variablen sind Namen für Objekte und können verschiedene Typen annehmen, ohne Deklaration. Python unterstützt prozedurales, objektorientiertes und funktionales Programmieren. Python bietet großen Komfort beim Programmieren, benötigt dafür aber viel Rechenleistung und Speicherplatz. Aufwendige Rechnungen (zum Beispiel für KI) verlagert man deshalb in Bibliotheken, die etwa in C geschrieben sind.
Typisierung Statisch und schwach: Variablen haben feste Typen (z. B. int, char), die der Compiler prüft. In C gibt es erst seit C99 einen separaten Bool-Typ; Nicht-Null-Werte gelten als „wahr“. Statisch und schwach: Ähnlich wie C (z. B. int, double). C++ führt einen eigenen bool-Typ ein (mit Werten true/false). Die Typprüfung erfolgt zur Compile-Zeit; implizite Typkonvertierungen sind möglich (z. B. int zu double). Dynamisch und stark: Typen werden erst zur Laufzeit erkannt; eine Variable kann zunächst eine Zahl und später einen String halten. Gleichzeitig ist Python stark typisiert: inkompatible Typen werden nicht stillschweigend umgewandelt, aber 1 + 2.0 ist erlaubt. Für Wahrheitswerte existiert bool mit True/False (wobei z. B. leere Listen und None als False gelten). Type Hints der Art a: list[int] = [] in Python ermöglichen es, Typen für Funktionsparameter, Rückgabewerte und Variablen explizit anzugeben. Diese Hinweise dienen primär der statischen Code-Analyse und Dokumentation, indem sie Entwickler-Tools und Linter unterstützen, ohne dabei das Laufzeitverhalten zu verändern. Sie verbessern die Lesbarkeit und Wartbarkeit von Code, besonders in größeren Projekten.
Syntax & Codeblöcke Codeblöcke werden durch geschweifte Klammern {} gruppiert. Jede Anweisung endet mit einem Semikolon ;. Die Leserlichkeit hängt stark vom Programmierstil ab; Einrückungen sind nicht zwingend. C++ verwendet dieselben Blockstrukturen wie C mit {} und ;. Zusätzlich bietet C++ namespace-Definitionen, um Namensräume für Gruppen von Funktionen/Klassen zu schaffen und Namenskollisionen zu vermeiden. Python verwendet zur Blockbildung Einrückungen anstelle von Klammern. Jede Code-Einrückungsstufe definiert einen Block. Zeilenenden markieren automatisch das Ende einer Anweisung. Diese erzwungene klare Blockstruktur erhöht die Lesbarkeit deutlich. (Falls unbedingt gewünscht, erlaubt Python auch, mehrere Anweisungen getrennt mit Semikolons in eine einzige Zeile zu schreiben.)
Bezeichner & Namenskonventionen In C dürfen Namen aus Buchstaben, Zahlen und Unterstrichen bestehen, dürfen aber nicht mit einer Zahl beginnen. Groß- und Kleinschreibung wird unterschieden. Gültige Namen: sum, my_var, MAX_VALUE. Häufig wird snake_case verwendet, in Makros dagegen GROSSBUCHSTABEN. Umlaute und Unicode-Zeichen sind nicht erlaubt. In C++ gelten dieselben Regeln wie in C. Für Klassen, Methoden und Templates ist CamelCase oder PascalCase üblich, für Variablen oft snake_case. Konventionen variieren je nach Code-Stil (z. B. Google im Unterschied zu Qt). Unicode in Bezeichnern ist theoretisch erlaubt, aber selten und problematisch. In Python gelten ähnliche Regeln: Namen dürfen Buchstaben, Ziffern und Unterstriche enthalten, aber nicht mit einer Ziffer beginnen. Auch Python unterscheided Groß und Kleinschreibung. Die Konvention (PEP 8) ist: snake_case für Variablen und Funktionen, CamelCase für Klassen, und ein führender Unterstrich (_foo) signalisiert intern. Zwei führende Unterstriche (__foo) lösen Namens-Mangling aus. Unicode (allerdings keine Emojis und Satzzeichen) in Namen ist ab Python 3 erlaubt, wird aber aus Lesbarkeitsgründen selten genutzt.
Kommentare In C beginnen einzeilige Kommentare mit //, mehrzeilige Kommentare stehen zwischen /* und */. C++ verwendet dieselben Kommentarzeichen wie C. In Python beginnt ein Kommentar mit # und gilt bis zum Ende der Zeile. Mehrzeilige Kommentare schreibt man entweder mit mehreren #-Zeilen oder als (zweckentfremdete) mehrzeilige Strings mit ''' ... ''', wobei letztere oft benutzt werden, um automatisch Dokumentationen zu erzeugen.
Einfache Operatoren Inkrement: C bietet ++ und -- sowohl als Präfix (++i) als auch als Postfix (i++) zum Erhöhen/Verringern von Zahlen um 1. Logisch NICHT: ! negiert boolesche Ausdrücke. Logisch UND/ODER: && und || werten wie üblich aus – mit Kurzschlussauswertung (wenn a && b, wird b nicht geprüft, falls a schon false ist). Exklusives ODER: ^ ist streng genommen kein üblicher logischer Operator, sondern das bitweise XOR. Inkrement: C++ übernimmt ++/--, !, && und || von C. Zusätzliche Operatoren: C++ erlaubt Operatorüberladung, so dass man z. B. den +-Operator für eigene Klassen neu definieren können, um ihn je nach Zusammenhang anders wirken zu lassen. Inkrement: Python hat keine Operatoren ++/--. Stattdessen erhöht man Zahlen z. B. mit i += 1 um 1. Logisch NICHT: not negiert logische Ausdrücke. UND/ODER: and und or sind die entsprechenden Schlüsselwörter. Sie nutzen ebenfalls Kurzschlussauswertung. Besonderheit: Anders als in C/C++ liefert and/or in Python nicht wahr oder falsch als Ergebnis, sondern einen der Operanden. Zum Beispiel ergibt [] or 13 deshalb 13.
Mathematische Operatoren Potenzierung: Kein eigener Operator; man verwendet die Bibliotheksfunktion pow(x, y) aus <math.h>. ^ bedeutet hier bitweises XOR, nicht Potenz. Ganzzahldivision: / zwischen Integern führt ebenfalls Ganzzahldivision aus, d. h. 7/3 ergibt die Ganzzahl 2, aber schon 7.0/3 liefert 2,333… Potenzierung: Kein spezieller Operator, stattdessen die Funktion std::pow(base, exp) aus <cmath>. Ganzzahldivision: wie in C. Python unterstützt einen Operator Potenzierung namens **. Zum Beispiel ist 2 ** 3 gleich 8. Alternativ kann auch pow(2, 3) genutzt werden. Für die Ganzzahldivision gibt es den eigenen Operator //, so dass z. B. 7//3 gleich 2 ist, während 7/3 die Gleitkommazahl 2,333… liefert.
Standard-Bibliothek & Funktionen Ein-/Ausgabe: C nutzt Funktionen wie printf/scanf aus <stdio.h>. Die Formatierung erfolgt über Format-Strings, z. B. printf("Wert: %d", x);. Mathe-Funktionen: In C stellt <math.h> Funktionen wie sin(), cos(), sqrt() bereit, die in der Regel mit double-Werten arbeiten. Diese benötigen oft die Linker-Option -lm (math-Bibliothek). Ein-/Ausgabe: C++ bietet den Typ-sicheren IO-Stream std::cout/std::cin (mit Operator << bzw. >>) sowie weiterhin printf für spezielle Fälle. Beispiel: std::cout << "Wert: " << x << std::endl;. Mathe-Bibliothek: <cmath> stellt dieselben Funktionen wie C zur Verfügung, aber auch überladen für versch. Typen (float, double, long double). Zudem existiert in C++ <complex> für komplexe Zahlen mit std::pow usw. in komplexer Arithmetik. Ein-/Ausgabe: Die Ausgabe erfolgt über die eingebaute Funktion print(), die beliebig viele Argumente nacheinander ausgibt. Sie hängt automatisch einen Zeilenumbruch an, was sich aber nach der Art print("Hallo", end="") unterdrücken lässt. Formatierung kann über f-Strings erfolgen, z. B. print(f"Dies ist der Wert: {x:.2f}"), um die Gleitkommazahl in x mit zwei Nachkommastellen auszugeben. Mathe-Bibliothek: Python stellt das math-Modul bereit (import math), das Funktionen wie math.sin(x) und math.pow(x, y) (ähnlich dem ** Operator) enthält. Zusätzlich gibt es cmath für komplexe Arithmetik.
Datenstrukturen Arrays & Strukturen: C verwendet Arrays als Sammlung gleichartiger Elemente. Die Größe wird zu Beginn definiert (z. B. int arr[10];). Strings sind Char-Arrays, beendet mit '\0'. Strukturen (struct) fassen verschiedene Datentypen unter einem Namen zusammen, haben aber keine Methoden. Es gibt keine eingebauten dynamischen Container – dafür malloc/free (s. Speicherverwaltung). Arrays & Container: C++ bietet den Template-Typ std::array (feste Größe) und dynamische Container wie std::vector (Array mit variabler Länge) in <vector>, sowie std::string Klasse für Zeichenketten. Strukturen gibt es weiterhin, jedoch meist durch Klassen ersetzt. Zusätzlich hat C++ assoziative Container wie std::map (Schlüssel-Wert, ähnlich Python-Dict) und std::unordered_map in der STL. Diese bieten bereits viele Methoden (Insert, Find usw.). Listen & Dictionaries: Python hat eingebaute dynamische Listen (list), die wie flexible Arrays funktionieren (beliebige Länge, heterogene Elemente möglich). Beispiel: my_list = [1, "Hallo", 3.5]. Außerdem gibt es Dictionaries (dict) für Schlüssel-Wert-Paare (vergleichbar mit Maps/Hash-Tabellen). Strings (str) können wie Tupel behandelt werden, sind aber unveränderlich. Weitere eingebaute Strukturen: tuple (unveränderliche Listen), set (Mengen). All diese Datentypen sind Teil der Sprache und benötigen keine spezielle Bibliothek.
Speicherverwaltung Manuell: C verlangt vom Programmierer, Speicher selbst zu verwalten. Speicher wird mit malloc/calloc allokiert und muss mit free wieder freigegeben werden. Fehlende Freigabe führt zu Speicherleck, doppelte Freigabe zu undefiniertem Verhalten. Speicher von lokalen Variablen wird automatisch verwaltet. Es gibt keine automatische Garbage Collection. Manuell/automatisch: C++ unterstützt weiterhin C-Mechanismen (new/delete als Entsprechung zu malloc/free). Darüber hinaus erleichtert RAII (Resource Acquisition Is Initialization) die Verwaltung: Destruktoren von Objekten können automatisch Speicher freigeben (z. B. std::unique_ptr in <memory> räumt im Destruktor auf). C++ hat ebenfalls keine Garbage Collection, aber mit Smart Pointern und Containern (z. B. std::vector) sinkt die Gefahr von Speicherlecks. Automatisch (Garbage Collection): Python verwaltet den Speicher automatisch: Objekte werden freigegeben, wenn keine Referenz mehr darauf zeigt. Falls doch in seltenen Fällen nötig, lässt sich dieses Verhalten durch das Programm steuern.
Variablen & Referenzen Werte und Zeiger: Variablen der Grundtypen und struct enthalten direkt Werte (z. B. ein int enthält den Wert 5). Zusätzlich existieren Zeiger, die Speicheradressen halten und auf andere Variablen oder allokierten Speicher zeigen (z. B. int *p = &x;). C unterscheidet streng zwischen Wert und Adresse; Funktionen können per Wert oder per Zeiger Parameter bekommen; in letzterem Fall verändern sie die Originaldaten. Referenzen und Zeiger: Neben Zeigern (wie in C) gibt es in C++ Referenzen (Deklaration mit &, z. B. int &ref = x;), die als weiterer Name (Alias) für eine vorhandene Variable dienen. Funktionen können Referenzen als Parameter annehmen, um Objekte zu modifizieren, ohne ausdrücklich Zeiger zu nutzen, die NULL werden könnten. Grundtypen verhalten sich wie in C, aber Klassen-/Objekttypen können steuern, was bei einer Zuweisung passiert. Alles sind Objekte: In Python sind alle Variablen lediglich Referenzen auf Objekte. Eine Zuweisung a = b kopiert keine Werte, sondern lässt a auf dasselbe Objekt zeigen wie b. Es gibt kein Äquivalent zu C-Zeigern, aber Listen undDictionarys verhalten sich beim Zuweisen wie Referenzen (Änderungen in b = a; b.append(1) wirken auch in a). Primitive Typen wie Zahlen und Strings sind in Python unveränderlich: So ändert c = c + 1 nicht den Wert des Zahlenobjekts, auf das c referenziert, sondern schreibt eine Referenz auf ein anderes, um 1 höheres Zahlenobjekt in c. Die Übergabe an Funktionen erfolgt immer per Objektreferenz (ähnlich Call-by-reference der Werte, aber bei Mutables können Inhalte geändert werden, bei Immutables nicht).
Null-Zeiger/Null-Referenz In C steht NULL für einen Null-Zeiger, d. h. einen Zeiger, der auf nichts zeigt. Der Versuch, von dort zu lesen oder dorthin zu schreiben, führt zu einem Absturz (Segmentation Fault). In C++ existiert ebenfalls NULL, seit C++11 gibt es zusätzlich nullptr, einen typsicheren Nullzeiger, der explizit nur als Zeiger verwendet werden kann. In Python gibt es None als spezielles Objekt für „nichts“. Es ist kein Zeiger, sondern ein eigenes Objekt, das z. B. als Rückgabewert dient, wenn eine Funktion eigentlich nichts zurückliefert. Vergleiche erfolgen mit is None und is not None.
Enums (Aufzählungen) C kennt Aufzählungstypen per enum. Diese werden als Ganzzahlen umgesetzt. Beispiel: enum Farbe {ROT, GRUEN, BLAU}; Dabei ist ROT=0, GRUEN=1 etc., sofern man keine anderen Werte zuweist. Enums in C sind eher einfache Konstantenlisten ohne Typsicherheit (ein int kann jeden enum-Wert aufnehmen). C++ übernimmt enum von C, aber C++11 führte enum class ein. Ein enum class ist streng typisiert und die Werte konvertieren nicht implizit zu int, was Typfehler vermeidet. Beispiel: enum class Farbe {ROT, GRUEN, BLAU}; erfordert Farbe::ROT beim Zugriff und verhindert die Nutzung außerhalb dieses Typs ohne Cast. Python unterstützt seit Version 3.4 Aufzählungen über das Modul enum. Man definiert Enums mittels Klassen: z. B. from enum import Enum; class Farbe(Enum): ROT = 1; GRUEN = 2. Die Enum-Mitglieder (wie Farbe.ROT) sind Instanzen der Enum-Klasse und haben Eigenschaften wie name und value. Python-Enums sind Objekte und können verglichen oder in Schleifen verwendet werden, dienen aber hauptsächlich der besseren Lesbarkeit von konstanten Werten.
Strings & Zeichen Zeichenketten: In C gibt es keinen eigenen String-Datentyp. Strings sind Char-Arrays, die mit '\0' (Null-Byte) abgeschlossen werden. Man benutzt Funktionen aus <string.h> wie strcpy, strlen, strcmp für Operationen. Achtung: Pufferüberläufe müssen vom Programmierer verhindert werden. Einzelne Zeichen sind vom Typ char (häufig ASCII oder UTF-8 je nach System). std::string: C++ bietet die Klasse std::string in <string>. Sie kapselt char-Arrays und handhabt Größenerweiterungen intern. Strings können mit + aneinandergehängt werden (dank Operatorüberladung) und verfügen über Methoden wie .size() und .substr(). Ein Ausdruck wie std::string s = u8"Hallo 🌍"; erzeugt UTF-8. Die Klasse std::string hat gegenüber den char-Arrays von C den Vorteil, dass sie die Länge kennt und Funktionen als Methoden bereitstellt. str: In Python sind Strings Objekte vom Typ str. Sie sind unveränderlich. Zeichenkettenliterale können in einfachen '...' oder doppelten "..." Anführungszeichen stehen, Unicode (UTF-8) ist Standard. Strings können mit + aneinandergehängt werden. Häufiger aber nutzt man stattdessen formatierte Strings (f-Strings oder format()-Methode) Verkettung. Python bietet umfangreiche String-Methoden, z. B. .lower(), .split(), .find(). Einzelne Zeichen sind ebenfalls str, mit einer Länge von 1.
Funktionen & Parameter Funktionen müssen vor ihrem Aufruf definiert oder zumindest deklariert sein. Parameter werden standardmäßig per Wert übergeben (Kopie des Arguments). Soll eine Funktion eine Variable modifizieren, übergibt man einen Zeiger auf diese (Call-by-pointer). C unterstützt keine Standardparameterwerte: Jeder Funktionsaufruf muss für jeden Parameter ein Argument liefern. Überladene Funktionen (gleicher Name, aber unterschiedliche Parameteranzahl/-typen) gibt es in C nicht. C++ erlaubt Default-Parameterwerte bei Funktionen, die im Funktionsprototyp oder der Definition angegeben werden können. Beispiel: void print(int x, int base=10); – wird print(42) aufgerufen, nutzt die Funktion intern base=10. Außerdem unterstützt C++ Funktionsüberladung: Mehrere Funktionen mit gleichem Namen, aber unterschiedlicher Parameterzahl oder -typen, können definiert werden (der Compiler wählt anhand des Aufrufkontexts die passende). Übergabe ist normalerweise per Wert oder per Referenz (siehe oben). Mit Template-Funktionen können sogar typgenerische Funktionen erstellt werden. In Python können Funktionen Defaultwerte für Parameter definieren: def greet(name, msg="Hallo"): hat einen optionalen Parameter msg. Wird greet("Lisa") aufgerufen, nimmt msg automatisch den Default Hallo an. Alle Standardwerte werden genau einmal beim Definieren der Funktion berechnet und für alle Aufrufe verwendet. (Achtung bei veränderlichen Objekten als Default, denn der nächste Aufruf bekommt das veränderte Objekt!) Python unterstützt auch benannte Argumente: Beim Aufruf kann man greet(msg="Hi", name="Tom") schreiben – die Reihenfolge spielt dann keine Rolle. Überladene Funktionen im C++-Sinne gibt es nicht; stattdessen schreibt man Funktionen, die unterschiedlich auf Argumenttypen reagieren (Duck-Typing) oder man verwendet optionale/variadische Parameter (*args, **kwargs).
Programmstart & Module Das Programm startet in der Funktion main(). Man kann diese mit Parametern int main(int argc, char *argv[]) definieren, um Kommandozeilenargumente zu erhalten. C kennt kein Modulsystem – jede .c-Datei wird separat kompiliert und am Ende gelinkt. Gemeinsame Deklarationen stehen in Header-Dateien (.h), die per #include eingefügt werden. Globale Variablen/Funktionen: Funktionen und Variablen außerhalb von Funktionen sind in allen Programmdateien verfügbar, können aber mit static auf die jeweilige Datei beschränkt werden. Das Schlüsselwort extern wiederum deklariert, dass eine Definition in einer anderen Datei erfolgt. (Das Schlüsselwort static hat eine zweite Bedeutung: So lässt sich in einer Funktion eine lokale Variablen erzeugen, die ihren Wert zwischen Aufrufen behält.) Auch in C++ beginnt das Programm in main(). C++ unterstützt die Aufteilung in mehrere Dateien ähnlich wie C (Header und Implementationsdateien). Zusätzlich bietet C++ Namensräume (namespace), um Funktionen/Klassen in einen logischen Namensraum einzuschließen, so dass zum Beispiel zwei verschiedene Bibliotheken je eine Funktion init() haben können, ohne zu kollidieren (Aufruf dann z. B. LibA::init() vs. LibB::init()). Seit C++20 beherrscht C++ Module, so dass Code nicht mehr über Header und #include eingebunden werden muss. Es gibt in Python keine Startfunktion, aber die gängige Schreibweise lautet: if __name__ == "__main__": .... Dieser Block wird nur ausgeführt, wenn das Skript direkt gestartet wird, nicht aber beim Import als Modul. Damit fungiert er ähnlich wie ein main()-Block mit einer Testfunktion. Python verfügt über ein mächtiges Modul- und Paketsystem: Jede .py-Datei ist ein Modul, das man via import modulname einbinden kann. Auf Variablen, Funktionen und Klassen in einem Modul kann nach dem Muster modulname.bla zugegriffen werden. Es gibt keine direkten Entsprechungen zu extern oder static – Sichtbarkeit wird über Namensräume geregelt. Mit Unterstrich-Präfix vor dem Namen (z. B. _intern) zeigt man an, dass etwas verborgen sein soll; das ist aber nur ein freundlicher Hinweise, denn Python verbietet nicht den Zugriff darauf.
Fehlerbehandlung C bietet kein eigenes Exception-Handling. Fehler müssen z. B. über Rückgabewerte signalisiert werden (etwa liefert malloc bei Misserfolg NULL oder eine Funktion gibt -1 zurück und setzt errno). Diese Werte sind stets manuell zu prüfen. Schwere Fehler, die nicht abgefangen werden (z. B. Division durch 0 bei Integern oder Segfault bei ungültigem Zeiger), führen zu undefiniertem Verhalten oder Programmabsturz. C++ verfügt über Exceptions: mittels try { ... } catch(SomeException &e) { ... } können Fehler aufgefangen werden. Standardbibliothek-Funktionen (wie std::stoi oder Methoden wie std::vector::at) werfen bei Problemen Ausnahmen vom Typ std::exception oder abgeleiteten Klassen. Entwickler können eigene Exceptions definieren (meist durch Vererbung von std::exception). Allerdings ist der Einsatz von Exceptions in C++ teils umstritten; viele Performance-kritische Anwendungen meiden sie und nutzen stattdessen ebenfalls Fehlercodes oder std::optional/std::variant für erwartbare Fehler. Python setzt stark auf Exceptions. Bei Fehlern (z. B. Division durch 0, Zugriff auf nicht vorhandenen Listeneintrag, Import-Fehler etc.) wirft Python automatisch eine entsprechende Ausnahme (z. B. ZeroDivisionError, IndexError). Mit try-except Blöcken kann man diese abfangen: try: ... except ExceptionType as e: .... Es ist in Python üblich, Exceptions für den Programmfluss zu nutzen, z. B. eine Schleife oder eine Suche mittels Exception zu beenden, was in anderen Sprachen eher unüblich ist. Eigene Exceptions werden durch Subclassing von Exception erstellt. Unbehandelte Exceptions führen zum Abbruch des Programms mit einer Fehlermeldung.
Objektorientierung (OOP) C selbst unterstützt keine Klassen oder Objekte. Man kann zwar strukturiert programmieren und mittels Strukturen und Funktionszeigern einfache objektähnliche Konstrukte basteln, doch Konzepte wie Vererbung oder Polymorphie fehlen vollständig. Daher spricht man oft von C als rein prozeduraler Sprache. C++ ist voll objektorientiert: Es gibt Klassen (ähnlich wie struct, aber mit Standard-Zugriffsrechten private für Mitglieder). C++ unterstützt Vererbung (auch Mehrfachvererbung), Polymorphie sowie Abstraktion mittels virtuellen Funktionen und Kapselung (über Zugriffsmodifier public/private/protected). Anders als reine OOP-Sprachen erzwingt aber nicht, alles als Objekt zu sehen: Man kann weiterhin im C-Stil prozedural programmieren. Zusätzliche OOP-Features: Operatorüberladung (z. B. operator+ für eigene Klassen definieren), Templates (für Generizität statt nur Klassen-basiertem Polymorphismus), Destruktoren (für Aufräumlogik). Python ist ebenfalls objektorientiert, aber auf etwas andere Weise. Alles in Python ist ein Objekt, auch einfache Typen wie Zahlen oder Funktionen. Klassen definiert man mit class-Syntax; sie unterstützen Mehrfachvererbung, allerdings verwendet man meit nur kleine Klassen (Mixins) als zusätzliche Elternklassen. Polymorphie ergibt sich automatisch, denn jede Methode/Attribut-Aufruf hängt vom Objekttyp zur Laufzeit ab; es gibt keine Deklaration, dass eine Methode der Kindklasse eine Methode einer Mutterklasse überschreibt. Python kennt private Attribute nur eingschränkt: ein Prefix __ (Doppel-Unterstrich) löst Name-Mangling aus, was einen gewissen Schutz bietet, aber echte Zugriffsbeschränkungen existieren nicht. Anders als C++ hat Python keine Schnittstellen oder abstrakten Klassen im Sprachkern (man nutzt dafür ABCs aus abc-Modul). Operatorüberladung erfolgt durch spezielle Methoden (z. B. __add__ für +) in Klassen, wodurch man definieren kann, wie Objekte auf Operatoren reagieren. Eine Besonderheit: Python erlaubt dynamisches Hinzufügen von Attributen zu Objekten und Klassen während der Laufzeit.
Parallelität & Threading C selbst definiert in der Sprache keine Threads. Man greift auf Betriebssystem-APIs (z. B. POSIX-Threads unter Unix) oder Bibliotheken zurück. Seit C11 gibt es in <threads.h> grundlegende Thread-Funktionen. C++ erhielt mit C++11 einen plattformunabhängigen Thread-Support <thread> in der Standardbibliothek. Zum Beispiel startet std::thread t(func); einen neuen Thread, der func() ausführt. Synchronisations-Primitive wie std::mutex, std::lock_guard, std::condition_variable sind ebenfalls Teil davon. Python unterstützt Multithreading auf Sprachebene (Modul threading), aber die Ausführung ist in der Standard-Implementierung CPython durch den GIL (Global Interpreter Lock) beschränkt: Dort kann stets nur ein Thread zur gleichen Zeit Python-Bytecode ausführen. Daher bringen Threads in Python bei rechenintensiven Aufgaben keine Geschwindigkeitssteigerung, sondern entzerren das Warten z. B. auf mehrere gleichzeitige Netzwerk-Operationen. Für Parallelisierung nutzt man typischerweise Multiprocessing (statt mehrerer Threads mehrere komplette Prozesse). Allerdings bindet Python auf einfache Art C/C++-Module ein, die intern echte Parallelität nutzen können; rechenintensive Aufgaben etwa für KI werden oft an solche ausgelagert. Eine Neuerung: Die übliche Implementierung CPython erlaubt ab Python 3.13 experimentell, den GIL abzuschalten und echtes Multithreading zu betreiben; dies dürfte in Zukunft Standard werden.