Accéder au contenu principal

Classes de données Python : Un tutoriel complet

Un tutoriel adapté aux débutants sur les classes de données Python et leur utilisation en pratique.
Actualisé 16 janv. 2025  · 9 min de lecture

Les classes de données sont l'une des caractéristiques de Python qui, une fois que vous les avez découvertes, ne vous permet plus de revenir à l'ancienne méthode. Considérez cette classe régulière :

class Exercise:
   def __init__(self, name, reps, sets, weight):
       self.name = name
       self.reps = reps
       self.sets = sets
       self.weight = weight

Pour moi, cette définition de classe est très inefficace - dans la méthode __init__, vous répétez chaque paramètre au moins trois fois. Cela peut sembler anodin, mais pensez au nombre de fois où vous écrivez des classes avec beaucoup plus de paramètres.

En comparaison, jetez un coup d'œil à l'alternative des classes de données du code ci-dessus :

from dataclasses import dataclass


@dataclass
class Exercise:
   name: str
   reps: int
   sets: int
   weight: float  # Weight in lbs

Ce morceau de code d'apparence modeste est bien meilleur qu'une classe ordinaire. Le minuscule décorateur @dataclass implémente les classes __init__, __repr__, __eq__ dans les coulisses, ce qui aurait nécessité au moins 20 lignes de code manuellement.

En outre, de nombreuses autres fonctionnalités, telles que les opérateurs de comparaison, l'ordonnancement des objets et l'immutabilité, sont toutes à une ligne près d'être créées comme par magie pour notre classe.

Le but de ce tutoriel est donc de vous montrer pourquoi les classes de données sont l'une des meilleures choses qui soient arrivées à Python si vous aimez la programmation orientée objet.

Commençons !

Les bases des classes de données Python

Abordons quelques-uns des concepts fondamentaux des classes de données Python qui les rendent si utiles.

Certaines méthodes sont automatiquement générées dans les classes de données

Malgré toutes leurs caractéristiques, les classes de données sont des classes normales qui nécessitent beaucoup moins de code pour mettre en œuvre la même fonctionnalité. Voici à nouveau la classe Exercise:

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'

À l'heure actuelle, Exercise dispose déjà des méthodes __repr__ et __eq__. Vérifions-le :

repr(ex1)
"Exercise(name='Bench press', reps=10, sets=3, weight=52.5)"

La représentation d'un objet repr doit renvoyer le code qui peut se recréer lui-même, et nous pouvons voir que c'est exactement le cas pour ex1.

En comparaison, Exercise défini selon l'ancienne méthode ressemblerait à ceci :

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>

Il a l'air assez horrible et inutile !

Vérifions maintenant l'existence de __eq__, qui est l'opérateur d'égalité :

# 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)

La comparaison de la classe à elle-même et à une autre classe avec des paramètres identiques doit renvoyer True :

ex1 == ex2
True
ex1 == ex1
True

Et c'est le cas ! Dans les classes ordinaires, cette logique aurait été pénible à écrire.

Les classes de données nécessitent des indications de type

Comme vous l'avez peut-être remarqué, les classes de données nécessitent des indications de type lors de la définition des champs. En fait, les classes de données autorisent n'importe quel type du module typing. Par exemple, voici comment créer un champ qui peut accepter le type de données Any:

from typing import Any


@dataclass
class Dummy:
   attr: Any

Cependant, l'idiosyncrasie de Python est que même si les classes de données nécessitent des indications de type, les types ne sont pas réellement imposés.

Par exemple, la création d'une instance de la classe Exercise avec des types de données totalement incorrects peut être exécutée sans erreur :

silly_exercise = Exercise("Bench press", "ten", "three sets", 52.5)

silly_exercise.sets

“Three sets”

Si vous souhaitez renforcer les types de données, vous devez utiliser des vérificateurs de types tels que Mypy.

Les classes de données autorisent les valeurs par défaut dans les champs

Jusqu'à présent, nous n'avons pas ajouté de valeurs par défaut à nos classes. Corrigeons cela :

@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)

N'oubliez pas que les champs qui ne sont pas des champs par défaut ne peuvent pas suivre les champs par défaut. Par exemple, le code ci-dessous provoquera une erreur :

@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

Dans la pratique, vous définirez rarement des valeurs par défaut à l'aide de la syntaxe name: type = value.

Vous utiliserez plutôt la fonction field, qui permet de mieux contrôler chaque définition de champ :

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)

La fonction field a plus de paramètres, tels que

  • repr
  • init
  • compare
  • default_factory

et ainsi de suite. Nous les examinerons dans les sections suivantes.

Les classes de données peuvent être créées à l'aide d'une fonction

