Les classes en Python

La programmation orientée objet (POO) est l’un des atouts de Python. Elle permet d’adapter des instructions à un type particulier d’objet. En apparence plus complexe que la programmation fonctionnelle évoquée précédemment, elle permet néanmoins de bien rélféchir à la structure des objets utilisés. Ce chapitre vise à quelques rappels sur la programmation orientée objet.

Tutoriel
Rappels
Author

Lino Galiana

Published

2024-04-27

1 Qu’est-ce que la programmation orientée objet ?

Le langage Python se base sur des objets et définit pour eux des actions. Selon le type d’objet, les actions seront différentes. On parle à ce propos de langage orienté objet ce qui signifie que la syntaxe du langage Python permet de définir de manière conceptuelle des objets et appliquer des traitements cohérents avec leur structure interne.

Par exemple, pour manipuler des données textuelles ou numériques, on aura besoin d’appliquer des méthodes différentes. Prenons l’exemple de l’opération +. Pour des données numériques, il s’agit de l’addition. Pour des données textuelles, l’addition n’a pas de sens mais on peut envisager d’appliquer cette opération pour faire de la concaténation.

Chaque type d’objet se verra donc appliquer des actions adaptées. Cela offre une grande flexibilité au langage Python car on peut définir une méthode générique (par exemple l’addition) et l’adapter à différents types d’objets.

Le fait que Python soit un langage orienté objet a une influence sur la syntaxe. On retrouvera régulière la syntaxe objet.method qui est au coeur de Python. Par exemple pd.DataFrame.mean se traduit par appliquer la méthode mean a un objet de type pd.DataFrame.

1.1 Quand utilise-t-on cela dans le domaine de la data science ?

Les réseaux de neurones programmés avec Keras ou PyTorch fonctionnent de cette manière. On part d’une structure de base et modifie les attributs (par exemple le nombre de couches) ou les méthodes.

2 La définition d’un objet

Pour définir un objet, il faut lui donner des caractéristiques et des actions, ce qu’il est, ce qu’il peut faire.

Avec une liste, on peut ajouter des éléments par exemple avec l’action .append(). On peut créer autant d’objets “liste” qu’on le souhaite.

Une classe regroupe des fonctions et des attributs qui définissent un objet. Un objet est une instance d’une classe, c’est-à-dire un exemplaire issu de la classe. L’objet avec un comportement et un état, tous deux définis par la classe. On peut créer autant d’objets que l’on désire avec une classe donnée.

Ici nous allons essayer de créer une classe chat, avec des attributs pour caractériser le chat et des actions, pour voir ce qu’il peut faire avec un objet de la classe chat.

3 Exemple : la Classe chat()

3.1 Les attributs de la classe chat

3.1.1 Classe chat version 1 - premiers attributs

On veut pouvoir créer un objet chat() qui nous permettra à terme de créer une colonie de chats (on sait jamais ca peut servir …). Pour commencer, on va définir un chat avec des attributs de base : une couleur et un nom.

class chat:  # Définition de notre classe chat
    """Classe définissant un chat caractérisé par :
    - son nom
    - sa couleur"""

    def __init__(self):  # Notre méthode constructeur -
        # self c'est notre objet qu'on est en train de créer
        """Pour l'instant, on ne va définir que deux attributs - nom et couleur"""
        self.couleur = "Noir"
        self.nom = "Aucun nom"
mon_chat = chat()

print(type(mon_chat), mon_chat.couleur, ",", mon_chat.nom)
<class '__main__.chat'> Noir , Aucun nom

On nous dit bien que Mon chat est défini à partir de la classe chat, c’est ce que nous apprend la fonction type. Pour l’instant il n’a pas de nom

3.1.2 Classe chat version 2 - autres attributs

Avec un nom et une couleur, on ne va pas loin. On peut continuer à définir des attributs pour la classe chat de la même façon que précédemment.

class chat:  # Définition de notre classe chat
    """Classe définissant un chat caractérisé par :
    - sa couleur
    - son âge
    - son caractère
    - son poids
    - son maitre
    - son nom"""

    def __init__(self):  # Notre méthode constructeur -
        # self c'est notre objet qu'on est en train de créer
        self.couleur = "Noir"
        self.age = 10
        self.caractere = "Joueur"
        self.poids = 3
        self.maitre = "Jeanne"
        self.nom = "Aucun nom"
