Kurs
Python Data Classes: Ein umfassendes Tutorial
Datenklassen sind eine der Funktionen von Python, die du, wenn du sie einmal entdeckt hast, nie wieder verwenden wirst. Betrachte diese reguläre Klasse:
class Exercise:
def __init__(self, name, reps, sets, weight):
self.name = name
self.reps = reps
self.sets = sets
self.weight = weight
Meiner Meinung nach ist diese Klassendefinition sehr ineffizient - in der Methode __init__
wiederholst du jeden Parameter mindestens dreimal. Das klingt vielleicht nicht nach einer großen Sache, aber überlege mal, wie oft du in deinem Leben Klassen mit viel mehr Parametern schreibst.
Zum Vergleich: Schau dir die Datenklassen-Alternative des obigen Codes an:
from dataclasses import dataclass
@dataclass
class Exercise:
name: str
reps: int
sets: int
weight: float # Weight in lbs
Dieses bescheiden aussehende Stück Code ist um Größenordnungen besser als eine normale Klasse. Der winzige Dekorator @dataclass
implementiert die Klassen __init__
, __repr__
, __eq__
hinter den Kulissen, was manuell mindestens 20 Zeilen Code erfordert hätte.
Außerdem sind viele andere Funktionen wie Vergleichsoperatoren, Objektordnung und Unveränderlichkeit nur eine einzige Zeile davon entfernt, für unsere Klasse erstellt zu werden.
In diesem Tutorial wollen wir dir zeigen, warum Datenklassen das Beste sind, was Python passieren konnte, wenn du objektorientierte Programmierung liebst.
Lass uns loslegen!
Grundlagen der Python-Datenklassen
Im Folgenden werden einige der grundlegenden Konzepte von Python-Datenklassen erläutert, die Python so nützlich machen.
Einige Methoden werden automatisch in Datenklassen generiert
Trotz all ihrer Funktionen sind Datenklassen ganz normale Klassen, die viel weniger Code benötigen, um die gleiche Funktionalität zu implementieren. Hier ist wieder die Exercise
Klasse:
from dataclasses import dataclass
@dataclass
class Exercise:
name: str
reps: int
sets: int
weight: float
ex1 = Exercise("Bench press", 10, 3, 52.5)
# Verifying Exercise is a regular class
ex1.name
'Bench press'
Im Moment hat Exercise
bereits die Methoden __repr__
und __eq__
implementiert. Lass es uns überprüfen:
repr(ex1)
"Exercise(name='Bench press', reps=10, sets=3, weight=52.5)"
Die Objektrepräsentation eines Objekts repr
muss den Code zurückgeben, der sich selbst wiederherstellen kann, und wir können sehen, dass genau das bei ex1
der Fall ist.
Im Vergleich dazu würde Exercise
auf die alte Art und Weise wie folgt aussehen:
class Exercise:
def __init__(self, name, reps, sets, weight):
self.name = name
self.reps = reps
self.sets = sets
self.weight = weight
ex3 = Exercise("Bench press", 10, 3, 52.5)
ex3
<__main__.Exercise at 0x7f6834100130>
Sieht ziemlich furchtbar und nutzlos aus!
Überprüfen wir nun die Existenz von __eq__
, dem Gleichheitsoperator:
# Redefine the class
@dataclass
class Exercise:
name: str
reps: int
sets: int
weight: float
ex1 = Exercise("Bench press", 10, 3, 52.5)
ex2 = Exercise("Bench press", 10, 3, 52.5)
Der Vergleich der Klasse mit sich selbst und mit einer anderen Klasse mit identischen Parametern muss True ergeben:
ex1 == ex2
True
ex1 == ex1
True
Und das tut sie auch! Im normalen Unterricht wäre diese Logik mühsam zu schreiben gewesen.
Datenklassen erfordern Typ-Hinweise
Wie du vielleicht schon bemerkt hast, benötigen Datenklassen bei der Definition von Feldern Typ-Hinweise. In der Tat erlauben Datenklassen jeden Typ aus dem typing
Modul. So kannst du zum Beispiel ein Feld erstellen, das den Datentyp Any
akzeptiert:
from typing import Any
@dataclass
class Dummy:
attr: Any
Die Besonderheit von Python ist jedoch, dass die Typen nicht erzwungen werden, obwohl die Datenklassen Hinweise auf den Typ benötigen.
Zum Beispiel kann die Erstellung einer Instanz der Klasse Exercise
mit völlig falschen Datentypen ohne Fehler ausgeführt werden:
silly_exercise = Exercise("Bench press", "ten", "three sets", 52.5)
silly_exercise.sets
“Three sets”
Wenn du Datentypen erzwingen willst, musst du Typprüfungen wie Mypy verwenden.
Datenklassen erlauben Standardwerte in Feldern
Bis jetzt haben wir unseren Klassen noch keine Vorgaben hinzugefügt. Das müssen wir ändern:
@dataclass
class Exercise:
name: str = "Push-ups"
reps: int = 10
sets: int = 3
weight: float = 0
# Now, all fields have defaults
ex5 = Exercise()
ex5
Exercise(name='Push-ups', reps=10, sets=3, weight=0)
Denke daran, dass Nicht-Standardfelder nicht auf Standardfelder folgen können. Der folgende Code zum Beispiel wird einen Fehler auslösen:
@dataclass
class Exercise:
name: str = "Push-ups"
reps: int = 10
sets: int = 3
weight: float # NOT ALLOWED
ex5 = Exercise()
ex5
TypeError: non-default argument 'weight' follows default argument
In der Praxis wirst du nur selten Standardwerte mit der name: type = value
Syntax definieren.
Stattdessen verwendest du die Funktion field
, die mehr Kontrolle über die einzelnen Felddefinitionen ermöglicht:
from dataclasses import field
@dataclass
class Exercise:
name: str = field(default="Push-up")
reps: int = field(default=10)
sets: int = field(default=3)
weight: float = field(default=0)
# Now, all fields have defaults
ex5 = Exercise()
ex5
Exercise(name='Push-up', reps=10, sets=3, weight=0)
Die Funktion field
hat mehr Parameter, wie zum Beispiel:
repr
init
compare
default_factory
und so weiter. Wir werden diese in den nächsten Abschnitten besprechen.
Datenklassen können mit einer Funktion erstellt werden
Ein letzter Hinweis zu den Grundlagen der Datenklassen ist, dass ihre Definition noch kürzer sein kann, wenn du die Funktion make_dataclass
verwendest:
from dataclasses import make_dataclass
Exercise = make_dataclass(
"Exercise",
[
("name", str),
("reps", int),
("sets", int),
("weight", float),
],
)
ex3 = Exercise("Deadlifts", 8, 3, 69.0)
ex3
Exercise(name='Deadlifts', reps=8, sets=3, weight=69.0)
Aber du verlierst dabei die Lesbarkeit, deshalb empfehle ich diese Funktion nicht.
Fortgeschrittene Python-Datenklassen
In diesem Abschnitt werden wir erweiterte Funktionen von Datenklassen besprechen, die mehr Vorteile bringen. Eine solche Funktion ist die Standardfabrik.
Standard-Fabriken
Um die Standardfabriken zu erklären, erstellen wir eine weitere Klasse namens WorkoutSession
, die zwei Felder akzeptiert:
from dataclasses import dataclass
from typing import List
@dataclass
class Exercise:
name: str = "Push-ups"
reps: int = 10
sets: int = 3
weight: float = 0
@dataclass
class WorkoutSession:
exercises: List[Exercise]
duration_minutes: int
Indem wir den Typ List
verwenden, geben wir an, dass WorkoutSession
eine Liste von Exercise
Instanzen annimmt.
# Define the Exercise instances for HIIT training
ex1 = Exercise(name="Burpees", reps=15, sets=3)
ex2 = Exercise(name="Mountain Climbers", reps=20, sets=3)
ex3 = Exercise(name="Jump Squats", reps=12, sets=3)
exercises_monday = [ex1, ex2, ex3]
hiit_monday = WorkoutSession(exercises=exercises_monday, duration_minutes=30)
Momentan müssen für jede Trainingseinheit Übungen initialisiert werden. Aber das spiegelt nicht wider, wie die Menschen trainieren - zuerst beginnen sie eine Sitzung (wahrscheinlich in einer App) und fügen dann während des Trainings Übungen hinzu.
Wir müssen also in der Lage sein, Sitzungen ohne Übungen und ohne Dauer zu erstellen. Um dies zu erreichen, fügen wir eine leere Liste als Standardwert für exercises
hinzu:
@dataclass
class WorkoutSession:
exercises: List[Exercise] = []
duration_minutes: int = None
hiit_monday = WorkoutSession("25-02-2024")
ValueError: mutable default <class 'list'> for field exercises is not allowed: use default_factory
Wir erhielten jedoch einen Fehler - es stellte sich heraus, dass Datenklassen keine veränderbaren Standardwerte zulassen.
Zum Glück können wir das beheben, indem wir eine Standardfabrik verwenden:
@dataclass
class WorkoutSession:
exercises: List[Exercise] = field(default_factory=list) # PAY ATTENTION
duration_minutes: int = 0
hiit_monday = WorkoutSession()
hiit_monday
WorkoutSession(exercises=[], duration_minutes=0)
Der Parameter default_factory
akzeptiert eine Funktion, die einen Anfangswert für ein Datenklassenfeld zurückgibt. Das bedeutet, dass sie jede beliebige Funktion annehmen kann:
tuple
dict
set
- Jede benutzerdefinierte benutzerdefinierte Funktion
Dies gilt unabhängig davon, ob das Ergebnis der Funktion veränderbar ist oder nicht.
Wenn wir darüber nachdenken, beginnen die meisten Menschen ihr Training mit Aufwärmübungen, die für jede Art von Training typisch sind. Es kann also sein, dass der Beginn einer Sitzung ohne Übungen nicht das ist, was manche Leute wollen.
Stattdessen wollen wir eine Funktion erstellen, die drei Aufwärmprogramme zurückgibt Exercises
:
def create_warmup():
return [
Exercise("Jumping jacks", 30, 1),
Exercise("Squat lunges", 10, 2),
Exercise("High jumps", 20, 1),
]
@dataclass
class WorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5 # Increase the default duration as well
hiit_monday = WorkoutSession()
hiit_monday
WorkoutSession(exercises=[Exercise(name='Jumping jacks', reps=30, sets=1, weight=0), Exercise(name='Squat lunges', reps=10, sets=2, weight=0), Exercise(name='High jumps', reps=20, sets=1, weight=0)], duration_minutes=5)
Wenn wir jetzt eine Unterrichtseinheit erstellen, werden bereits einige Aufwärmübungen aufgezeichnet. Die neue Version von WorkoutSession
hat eine Standarddauer von fünf Minuten, um dies zu berücksichtigen.
Hinzufügen von Methoden zu Datenklassen
Da Datenklassen reguläre Klassen sind, bleibt das Hinzufügen von Methoden zu ihnen dasselbe. Fügen wir zwei Methoden zu unserer WorkoutSession
Datenklasse hinzu:
@dataclass
class WorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
def add_exercise(self, exercise: Exercise):
self.exercises.append(exercise)
def increase_duration(self, minutes: int):
self.duration_minutes += minutes
Mit diesen Methoden können wir jetzt jede neue Aktivität in einer Sitzung protokollieren:
hiit_monday = WorkoutSession()
# Log a new exercise
new_exercise = Exercise("Deadlifts", 6, 4, 60)
hiit_monday.add_exercise(new_exercise)
hiit_monday.increase_duration(15)
Aber es gibt ein Problem:
hiit_monday
WorkoutSession(exercises=[Exercise(name='Jumping jacks', reps=30, sets=1, weight=0), Exercise(name='Squat lunges', reps=10, sets=2, weight=0), Exercise(name='High jumps', reps=20, sets=1, weight=0), Exercise(name='Deadlifts', reps=6, sets=4, weight=60)], duration_minutes=20)
Wenn wir die Sitzung ausdrucken, ist ihre Standarddarstellung zu ausführlich und unleserlich, da sie den Code zur Neuerstellung des Objekts enthält. Das müssen wir ändern.
__repr__
und __str__
in Datenklassen
Datenklassen implementieren __repr__
automatisch, aber nicht __str__
. So kann die Klasse auf __repr__
zurückgreifen, wenn wir sie zum Drucken aufrufen.
Also setzen wir dieses Verhalten außer Kraft, indem wir __str__
selbst definieren:
@dataclass
class Exercise:
name: str = "Push-ups"
reps: int = 10
sets: int = 3
weight: float = 0
def __str__(self):
base = f"{self.name}: {self.reps}/{self.sets}"
if self.weight == 0:
return base
return base + f", {self.weight} lbs"
ex1 = Exercise(name="Burpees", reps=15, sets=3)
ex1
Exercise(name='Burpees', reps=15, sets=3, weight=0)
Die __repr__
ist immer noch die gleiche, aber wenn wir print
aufrufen:
print(ex1)
Burpees: 15/3
Die Frühlingsdarstellung der Klasse ist viel schöner. Und jetzt lass uns auch WorkoutSession
reparieren:
@dataclass
class WorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5 # Increase the default duration as well
def add_exercise(self, exercise: Exercise):
self.exercises.append(exercise)
def increase_duration(self, minutes: int):
self.duration_minutes += minutes
def __str__(self):
base = ""
for ex in self.exercises:
base += str(ex) + "\n"
base += f"\nSession duration: {self.duration_minutes} minutes."
return base
hiit_monday = WorkoutSession()
print(hiit_monday)
Jumping jacks: 30/1
Squat lunges: 10/2
High jumps: 20/1
Session duration: 5 minutes.
Hinweis: Verwende die Schaltfläche "Code erklären" am Ende des Snippets, um eine zeilenweise Erklärung des Codes zu erhalten.
Jetzt haben wir eine lesbare und kompakte Ausgabe.
Vergleich in Datenklassen
Bei vielen Klassen ist es sinnvoll, ihre Objekte nach einer bestimmten Logik zu vergleichen. Beim Training kann es die Trainingsdauer, die Trainingsintensität oder das Gewicht sein.
Schauen wir uns zunächst an, was passiert, wenn wir versuchen, zwei Workouts im aktuellen Zustand zu vergleichen:
hiit_wednesday = WorkoutSession()
hiit_wednesday.add_exercise(Exercise("Pull-ups", 7, 3))
print(hiit_wednesday)
Jumping jacks: 30/1
Squat lunges: 10/2
High jumps: 20/1
Pull-ups: 7/3
Session duration: 5 minutes.
hiit_monday > hiit_wednesday
TypeError: '>' not supported between instances of 'WorkoutSession' and 'WorkoutSession'
Wir erhalten eine TypeError
, da Datenklassen keine Vergleichsoperatoren implementieren. Das lässt sich aber leicht beheben, indem du den Parameter order
auf True
setzt:
@dataclass(order=True)
class WorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
...
hiit_monday = WorkoutSession()
# hiit_monday.add_exercise(...)
hiit_monday.increase_duration(10)
hiit_wednesday = WorkoutSession()
hiit_monday > hiit_wednesday
True
Dieses Mal funktioniert der Vergleich, aber was vergleichen wir überhaupt?
In Datenklassen wird der Vergleich in der Reihenfolge durchgeführt, in der die Felder definiert sind. Im Moment werden die Klassen anhand der Trainingsdauer verglichen, da das erste Feld, exercises
, nicht standardisierte Objekte enthält.
Wir können das überprüfen, indem wir die Dauer der Mittwochssitzung verlängern:
hiit_monday = WorkoutSession()
# hiit_monday.add_exercise(...)
hiit_wednesday = WorkoutSession()
hiit_wednesday.increase_duration(10)
hiit_monday > hiit_wednesday
False
Wie erwartet, haben wir False
erhalten.
Was würde aber passieren, wenn das erste Feld von Workout
eine andere Art von Feld wäre, zum Beispiel ein String? Lass es uns herausfinden:
@dataclass(order=True)
class WorkoutSession:
date: str = None # DD-MM-YYYY
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
...
hiit_monday = WorkoutSession("25-02-2024")
hiit_monday.increase_duration(10)
hiit_wednesday = WorkoutSession("27-02-2024")
hiit_monday > hiit_wednesday
False
Auch wenn die Montagssitzung länger dauert, zeigt der Vergleich, dass sie kleiner ist als die Mittwochssitzung. Der Grund dafür ist, dass "25" beim Python-Stringvergleich vor "27" kommt.
Wie können wir also die Reihenfolge der Felder beibehalten und die Sitzungen trotzdem nach der Trainingsdauer sortieren? Das geht ganz einfach über die Funktion field
:
@dataclass(order=True)
class WorkoutSession:
date: str = field(default=None, compare=False)
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
...
hiit_monday = WorkoutSession("25-02-2024")
hiit_monday.increase_duration(10)
hiit_wednesday = WorkoutSession("27-02-2024")
hiit_monday > hiit_wednesday
True
Indem wir compare
für ein beliebiges Feld auf False
setzen, schließen wir es von der Sortierung aus, wie das obige Ergebnis zeigt.
Manipulation des Post-Init-Feldes
Im Moment haben wir eine Standarddauer von fünf Minuten, um Aufwärmübungen zu berücksichtigen. Das macht aber nur Sinn, wenn ein Nutzer eine Sitzung mit einem Warm-up beginnt. Was ist, wenn sie eine Sitzung mit anderen Übungen beginnen?
new_session = WorkoutSession([Exercise("Diamond push-ups", 10, 3)])
new_session.duration_minutes
5
Für nur eine einzige Übung beträgt die Gesamtdauer fünf Minuten, was unlogisch ist. Jede Einheit muss ihre Dauer dynamisch anhand der Anzahl der Sätze jeder Übung schätzen. Das bedeutet, dass wir duration_minutes
von dem Feld exercises
abhängig machen sollten.
Lass es uns umsetzen:
@dataclass
class WorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = field(default=0, init=False)
def __post_init__(self):
set_duration = 3
for ex in self.exercises:
self.duration_minutes += ex.sets * set_duration
...
Dieses Mal definieren wir duration_minutes
, wobei init
auf False
gesetzt ist, um die Initialisierung des Feldes zu verzögern.
Dann aktualisieren wir in einer speziellen Methode __post_init__
den Wert auf der Grundlage der Gesamtzahl der Sätze in jedem Exercise
.
Wenn wir nun WorkoutSession
initialisieren, wird duration_minutes
dynamisch um drei Minuten für jeden Satz in jeder Übung erhöht.
# Adding an exercise with three sets
hiit_friday = WorkoutSession([Exercise("Diamond push-ups", 10, 3)])
hiit_friday.duration_minutes
9
Wenn du ein Feld definieren willst, das von anderen Feldern deiner Datenklasse abhängt, kannst du die __post_init__
Logik verwenden.
Unveränderlichkeit in Datenklassen
Unsere WorkoutSession
Datenklasse ist fast fertig; sie muss nur noch geschützt werden. Im Moment kann es ziemlich leicht durcheinander gebracht werden:
hiit_friday.duration_minutes = 1000
hiit_friday.duration_minutes
1000
del hiit_friday.exercises
Wir wollen alle Felder unserer Klassen schützen, damit sie nur in der von uns gewünschten Weise geändert werden können. Um dies zu erreichen, bietet der @dataclass
Dekorator ein praktisches frozen
Argument:
@dataclass(frozen=True)
class FrozenExercise:
name: str
reps: int
sets: int
weight: int | float = 0
ex1 = FrozenExercise("Muscle-ups", 5, 3)
Wenn wir jetzt ein Feld ändern wollen, erhalten wir eine Fehlermeldung:
ex1.sets = 5
FrozenInstanceError: cannot assign to field 'sets'
Wenn du frozen
auf True
setzt, werden automatisch die Methoden __deleteattr__
und __setattr__
für jedes Feld hinzugefügt, damit sie nach der Initialisierung vor dem Löschen oder Aktualisieren geschützt sind. Außerdem können andere keine neuen Felder mehr hinzufügen:
ex1.new_field = 10
FrozenInstanceError: cannot assign to field 'new_field'
Diese Funktionalität würde Dutzende von Codezeilen umfassen, wenn wir es mit traditionellen Klassen zu tun hätten.
Beachte aber bitte, dass wir unsere Klassen nicht wirklich unveränderlich machen können. Schreiben wir zum Beispiel die WorkoutSession
um, indem wir frozen
auf True
setzen:
@dataclass(frozen=True)
class ImmutableWorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
session1 = ImmutableWorkoutSession()
Wie erwartet, können wir die Liste der Übungen nicht direkt ändern:
session1.exercises = [Exercise()]
exercises
ist jedoch eine Liste, die vollständig veränderbar ist, sodass die folgende Operation möglich ist:
# Ändern eines der Elemente in einer Liste
# Changing one of the elements in a list
session1.exercises[1] = FrozenExercise("Totally new exercise", 5, 5)
print(session1)
ImmutableWorkoutSession(exercises=[Exercise(name='Jumping jacks', reps=30, sets=1, weight=0), FrozenExercise(name='Totally new exercise', reps=5, sets=5, weight=0), Exercise(name='High jumps', reps=20, sets=1, weight=0)], duration_minutes=5)
Zum Schutz vor versehentlichen Änderungen wird daher empfohlen, unveränderliche Objekte wie Tupel für Feldwerte zu verwenden.
Vererbung in Datenklassen
Ein letzter Punkt, den wir behandeln werden, ist die Reihenfolge der Felder in Eltern- und Kindklassen.
Da Datenklassen reguläre Klassen sind, funktioniert die Vererbung wie üblich:
@dataclass(frozen=True)
class ImmutableWorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
@dataclass(frozen=True)
class CardioWorkoutSession(ImmutableWorkoutSession):
pass
Da aber das letzte Feld in der übergeordneten Klasse (ImmutableWorkoutSession
) einen Standardwert hat, müssen alle Felder in den untergeordneten Klassen Standardwerte haben.
Dies ist zum Beispiel nicht erlaubt:
@dataclass(frozen=True)
class ImmutableWorkoutSession:
exercises: List[Exercise] = field(default_factory=create_warmup)
duration_minutes: int = 5
@dataclass(frozen=True)
class CardioWorkoutSession(ImmutableWorkoutSession):
intensity_level: str # Not allowed, must have a default
TypeError: non-default argument 'intensity_level' follows default argument
Nachteile von Datenklassen und weitere Ressourcen
Die Datenklassen wurden seit Python 3.7 stetig verbessert (sie waren von Anfang an großartig) und decken viele Anwendungsfälle ab, in denen du vielleicht Klassen schreiben musst. In den folgenden Szenarien können sie jedoch nachteilig sein:
- Benutzerdefinierte
__init__
Methoden - Benutzerdefinierte
__new__
Methoden - Verschiedene Vererbungsmuster
Und viele mehr, wie in diesem tollen Reddit-Thread diskutiert. Wenn du eine detailliertere Begründung dafür suchst, warum Datenklassen eingeführt wurden und warum sie kein einfacher Ersatz für normale Klassendefinitionen sind, lies PEP 557.
Wenn du dich für objektorientierte Programmierung im Allgemeinen interessierst, ist dies ein Kurs, mit dem du deine Reise fortsetzen kannst:
Im Grunde genommen sind Datenklassen ausgefeiltere Strukturen, um Daten effizienter zu speichern und abzurufen. Python verfügt jedoch über viele andere Datenstrukturen, die diese Aufgabe mehr oder weniger auf ähnliche Weise erfüllen. Im letzten Kapitel des Kurses "Datentypen für die Datenwissenschaft" erfährst du zum Beispiel mehr über Zähler, defaultdicts
und namedtuples
.