Une dernière remarque sur les bases des classes de données est que leur définition peut être encore plus courte en utilisant la fonction make_dataclass:

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)

Mais vous sacrifierez la lisibilité, c'est pourquoi je ne recommande pas l'utilisation de cette fonction.

Classes de données avancées en Python

Dans cette section, nous aborderons les fonctionnalités avancées des classes de données qui apportent davantage d'avantages. L'une de ces caractéristiques est une usine par défaut.

Usines par défaut

Pour expliquer les usines par défaut, créons une autre classe nommée WorkoutSession qui accepte deux champs :

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

En utilisant le type List, nous spécifions que WorkoutSession accepte une liste d'instances Exercise.

# 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)

Actuellement, chaque instance de séance d'entraînement nécessite l'initialisation des exercices. Mais cela ne reflète pas la façon dont les gens s'entraînent - ils commencent d'abord une session (probablement dans une application), puis ils ajoutent des exercices au fur et à mesure qu'ils s'entraînent.

Il faut donc pouvoir créer des sessions sans exercices et sans durée. Pour ce faire, ajoutons une liste vide comme valeur par défaut pour exercises:

@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

Cependant, nous avons obtenu une erreur - il s'avère que les classes de données n'autorisent pas les valeurs par défaut mutables.

Heureusement, il est possible de remédier à ce problème en utilisant une usine par défaut :

@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)

Le paramètre default_factory accepte une fonction qui renvoie une valeur initiale pour un champ de la classe de données. Cela signifie qu'il peut accepter n'importe quelle fonction arbitraire :

  • tuple
  • dict
  • set
  • Toute fonction personnalisée définie par l'utilisateur

Ceci est exact, que le résultat de la fonction soit mutable ou non.

Si l'on y réfléchit bien, la plupart des gens commencent leur entraînement par des exercices d'échauffement qui sont généralement similaires pour tout type de séance d'entraînement. Par conséquent, l'initialisation des sessions sans exercices peut ne pas correspondre à ce que certaines personnes souhaitent.

Au lieu de cela, créons une fonction qui renvoie trois sites d'échauffement 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)

Désormais, chaque fois que nous créons une session, les participants sont accompagnés d'exercices d'échauffement déjà enregistrés. La nouvelle version de WorkoutSession a une durée par défaut de cinq minutes pour en tenir compte.

Ajouter des méthodes aux classes de données

Les classes de données étant des classes normales, l'ajout de méthodes reste le même. Ajoutons deux méthodes à notre classe de données WorkoutSession:

@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

Grâce à ces méthodes, nous pouvons désormais enregistrer toute nouvelle activité dans une session :

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)

Mais il y a un problème :

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)

Lorsque nous imprimons la session, sa représentation par défaut est trop verbeuse et illisible puisqu'elle contient le code pour recréer l'objet. Corrigeons cela.

__repr__ et __str__ dans les classes de données

Les classes de données implémentent automatiquement __repr__ mais pas __str__. Cela permet à la classe de se rabattre sur __repr__ lorsque nous faisons appel à print.

Remplaçons donc ce comportement en définissant nous-mêmes __str__:

@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)

Le site __repr__ est toujours le même, mais lorsque nous appelons print sur ce site :

print(ex1)
Burpees: 15/3

La représentation printanière de la classe est beaucoup plus agréable. Maintenant, corrigeons également WorkoutSession:

@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.

Note: Utilisez le bouton "Expliquer le code" au bas de l'extrait pour obtenir une explication ligne par ligne du code.

Nous avons maintenant un résultat lisible et compact.

Comparaison des classes de données

Pour de nombreuses classes, il est judicieux de comparer leurs objets selon une certaine logique. Pour les séances d'entraînement, il peut s'agir de la durée de la séance, de l'intensité de l'exercice ou du poids.

Tout d'abord, voyons ce qui se passe si nous essayons de comparer deux séances d'entraînement dans l'état actuel :

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'

Nous recevons TypeError car les classes de données n'implémentent pas d'opérateurs de comparaison. Mais cela peut être facilement corrigé en réglant le paramètre order sur True:

@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

Cette fois-ci, la comparaison fonctionne, mais qu'est-ce qu'on compare ?

Dans les classes de données, la comparaison est effectuée dans l'ordre dans lequel les champs sont définis. Actuellement, les classes sont comparées sur la base de la durée de l'entraînement car le premier champ, exercises, contient des objets non standard.

Nous pouvons le vérifier en augmentant la durée de la session de mercredi :

hiit_monday = WorkoutSession()
# hiit_monday.add_exercise(...)

hiit_wednesday = WorkoutSession()
hiit_wednesday.increase_duration(10)

hiit_monday > hiit_wednesday
False