help(chat)
# si on veut savoir ce que fait la classe "chat" on appelle l'aide
Help on class chat in module __main__:

class chat(builtins.object)
 |  Classe définissant un chat caractérisé par :
 |  - sa couleur
 |  - son âge
 |  - son caractère
 |  - son poids
 |  - son maitre
 |  - son nom
 |  
 |  Methods defined here:
 |  
 |  __init__(self)
 |      Initialize self.  See help(type(self)) for accurate signature.
 |  
 |  ----------------------------------------------------------------------
 |  Data descriptors defined here:
 |  
 |  __dict__
 |      dictionary for instance variables (if defined)
 |  
 |  __weakref__
 |      list of weak references to the object (if defined)
mon_chat = chat()
print("L'âge du chat est", mon_chat.age, "ans")
# on avait défini l'attribut age de la classe chat comme étant égal à 10
# , si on demande l'attribut age de notre Martin on obtient 10
L'âge du chat est 10 ans

Par défaut, les attributs de la classe Chat seront toujours les mêmes à chaque création de chat à partir de la classe Chat.

Mais une fois qu’une instance de classe est créée (ici mon chat est une instance de classe) on peut décider de changer la valeur de ses attributs.

3.1.3 Un nouveau poids

print(mon_chat.poids)
# si on veut changer le poids de mon chat, parce qu'il a un peu grossi après les fêtes
mon_chat.poids = 3.5
print(mon_chat.poids)  # maintenant le poids est 3.5
3
3.5

3.1.4 Un nouveau nom

# on veut aussi lui donner un nom
mon_chat.nom = "Martin"
mon_chat.nom
'Martin'

3.1.5 Une autre instance de la classe Chat

On peut aussi créer d’autres objets chat à partir de la classe chat :

# on appelle la classe
l_autre_chat = chat()
# on change les attributs qui nous intéressent
l_autre_chat.nom = "Ginette"
l_autre_chat.maitre = "Roger"
# les attributs inchangés donnent la même chose
# que ceux définis par défaut pour la classe
print(l_autre_chat.couleur)
Noir

3.2 Les méthodes de la classe chat

Les attributs sont des variables propres à notre objet, qui servent à le caractériser.

Les méthodes sont plutôt des actions, comme nous l’avons vu dans la partie précédente, agissant sur l’objet.

Par exemple, la méthode append de la classe list permet d’ajouter un élément dans l’objet list manipulé.

3.2.1 Classe chat version 3 - première méthode

On peut définir une première méthode : nourrir

class chat:  # Définition de notre classe chat
    """Classe définissant un chat caractérisé par :
    - sa couleur
    - son âge
    - son caractère
    - son poids
    - son maitre
    - son nom

    L'objet chat a une méthode : nourrir"""

    def __init__(self):  # Notre méthode constructeur -
        # self c'est notre objet qu'on est en train de créer
        self.couleur = "Noir"
        self.age = 10
        self.caractere = "Joueur"
        self.poids = 3
        self.maitre = "Jeanne"
        self.nom = "Aucun nom"

        """Par défaut, notre ventre est vide"""
        self.ventre = ""

    def nourrir(self, nourriture):
        """Méthode permettant de donner à manger au chat.
        Si le ventre n'est pas vide, on met une virgule avant de rajouter
        la nourriture"""
        if self.ventre != "":
            self.ventre += ","
        self.ventre += nourriture
mon_chat = chat()
mon_chat.nom = "Martin"
mon_chat.ventre  # On n'a rien donné à Martin, son ventre est vide
''
# on appelle la méthode "nourrir" de la classe chat,
# on lui donne un élément, ici des croquettes
mon_chat.nourrir("Croquettes")
print("Le contenu du ventre de martin : ", mon_chat.ventre)
Le contenu du ventre de martin :  Croquettes
mon_chat.nourrir("Saumon")
print("Le contenu du ventre de martin : ", mon_chat.ventre)
Le contenu du ventre de martin :  Croquettes,Saumon

3.2.2 Classe chat version 4 - autre méthode

Avec un chat, on peut imaginer plein de méthodes. Ici on va définir une action “nourrir” et une autre action “litiere”, qui consiste à vider l’estomac du chat.