Ich bin ein Data Science Content Creator mit über 2 Jahren Erfahrung und einem der größten Follower auf Medium. Ich schreibe gerne ausführliche Artikel über KI und ML mit einem etwas sarkastischen Stil, denn man muss etwas tun, damit sie nicht so langweilig sind. Ich habe mehr als 130 Artikel verfasst und einen DataCamp-Kurs gemacht, ein weiterer ist in Vorbereitung. Meine Inhalte wurden von über 5 Millionen Augenpaaren gesehen, von denen 20.000 zu Followern auf Medium und LinkedIn wurden.
Weiter Python lernen
Lernpfad
Python Data Fundamentals
Kurs
Introduction to Functions in Python

Der Blog
Lehrer/innen und Schüler/innen erhalten das Premium DataCamp kostenlos für ihre gesamte akademische Laufbahn
Der Blog
2022-2023 DataCamp Classrooms Jahresbericht
Der Blog
Die 20 besten Snowflake-Interview-Fragen für alle Niveaus

Nisha Arya Ahmed
20 Min.
Der Blog
Q2 2023 DataCamp Donates Digest
Der Blog
Die 32 besten AWS-Interview-Fragen und Antworten für 2024
Der Blog
Top 30 Generative KI Interview Fragen und Antworten für 2024

Hesam Sheikh Hassani
15 Min.