Comme prévu, nous avons reçu False.

Mais que se passerait-il si le premier champ de Workout était un autre type de champ, par exemple une chaîne de caractères ? Essayons de le savoir :

@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

Même si la session du lundi dure plus longtemps, la comparaison montre qu'elle est plus petite que celle du mercredi. La raison en est que "25" vient avant "27" dans la comparaison de chaînes de Python.

Comment conserver l'ordre des champs tout en triant les sessions en fonction de la durée de la séance d'entraînement ? Cette opération est facile à réaliser grâce à la fonction 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

En définissant compare sur False pour un champ quelconque, nous l'excluons du tri, comme le montre le résultat ci-dessus.

Manipulation du champ post-init

À l'heure actuelle, la durée de la session est fixée par défaut à cinq minutes pour tenir compte des exercices d'échauffement. Toutefois, cela n'a de sens que si l'utilisateur commence une session par un échauffement. Que se passe-t-il s'ils commencent une session avec d'autres exercices ?

new_session = WorkoutSession([Exercise("Diamond push-ups", 10, 3)])

new_session.duration_minutes
5

Pour un seul exercice, la durée totale est de cinq minutes, ce qui est illogique. Chaque session doit déterminer dynamiquement sa durée en fonction du nombre de séries de chaque exercice. Cela signifie que nous devons rendre duration_minutes dépendant du champ exercises.

Mettons-le en œuvre :

@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

   ...

Cette fois, nous définissons duration_minutes avec init fixé à False pour retarder l'initialisation du champ.

Ensuite, à l'intérieur d'une méthode spéciale __post_init__, nous mettons à jour sa valeur en fonction du nombre total d'ensembles dans chaque Exercise.

Maintenant, lorsque nous initialisons WorkoutSession, le site duration_minutes est dynamiquement augmenté de trois minutes pour chaque série de chaque exercice.

# Adding an exercise with three sets
hiit_friday = WorkoutSession([Exercise("Diamond push-ups", 10, 3)])

hiit_friday.duration_minutes
9

En général, si vous souhaitez définir un champ qui dépend d'autres champs de votre classe de données, vous pouvez utiliser la logique __post_init__.

L'immutabilité dans les classes de données

Notre classe de données WorkoutSession est presque prête ; il ne reste plus qu'à la protéger. À l'heure actuelle, il est assez facile d'y mettre le bazar :

hiit_friday.duration_minutes = 1000

hiit_friday.duration_minutes
1000

del hiit_friday.exercises

Nous voulons protéger tous les champs de nos classes afin qu'ils ne puissent être modifiés qu'à notre guise. Pour ce faire, le décorateur @dataclass propose un argument pratique frozen:

@dataclass(frozen=True)
class FrozenExercise:
   name: str
   reps: int
   sets: int
   weight: int | float = 0


ex1 = FrozenExercise("Muscle-ups", 5, 3)

Maintenant, si nous voulons modifier un champ, nous obtenons une erreur :

ex1.sets = 5
FrozenInstanceError: cannot assign to field 'sets'

La définition de frozen en True ajoute automatiquement les méthodes __deleteattr__ et __setattr__ pour chaque champ afin qu'ils soient protégés contre la suppression ou les mises à jour après l'initialisation. En outre, les autres ne pourront pas non plus ajouter de nouveaux champs :

ex1.new_field = 10
FrozenInstanceError: cannot assign to field 'new_field'

Cette fonctionnalité comporterait des dizaines de lignes de code si nous avions affaire à des classes traditionnelles.

Notez toutefois que nous ne pouvons pas rendre nos classes réellement immuables. Par exemple, réécrivons le site WorkoutSession en remplaçant frozen par True:

@dataclass(frozen=True)
class ImmutableWorkoutSession:
   exercises: List[Exercise] = field(default_factory=create_warmup)
   duration_minutes: int = 5


session1 = ImmutableWorkoutSession()

Comme prévu, nous ne pouvons pas modifier directement la liste des exercices :

session1.exercises = [Exercise()]

Cependant, exercises est une liste, qui est entièrement mutable, ce qui rend l'opération suivante possible :

# Changement d'un des éléments d'une 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)

Pour se prémunir contre les modifications accidentelles, il est donc recommandé d'utiliser des objets immuables, tels que des tuples, pour les valeurs des champs.

Héritage dans les classes de données

Un dernier point que nous aborderons est l'ordre des champs dans les classes parentales et enfantines.

Comme les classes de données sont des classes normales, l'héritage fonctionne comme d'habitude :

@dataclass(frozen=True)
class ImmutableWorkoutSession:
   exercises: List[Exercise] = field(default_factory=create_warmup)
   duration_minutes: int = 5