class chat:  # Définition de notre classe Personne
    """Classe définissant un chat caractérisé par :
    - sa couleur
    - son âge
    - son caractère
    - son poids
    - son maitre
    - son nom

    L'objet chat a deux méthodes : nourrir et litiere"""

    def __init__(self):  # Notre méthode constructeur -
        # self c'est notre objet qu'on est en train de créer
        self.nom = ""
        self.couleur = "Roux"
        self.age = 10
        self.caractere = "Joueur"
        self.poids = 3
        self.maitre = "Jeanne"
        """Par défaut, notre ventre est vide"""
        self.ventre = ""

    def nourrir(self, nourriture):
        """Méthode permettant de donner à manger au chat.
        Si le ventre n'est pas vide, on met une virgule avant de rajouter
        la nourriture"""
        if self.ventre != "":
            self.ventre += ","
        self.ventre += nourriture

    def litiere(self):
        """Méthode permettant au chat d'aller à sa litière :
        en conséquence son ventre est vide"""
        self.ventre = ""
        print(self.nom, "a le ventre vide")
# on définit Martin le chat
mon_chat = chat()
mon_chat.nom = "Martin"
# on le nourrit avec des croquettes
mon_chat.nourrir("croquettes")
print("Le contenu du ventre de martin", mon_chat.ventre)


# Il va dans sa litiere
mon_chat.litiere()
Le contenu du ventre de martin croquettes
Martin a le ventre vide
help(mon_chat.nourrir)
help(mon_chat.litiere)
Help on method nourrir in module __main__:

nourrir(nourriture) method of __main__.chat instance
    Méthode permettant de donner à manger au chat.
    Si le ventre n'est pas vide, on met une virgule avant de rajouter
    la nourriture

Help on method litiere in module __main__:

litiere() method of __main__.chat instance
    Méthode permettant au chat d'aller à sa litière : 
    en conséquence son ventre est vide

3.2.3 Les méthodes spéciales (facultatif)

Si on reprend notre classe chat, il y a en réalité des méthodes spéciales que nous n’avons pas définies mais qui sont implicites.

Python comprend seul ce que doivent faire ces méthodes. Il a une idée préconcue de ce qu’elles doivent effectuer comme opération. Si vous ne redéfinissez par une méthode spéciale pour qu’elle fasse ce que vous souhaitez, ca peut donner des résultats inattendus.

Elles servent à plusieurs choses :

  • à initialiser l’objet instancié : __init__
  • à modifier son affichage : __repr__
# pour avoir la valeur de l'attribut "nom"

print(mon_chat.__getattribute__("nom"))
# on aurait aussi pu faire plus simple :
print(mon_chat.nom)
Martin
Martin
# si l'attribut n'existe pas : on a une erreur
# Python recherche l'attribut et, s'il ne le trouve pas dans l'objet et si une méthode __getattr__ est spécifiée,
# il va l'appeler en lui passant en paramètre le nom de l'attribut recherché, sous la forme d'une chaîne de caractères.

print(mon_chat.origine)
## Error in py_call_impl(callable, dots$args, dots$keywords): AttributeError: 'chat' object has no attribute 'origine'
## 
## Detailed traceback: 
##   File "<string>", line 1, in <module>

Mais on peut modifier les méthodes spéciales de notre classe chat pour éviter d’avoir des erreurs d’attributs. On va aussi en profiter pour modifier la représentation de l’instance chat qui pour l’instant donne <_main_.chat object at 0x0000000005AB4C50>

3.2.4 Classe chat version 5 - méthode spéciale

class chat:  # Définition de notre classe Personne
    """Classe définissant un chat caractérisé par :
    - sa couleur
    - son âge
    - son caractère
    - son poids
    - son maitre
    - son nom

    L'objet chat a deux méthodes : nourrir et litiere"""

    def __init__(self):  # Notre méthode constructeur -
        # self c'est notre objet qu'on est en train de créer
        self.nom = ""
        self.couleur = "Roux"
        self.age = 10
        self.caractere = "Joueur"
        self.poids = 3
        self.maitre = "Jeanne"
        """Par défaut, notre ventre est vide"""
        self.ventre = ""

    def nourrir(self, nourriture):
        """Méthode permettant de donner à manger au chat.
        Si le ventre n'est pas vide, on met une virgule avant de rajouter
        la nourriture"""
        if self.ventre != "":
            self.ventre += ","
        self.ventre += nourriture

    def litiere(self):
        """Méthode permettant au chat d'aller à sa litière :
        en conséquence son ventre est vide"""
        self.ventre = ""
        print(self.nom, "a le ventre vide")

    def __getattribute__(self, key):
        return print(key, "n'est pas un attribut de la classe chat")

    def __repr__(self):
        return "Je suis une instance de la classe chat"
# j'ai gardé l'exemple chat défini selon la classe version 4
# Martin, le chat
# on a vu précédemment qu'il n'avait pas d'attribut origine
# et que cela levait une erreur AttributeError
print(mon_chat.nom)


# on va définir un nouveau chat avec la version 5
# on appelle à nouveau un attribut qui n'existe pas "origine"
# on a bien le message défini par la méthode spéciale _gettattribute

mon_chat_nouvelle_version = chat()
mon_chat_nouvelle_version.origine

# Maintenant on a aussi une définition de l'objet plus clair
print(mon_chat)
print(mon_chat_nouvelle_version)
Martin
origine n'est pas un attribut de la classe chat
<__main__.chat object at 0x7fedeeeca590>
Je suis une instance de la classe chat

3.3 Conclusion sur les classes : ce qu’on retient

  • Les méthodes se définissent comme des fonctions, sauf qu’elles se trouvent dans le corps de la classe.

  • On définit les attributs d’une instance dans le constructeur de sa classe, en suivant cette syntaxe : self.nom_attribut = valeur.

  • facultatif : Les méthodes d’instance prennent en premier paramètre “self”, l’instance de l’objet manipulé.

  • facultatif : On construit une instance de classe en appelant son constructeur, une méthode d’instance appelée init.

Informations additionnelles

environment files have been tested on.

Latest built version: 2024-04-27

Python version used:

'3.11.6 | packaged by conda-forge | (main, Oct  3 2023, 10:40:35) [GCC 12.3.0]'
Package Version
affine 2.4.0
aiobotocore 2.12.2
aiohttp 3.9.3
aioitertools 0.11.0
aiosignal 1.3.1
alembic 1.13.1
aniso8601 9.0.1
annotated-types 0.6.0
appdirs 1.4.4
archspec 0.2.3
astroid 3.1.0
asttokens 2.4.1
attrs 23.2.0
Babel 2.14.0
bcrypt 4.1.2
beautifulsoup4 4.12.3
black 24.4.2
blinker 1.7.0
blis 0.7.11
bokeh 3.4.0
boltons 23.1.1
boto3 1.34.51
botocore 1.34.51
branca 0.7.1
Brotli 1.1.0
cachetools 5.3.3
cartiflette 0.0.2
Cartopy 0.23.0
catalogue 2.0.10
cattrs 23.2.3
certifi 2024.2.2
cffi 1.16.0
charset-normalizer 3.3.2
click 8.1.7
click-plugins 1.1.1
cligj 0.7.2
cloudpathlib 0.16.0
cloudpickle 3.0.0
colorama 0.4.6
comm 0.2.2
commonmark 0.9.1
conda 24.3.0
conda-libmamba-solver 24.1.0
conda-package-handling 2.2.0
conda_package_streaming 0.9.0
confection 0.1.4
contextily 1.6.0
contourpy 1.2.1
cryptography 42.0.5
cycler 0.12.1
cymem 2.0.8
cytoolz 0.12.3
dask 2024.4.1
dask-expr 1.0.10
debugpy 1.8.1
decorator 5.1.1
dill 0.3.8
distributed 2024.4.1
distro 1.9.0
docker 7.0.0
duckdb 0.10.1
en-core-web-sm 3.7.1
entrypoints 0.4
et-xmlfile 1.1.0
exceptiongroup 1.2.0
executing 2.0.1
fastjsonschema 2.19.1
fiona 1.9.6
flake8 7.0.0
Flask 3.0.2
folium 0.16.0
fontawesomefree 6.5.1
fonttools 4.51.0
frozenlist 1.4.1
fsspec 2023.12.2
GDAL 3.8.4
gensim 4.3.2
geographiclib 2.0
geopandas 0.12.2
geoplot 0.5.1
geopy 2.4.1
gitdb 4.0.11
GitPython 3.1.43
google-auth 2.29.0
graphene 3.3
graphql-core 3.2.3
graphql-relay 3.2.0
graphviz 0.20.3
great-tables 0.5.0
greenlet 3.0.3
gunicorn 21.2.0
htmltools 0.5.1
hvac 2.1.0
idna 3.6
imageio 2.34.1
importlib_metadata 7.1.0
importlib_resources 6.4.0
inflate64 1.0.0
ipykernel 6.29.3
ipython 8.22.2
ipywidgets 8.1.2
isort 5.13.2
itsdangerous 2.1.2
jedi 0.19.1
Jinja2 3.1.3
jmespath 1.0.1
joblib 1.3.2
jsonpatch 1.33
jsonpointer 2.4
jsonschema 4.21.1
jsonschema-specifications 2023.12.1
jupyter-cache 1.0.0
jupyter_client 8.6.1
jupyter_core 5.7.2
jupyterlab_widgets 3.0.10
kaleido 0.2.1
kiwisolver 1.4.5
kubernetes 29.0.0
langcodes 3.4.0
language_data 1.2.0
lazy_loader 0.4
libmambapy 1.5.7
llvmlite 0.42.0
locket 1.0.0
lxml 5.2.1
lz4 4.3.3
Mako 1.3.2
mamba 1.5.7
mapclassify 2.6.1
marisa-trie 1.1.0
Markdown 3.6
MarkupSafe 2.1.5
matplotlib 3.8.3
matplotlib-inline 0.1.6
mccabe 0.7.0
menuinst 2.0.2
mercantile 1.2.1
mizani 0.11.2
mlflow 2.11.3
mlflow-skinny 2.11.3
msgpack 1.0.7
multidict 6.0.5
multivolumefile 0.2.3
munkres 1.1.4
murmurhash 1.0.10
mypy 1.9.0
mypy-extensions 1.0.0
nbclient 0.10.0
nbformat 5.10.4
nest_asyncio 1.6.0
networkx 3.3
nltk 3.8.1
numba 0.59.1
numpy 1.26.4
oauthlib 3.2.2
opencv-python-headless 4.9.0.80
openpyxl 3.1.2
OWSLib 0.28.1
packaging 23.2
pandas 2.2.1
paramiko 3.4.0
parso 0.8.4
partd 1.4.1
pathspec 0.12.1
patsy 0.5.6
Pebble 5.0.7
pexpect 4.9.0
pickleshare 0.7.5
pillow 10.3.0
pip 24.0
pkgutil_resolve_name 1.3.10
platformdirs 4.2.0
plotly 5.19.0
plotnine 0.13.5
pluggy 1.4.0
polars 0.20.18
preshed 3.0.9
prometheus_client 0.20.0
prometheus-flask-exporter 0.23.0
prompt-toolkit 3.0.42
protobuf 4.25.3
psutil 5.9.8
ptyprocess 0.7.0
pure-eval 0.2.2
py7zr 0.20.8
pyarrow 15.0.0
pyarrow-hotfix 0.6
pyasn1 0.5.1
pyasn1-modules 0.3.0
pybcj 1.0.2
pycodestyle 2.11.1
pycosat 0.6.6
pycparser 2.21
pycryptodomex 3.20.0
pydantic 2.7.1
pydantic_core 2.18.2
pyflakes 3.2.0
Pygments 2.17.2
PyJWT 2.8.0
pylint 3.1.0
PyNaCl 1.5.0
pynsee 0.1.7
pyOpenSSL 24.0.0
pyparsing 3.1.2
pyppmd 1.1.0
pyproj 3.6.1
pyshp 2.3.1
PySocks 1.7.1
python-dateutil 2.9.0
python-dotenv 1.0.1
python-magic 0.4.27
pytz 2024.1
pyu2f 0.1.5
pywaffle 1.1.0
PyYAML 6.0.1
pyzmq 25.1.2
pyzstd 0.15.10
QtPy 2.4.1
querystring-parser 1.2.4
rasterio 1.3.10
referencing 0.34.0
regex 2023.12.25
requests 2.31.0
requests-cache 1.2.0
requests-oauthlib 2.0.0
rpds-py 0.18.0
rsa 4.9
Rtree 1.2.0
ruamel.yaml 0.18.6
ruamel.yaml.clib 0.2.8
s3fs 2023.12.2
s3transfer 0.10.1
scikit-image 0.23.2
scikit-learn 1.4.1.post1
scipy 1.13.0
seaborn 0.13.2
setuptools 69.2.0
shapely 2.0.3
six 1.16.0
smart-open 6.4.0
smmap 5.0.0
snuggs 1.4.7
sortedcontainers 2.4.0
soupsieve 2.5
spacy 3.7.4
spacy-legacy 3.0.12
spacy-loggers 1.0.5
SQLAlchemy 2.0.29
sqlparse 0.4.4
srsly 2.4.8
stack-data 0.6.2
statsmodels 0.14.1
tabulate 0.9.0
tblib 3.0.0
tenacity 8.2.3
texttable 1.7.0
thinc 8.2.3
threadpoolctl 3.4.0
tifffile 2024.4.24
tomli 2.0.1
tomlkit 0.12.4
toolz 0.12.1
topojson 1.8
tornado 6.4
tqdm 4.66.2
traitlets 5.14.2
truststore 0.8.0
typer 0.9.4
typing_extensions 4.11.0
tzdata 2024.1
Unidecode 1.3.8
url-normalize 1.4.3
urllib3 1.26.18
wasabi 1.1.2
wcwidth 0.2.13
weasel 0.3.4
webcolors 1.13
webdriver-manager 4.0.1
websocket-client 1.7.0
Werkzeug 3.0.2
wheel 0.43.0
widgetsnbextension 4.0.10
wordcloud 1.9.3
wrapt 1.16.0
xgboost 2.0.3
xlrd 2.0.1
xyzservices 2024.4.0
yarl 1.9.4
yellowbrick 1.5
zict 3.0.0
zipp 3.17.0
zstandard 0.22.0