@dataclass(frozen=True)
class CardioWorkoutSession(ImmutableWorkoutSession):
   pass

Mais comme le dernier champ de la classe mère (ImmutableWorkoutSession) a une valeur par défaut, tous les champs des classes enfants doivent avoir des valeurs par défaut.

Par exemple, ceci n'est pas autorisé :

@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

Inconvénients des classes de données et autres ressources

Les classes de données ont été constamment améliorées depuis Python 3.7 (elles étaient excellentes au départ) et couvrent de nombreux cas d'utilisation où vous pourriez avoir besoin d'écrire des classes. Mais ils peuvent être désavantageux dans les scénarios suivants :

  • Méthodes personnalisées __init__
  • Méthodes personnalisées __new__
  • Différents modèles d'héritage

Et bien d'autres encore, comme en témoigne cet excellent fil de discussion sur Reddit. Si vous souhaitez une explication plus détaillée des raisons pour lesquelles les classes de données ont été introduites et pourquoi elles ne remplacent pas directement les définitions de classes ordinaires, lisez le document PEP 557.

Si vous êtes intéressé par la programmation orientée objet en général, voici un cours qui vous permettra de poursuivre votre voyage :

Fondamentalement, les classes de données sont des structures plus sophistiquées qui permettent de conserver et d'extraire des données plus efficacement. Cependant, Python dispose de nombreuses autres structures de données qui effectuent cette tâche de manière plus ou moins similaire. Par exemple, vous pouvez en apprendre davantage sur les compteurs, defaultdicts et namedtuples dans le dernier chapitre du cours Data Types for Data Science.


Bex Tuychiev's photo
Author
Bex Tuychiev
LinkedIn

Je suis un créateur de contenu en science des données avec plus de 2 ans d'expérience et l'un des plus grands followings sur Medium. J'aime écrire des articles détaillés sur l'IA et la ML dans un style un peu sarcastıc, car il faut bien faire quelque chose pour les rendre un peu moins ennuyeux. J'ai produit plus de 130 articles et un cours DataCamp, et un autre est en cours d'élaboration. Mon contenu a été vu par plus de 5 millions de personnes, dont 20 000 sont devenues des adeptes sur Medium et LinkedIn. 

Sujets

Continuez à apprendre Python

cours

Intermediate Python

4 hr
1.2M
Level up your data science skills by creating visualizations using Matplotlib and manipulating DataFrames with pandas.
Afficher les détailsRight Arrow
Commencer le cours
Voir plusRight Arrow
Apparenté

blog

2022-2023 Rapport annuel DataCamp Classrooms

À l'aube de la nouvelle année scolaire, DataCamp Classrooms est plus motivé que jamais pour démocratiser l'apprentissage des données, avec plus de 7 650 nouveaux Classrooms ajoutés au cours des 12 derniers mois.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

8 min

blog

Q2 2023 DataCamp Donates Digest

DataCamp Donates a offert plus de 20k bourses d'études à nos partenaires à but non lucratif au deuxième trimestre 2023. Découvrez comment des apprenants défavorisés et assidus ont transformé ces opportunités en réussites professionnelles qui ont changé leur vie.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

blog

Nous avons fait don de bourses DataCamp Premium à un million de personnes, et ce n'est pas fini.

Réparties entre nos deux programmes d'impact social, DataCamp Classrooms et #DCDonates, les bourses offrent un accès illimité à tout ce que DataCamp Premium a à offrir.
Nathaniel Taylor-Leach's photo

Nathaniel Taylor-Leach

blog

Les 32 meilleures questions d'entretien sur AWS et leurs réponses pour 2024

Un guide complet pour explorer les questions d'entretien AWS de base, intermédiaires et avancées, ainsi que des questions basées sur des situations réelles. Il couvre tous les domaines, garantissant ainsi une stratégie de préparation bien équilibrée.
Zoumana Keita 's photo

Zoumana Keita

30 min

blog

Célébration de Saghar Hazinyar : Une boursière de DataCamp Donates et une diplômée de Code to Inspire

Découvrez le parcours inspirant de Saghar Hazinyar, diplômée de Code to Inspire, qui a surmonté les défis en Afghanistan et s'est épanouie grâce à une bourse de DataCamp Donates.
Fereshteh Forough's photo

Fereshteh Forough

4 min

blog

Les 20 meilleures questions d'entretien pour les flocons de neige, à tous les niveaux

Vous êtes actuellement à la recherche d'un emploi qui utilise Snowflake ? Préparez-vous à répondre à ces 20 questions d'entretien sur le flocon de neige pour décrocher le poste !
Nisha Arya Ahmed's photo

Nisha Arya Ahmed

20 min

Voir plusVoir plus