View file history

SHA Date Author Description
d75641d 2024-04-22 18:59:01 Lino Galiana Editorialisation des chapitres de manipulation de données (#491)
005d89b 2023-12-20 17:23:04 Lino Galiana Finalise l’affichage des statistiques Git (#478)
4c1c22d 2023-12-10 11:50:56 Lino Galiana Badge en javascript plutôt (#469)
1f23de2 2023-12-01 17:25:36 Lino Galiana Stockage des images sur S3 (#466)
69cf52b 2023-11-21 16:12:37 Antoine Palazzolo [On-going] Suggestions chapitres modélisation (#452)
a771183 2023-10-09 11:27:45 Antoine Palazzolo Relecture TD2 par Antoine (#418)
3bdf3b0 2023-08-25 11:23:02 Lino Galiana Simplification de la structure 🤓 (#393)
78ea2cb 2023-07-20 20:27:31 Lino Galiana Change titles levels (#381)
2dbf853 2023-07-05 11:21:40 Lino Galiana Add nice featured images (#368)
f10815b 2022-08-25 16:00:03 Lino Galiana Notebooks should now look more beautiful (#260)
d201e3c 2022-08-03 15:50:34 Lino Galiana Pimp la homepage ✨ (#249)
12965ba 2022-05-25 15:53:27 Lino Galiana :launch: Bascule vers quarto (#226)
6777f03 2021-10-29 09:38:09 Lino Galiana Notebooks corrections (#171)
2a8809f 2021-10-27 12:05:34 Lino Galiana Simplification des hooks pour gagner en flexibilité et clarté (#166)
a1b8aaf 2021-09-20 09:05:55 Lino Galiana Badges de telechargement dans les premiers TP (#146)
85ba119 2021-09-16 11:27:56 Lino Galiana Relectures des TP KA avant 1er cours (#142)
aeb3995 2021-07-06 11:11:03 avouacr Relecture et ajouts sur anaconda + jupyter (#116)
4cdb759 2021-05-12 10:37:23 Lino Galiana :sparkles: :star2: Nouveau thème hugo :snake: :fire: (#105)
c3c7433 2020-09-15 12:41:26 Lino Galiana Improve CI with gitlab and jupyter nb conversion (#35)
913047d 2020-09-08 14:44:41 Lino Galiana Harmonisation des niveaux de titre (#17)
56f8532 2020-09-08 10:40:03 Lino Galiana Reprise des éléments de la première séance dans le site web (#14)
Back to top

Citation

BibTeX citation:
@book{galiana2023,
  author = {Galiana, Lino},
  title = {Python Pour La Data Science},
  date = {2023},
  url = {https://pythonds.linogaliana.fr/},
  doi = {10.5281/zenodo.8229676},
  langid = {en}
}
For attribution, please cite this work as:
Galiana, Lino. 2023. Python Pour La Data Science. https://doi.org/10.5281/zenodo.8229676.