0% ont trouvé ce document utile (0 vote)
2 vues36 pages

Procédures Python et R pour Data Science

Ce document présente les notions de procédures et de fonctions, ainsi que leur implémentation avec Python et R. Il aborde également des concepts de programmation fonctionnelle, comme le currying, de manière informative. Le papier souligne l'importance de comprendre ces concepts pour développer des programmes efficaces et bien structurés, et met en évidence les similitudes et différences entre les instructions Python et R pour offrir une perspective comparative.

Transféré par

Kamingu
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd
0% ont trouvé ce document utile (0 vote)
2 vues36 pages

Procédures Python et R pour Data Science

Ce document présente les notions de procédures et de fonctions, ainsi que leur implémentation avec Python et R. Il aborde également des concepts de programmation fonctionnelle, comme le currying, de manière informative. Le papier souligne l'importance de comprendre ces concepts pour développer des programmes efficaces et bien structurés, et met en évidence les similitudes et différences entre les instructions Python et R pour offrir une perspective comparative.

Transféré par

Kamingu
Copyright
© All Rights Reserved
Nous prenons très au sérieux les droits relatifs au contenu. Si vous pensez qu’il s’agit de votre contenu, signalez une atteinte au droit d’auteur ici.
Formats disponibles
Téléchargez aux formats PDF, TXT ou lisez en ligne sur Scribd

Série Optimall Python vs.

R pour Data Scientists (Français)


Vol. 001, Num. 003

Python vs. R pour Data Scientists : Procédures et Fonctions


Gradi L. Kamingu∗
13 juillet 2023

Résumé
Ce papier présente les notions de procédures et de fonctions, ainsi que leur implémen-
tation à l’aide des langages de programmation Python et R. De plus, le papier aborde
certaines notions de programmation fonctionnelle, telles que le currying, en les présentant
sous une forme informative. Nous soulignons l’importance de comprendre ces concepts
pour développer des programmes efficaces et bien structurés. Le papier met également en
évidence les similitudes et les différences entre les instructions Python et R, offrant aux
lecteurs une perspective comparative.
Keywords : Procédure ; Fonction ; Programmation fonctionnelle ; Langage Python, Langage R.


Chercheur au Laboratoire d’Optimisation et Apprentissage Automatique (OPTIMALL), RD Congo.
E-mail : [Link]@[Link].
1 Introduction
À mesure que les programmes deviennent de plus en plus complexes, il devient de plus en plus labo-
rieux de les résoudre en implémentant directement les algorithmes correspondants. C’est pourquoi il est
utile de décomposer le problème en sous-problèmes indépendants et de résoudre chaque sous-problème
de manière autonome. C’est là qu’intervient la notion de sous-programme (ou sous-algorithme), qui
est un outil puissant en programmation (Knuth, 1997a). En effet, une utilisation judicieuse des fonc-
tions, notamment grâce à l’approche de programmation structurée, peut considérablement réduire les
coûts de développement et de maintenance d’un programme complexe, tout en améliorant sa qualité
et sa fiabilité. C’est pourquoi la syntaxe de nombreux langages de programmation intègre la possibilité
d’écrire et d’utiliser des sous-programmes.

Alors qu’Alan Turing (1945) avait déjà introduit le concept de sous-programmes dans un article
traitant de propositions de conception pour l’ordinateur NPL ACE, l’idée fondamentale de sous-
programmes a émergé des travaux de John Mauchly et Kathleen Antonelli sur l’ENIAC (Dasgupta,
2014). Cependant, la formalisation de ce concept eut lieu lors d’un symposium tenu à Harvard en
janvier 1947 (Mauchly, 1982). David Wheeler 1 , ainsi que Maurice Wilkes et Stanley Gill, sont géné-
ralement crédités de l’invention des sous-programmes vers 1951 (appelés sous-programmes fermés).
Ils ont également fourni l’explication initiale sur la façon de concevoir des bibliothèques de logiciels
(Wilkes et al., 1951; Wheeler, 1952).

Le reste de papier se structure de la manière suivante. Nous procédons à la présentation de la


notion de routine dans la section 2, puis présentons les procédures et fonctions en Python dans la
section 3, et les procédures et fonctions en R dans la section 4. Enfin, nous discutons des éléments de
comparaison de ces deux langages dans la section 6 avant de conclure.

2 Routines
2.1 Notion de routine
Plus l’algorithme devient complexe, plus il y a de chances d’avoir à effectuer le même traitement,
ou des traitements similaires, en plusieurs endroits (Darmangeat, 2008). D’où l’utilisation de routines,
appelées aussi sous-programmes (ou sous-algorithmes). C’est comme, par exemple, un algorithme qui
peut répéter dix fois le calcul de la moyenne arithmétique des dix nombres réels ou un algorithme qui
nécessite l’entrée de la réponse «Oui» ou «Non» vingt fois pour différentes questions.

Pour résoudre ce genre de problème, il faudra séparer le traitement répétitif des instructions qui
le composent dans un module à part. Ce module présente plusieurs avantages, notamment :
• La simplification de la complexité des algorithmes en évitant les recopies inutiles, ce qui implique
d’appeler des routines ou de reproduire les mêmes instructions.
• La possibilité de diviser le travail de manière à ce que la réalisation de gros algorithmes puisse
être réalisée de façon autonome au profit d’un gain de temps non négligeable.
• La lisibilité est assurée, c’est-à-dire que l’algorithme étant modulaire, la localisation des erreurs
est aisée ; il suffit de faire une seule modification au bon endroit, pour que la modification soit
effective pour tout l’algorithme.
1. David John Wheeler (1927 – 2004), un informaticien britannique, le premier au monde ayant obtenu
un doctorat en Informatique (en 1951). À l’époque, la plupart des universitaires associés à la recherche sur
l’informatique avaient des diplômes d’études supérieures en Mathématiques.

71
Le corps de l’algorithme est donc l’(e) algorithme (programme) principal ou procédure principale.
Ainsi, il existe deux types d’algorithmes : les procédures et les fonctions :
• Les procédures, qui sont des routines exécutées par un algorithme appelant, qui génèrent géné-
ralement des modifications dans les valeurs de certaines variables ou renvoient plusieurs valeurs
(au lieu d’une seule) ou aucune valeur à chaque appel.
• Les fonctions, qui sont des routines qui doivent retourner une et une seule valeur chaque fois
qu’elles sont appelées à l’algorithme appelant.

Dans la plupart des langages de programmation, la déclaration (et donc la définition) d’une routine
comprend généralement :
• un mot-clé (procédure ou fonction) dans le cas d’une routine dans un langage distinguant
clairement les différentes formes de routine ;
• l’identifiant de la routine (nom donné par le programmeur à la routine) ;
• la description des paramètres indiquant pour chacun (s’il y a des paramètres) :
• l’identifiant (nom) du paramètre,
• le type (explicite ou implicite) du paramètre (dans le cas d’une routine dans un langage
typé).

Dans le cas d’une fonction, la déclaration de la routine comprend également :


• le type de la routine (dans le cas d’une fonction de langage typée), c’est-à-dire le type de sa
valeur à retourner.
Dans le cas d’une fonction, la définition de la routine comprend également :
• un corps contenant le code réalisant l’opération dévolue à cette routine ;
• l’affectation, dans le corps de la routine, d’un résultat à la valeur à retourner de la fonction.

2.2 Procédures
La déclaration d’une procédure se fait de la manière suivante :

Procédure nom_procedure (par1 en type_par1, par2 en type_par2, ... , parn en type_parn)


# Déclaration des variables locales
Var variable1 en type_variable1
Var variable2 en type_variable2
···
Var variablen en type_variablen

# Corps de la procédure
Suites d’instructions
Fin Procédure nom_procedure

En utilisant par1, par2, ..., parn pour représenter les n paramètres de la procédure et type_par1,
type_par2, . . . , type_parn pour désigner leurs types respectifs.

L’exécution (ou l’appel) d’une procédure peut être déclenchée en utilisant son identificateur et, si
nécessaire, en fournissant ses paramètres, séparés par des virgules. Cette action déclenche l’exécution

72
des instructions qui composent la procédure. Lorsqu’une procédure est appelée, le programme inter-
rompt son flux d’exécution normal, exécute les instructions spécifiées dans la procédure, puis revient
au programme appelant pour poursuivre l’exécution à partir de l’instruction suivante.

Il est possible d’avoir une procédure sans aucun paramètre, comme illustré dans l’exemple suivant :

Exemple 2.1. La procédure suivant permet de saluer l’utilisateur :

#La procédure
Procédure salutation()
Afficher «Salut !»
Fin Procédure salutation

#L’algorithme principal
Début
salutation()
Fin

L’algorithme ci-dessus définit une procédure nommée salutation qui affiche le message «Salut !». En-
suite, dans l’algorithme principal, la procédure salutation() est appelée. Ainsi, lorsque l’algorithme
est exécuté, il affiche le message «Salut !».

Exemple 2.2. Toujours dans le même contexte, on peut modifier l’algorithme pour demander à l’utili-
sateur son prénom.

#La procédure
Procédure salutation()
Afficher «Entrer votre prénom :»
Lire prenom
Afficher «Salut », prenom, « !»
Fin Procédure salutation

#L’algorithme principal
Début
salutation()
Fin

Le pseudocode ci-dessus définit une procédure appelée salutation(). Cette procédure demande à
l’utilisateur de saisir son prénom, lit la valeur saisie puis affiche le message «Salut [prénom] !» où [pré-
nom] représente le prénom saisi par l’utilisateur. Dans l’algorithme principal, la procédure salutation
est appelée. Ainsi, lorsque l’algorithme est exécuté, il demande à l’utilisateur son prénom, puis affiche
le message d’accueil correspondant.

Exemple 2.3. Modifions l’algorithme précédent afin que la procédure salutation() prenne un para-
mètre. Ainsi,

#La procédure
Procédure salutation (prenom en chaîne de caractères)
Afficher «Salut », prenom, « !»
Fin Procédure salutation

73
#L’algorithme principal
Début
Afficher «Entrer votre prénom :»
Lire votre_prenom
salutation(votre_prenom)
Fin

L’algorithme précédent permet à l’utilisateur d’entrer son prénom, puis appelle la procédure salutation()
avec ce prénom en tant que paramètre. La procédure salutation() affiche ensuite le message «Salut»
suivi du prénom de l’utilisateur, avec « ! » à la fin.

Prenons un autre exemple où la procédure a plus d’un paramètre.

Exemple 2.4 (Table de multiplication). Supposons que nous souhaitons afficher une partie spécifique
de la table de multiplication d’un nombre donné (que nous appellerons «base»), en affichant chaque
multiplication dans une plage d’opérations définie par deux nombres (un nombre de départ et un nombre
de fin). Voici l’algorithme correspondant :

# Procédure de la table de multiplication


Procédure tableMulti (base en entier, depart en entier, fin en entier)
Afficher «Fragment de la table de multiplication par», base, « :»
Afficher «——————————————————————»
n ← depart
Tant que n ≤ f in :
Afficher n, «x», base, «=», n × base
n←n+1
Fin Procédure tableMulti

# Algorithme principal
Début
tableMulti(4, 1, 12)
Fin.

Lorsque la procédure tableMulti() est appelée avec les paramètres 4, 1 et 12, comme dans l’appel
tableMulti(4, 1, 12) dans l’algorithme principal, l’algorithme affiche un fragment spécifique de la
table de multiplication pour le nombre 4. Plus précisément, il affiche les opérations de multiplication
de 1 à 12 par 4, en mettant en évidence les résultats correspondants.

A noter que s’il y a plusieurs paramètres, comme dans les algorithmes, les arguments doivent être
fournis, lors de l’appel de la procédure, dans le même ordre que celui des paramètres correspondants
(en les séparant également par des virgules). Le premier argument sera affecté au premier paramètre,
le deuxième argument sera au deuxième paramètre, et ainsi de suite, jusqu’au n-ième argument qui
sera assigné au n-ième paramètre.

2.3 Fonctions
La déclaration d’une fonction se fait de la manière suivante :

Fonction nom_fonction (par1 en type_par1, ... , parn en type_parn) en type_fonction

74
# Déclaration des variables locales
Var variable1 en type_variable1
Var variable2 en type_variable2
···
Var variablen en type_variablen

# Corps de la fonction
Suites d’instructions
...
Retourner valeur_a_retourner
Fin Fonction nom_fonction

En utilisant par1, par2, ..., parn pour représenter les n paramètres de la procédure et type_par1,
type_par2, . . . , type_parn pour désigner leurs types respectifs.

Étant donné que la fonction est principalement conçue pour retourner une valeur, il est donc né-
cessaire de spécifier le type de la fonction, qui correspond en réalité au type de valeur_a_retourner.

L’exécution d’une fonction peut être initiée en utilisant son identifiant et, si nécessaire, en four-
nissant ses paramètres. Cette action déclenche l’exécution des instructions qui composent la fonction.
Exemple 2.5.
# Déclaration des variables
Var x, y, s en entier

# La fonction
Fonction somme (nbr1 en entier, nbr2 en entier) en entier
Var som en entier
som ← nbr1 + nbr2
Retourner som
Fin Fonction somme

# L’algorithme principal
Début
Afficher «Entrer la valeur du premier nombre»
Lire nbr1
Afficher «Entrer la valeur du deuxième nombre»
Lire nbr2
s ← somme(x, y)
Afficher «La somme de », x ,«et de », y «est :», s
Fin.

Cet algorithme effectue une opération de somme entre deux nombres saisis par l’utilisateur. Il utilise
une fonction appelée somme(), qui prend deux paramètres entiers et renvoie leur somme. Dans l’algo-
rithme principal, il demande à l’utilisateur d’entrer deux nombres, puis appelle la fonction somme()
avec ces nombres comme arguments. Le résultat de la fonction est ensuite stocké dans une variable s.
Enfin, l’algorithme affiche le message "La somme de x et de y est : s".

La fonction se distingue de la procédure par sa capacité à être appelée par son nom dans une
expression ou une affectation. Comme dans l’exemple suivant :
Exemple 2.6.

75
#Déclaration des variables
Var x, y, z, resultat en entier

#La fonction somme


Fonction som (nbr1 en entier, nbr2 en entier, nbr3 en entier) en entier
Var somme en entier
somme ← nbr1 + nbr2 + nbr3
Retourner somme
Fin Fonction som

#L’algorithme principal
Début
Afficher «Entrer la valeur du premier nombre»
Lire x
Afficher «Entrer la valeur du deuxième nombre»
Lire y
Afficher «Entrer la valeur du troisième nombre»
Lire z
resultat ← −som(x, y, z) +22
Afficher «Le résultat est », resultat
Fin.

Cet algorithme déclare les variables entières x, y, z et resultat. Il définit une fonction som() qui prend
trois paramètres entiers et retourne la somme de ces trois nombres. Dans l’algorithme principal, il
demande à l’utilisateur d’entrer trois nombres, puis il appelle la fonction som() avec ces nombres en
tant qu’arguments et stocke le résultat dans la variable resultat. Enfin, il soustrait 22 du résultat et
affiche le résultat final.

2.4 Passage de paramètres d’une routine


Les échanges d’informations entre une procédure et le sous-algorithme appelant se font au travers
de paramètres. Souligons que les paramètres sont nommés différemment selon leur emplacement dans
le code source. On distingue alors :
• les paramètres formels ou arguments muets, qui sont des variables utilisées dans la routine ;
• les paramètres effectifs, qui sont des variables (ou valeurs) fournies lors de l’appel de la rou-
tine. Certains langages, comme Perl 6, utilisent le terme paramètre pour paramètre formel et
argument pour paramètre effectif.

Cependant, deux grands types de passage de paramètres sont utilisés, offrant des usages distincts : (i)
le passage par valeur ; et (ii) le passage par référence.

2.4.1 Passage par valeur


Le passage par valeur, également connu sous le nom de passage par copie, implique qu’une copie
de la valeur du paramètre effectif est créée et transmise à la routine ou à la fonction. Les modifications
effectuées sur les paramètres formels n’affectent pas les paramètres effectifs.

Du point de vue syntaxique, dans le passage par valeur, on ne met rien devant le paramètre lors
de la déclaration de la routine.

76
Exemple 2.7.

#La procédure incrementer()


Procédure incrementer(valeur)
valeur ← valeur +1
Fin Procédure incrementer

#L’algorithme principal
Début
Var x en entier
x←5
incrementer(x)
Afficher x #Affiche 5, la valeur de x n’a pas été modifiée.
Fin

2.4.2 Passage par référence


Le passage par référence, également connu sous le nom de passage par adresse, implique que
l’adresse mémoire du paramètre effectif est transmise à la routine ou à la fonction. Les modifications
effectuées sur les paramètres formels affectent directement les paramètres effectifs.

Du point de vue syntaxique, dans le passage par référence, le mot-clé «Var», similaire à celui utilisé
dans la déclaration des variables, est positionné devant le paramètre formel lors de la déclaration de
la routine.

Exemple 2.8.

#La procédure incrementer()


Procédure incrementer(Var valeur en entier)
valeur ← valeur +1
Fin Procédure incrementer

#L’algorithme principal
Début
Var x en entier
x←5
incrementer(x)
Afficher x #Affiche 6, la valeur de x a été modifiée par référence.
Fin

Dans l’algorithme de passage par valeur ci-haut, la procédure incrementer() reçoit une copie de la
valeur de la variable x, et lorsque la valeur est modifiée à l’intérieur de la procédure, cela n’affecte
pas la valeur originale de x. Par conséquent, l’affichage de x à la fin renvoie la valeur d’origine, qui
est 5. En revanche, dans l’algorithme de passage par référence donné, la procédure incrementer()
reçoit une référence à la variable x, et lorsque la valeur est modifiée à l’intérieur de la procédure, cela
modifie directement la valeur d’origine de x. Ainsi, l’affichage de x à la fin renvoie la valeur modifiée,
qui est 6.

Notons également que le passage par valeur présente l’avantage de garantir la sécurité et la protec-
tion des données, mais il peut être plus lent en raison de la copie des données et de la consommation
double de l’espace mémoire (cependant, il convient bien pour les variables simples). En revanche, le
passage par référence offre l’avantage d’un accès rapide aux données et d’une occupation mémoire
réduite, car il utilise des adresses. Cependant, il peut présenter des risques en termes de sécurité des

77
données et nécessite une connaissance de la façon dont les données sont physiquement implantées sur
la machine.

2.5 Portée d’une variable


Définition 2.1. La portée d’une variable fait référence à la zone où cette variable est visible et accessible.

Une variable peut être déclarée à deux endroits distincts.

• Une variable déclarée en dehors du corps d’une routine (c’est-à-dire dans la section de décla-
ration de l’algorithme principal) est appelée variable globale ou variable à portée globale. Il est
accessible de n’importe où dans l’algorithme, y compris à partir de procédures et de fonctions.
Il existe pour la durée de vie du programme.

Exemple 2.9. Considérons l’algorithme suivant :

#Déclaration d’une variable globale


Var x en entier
x←4

#La routine avec une variable locale


Procédure additionner()
#Déclaration d’une variable locale
somme ← somme + valeur #Utilisation de la variable globale.
Var y en entier
y ← 12
Afficher x + y #Accès à la variable globale et à la variable locale.
Fin Procédure additionner

#L’algorithme principal
Début
additionner()
Fin.

Dans l’exemple précédent, la variable x est une variable globale qui peut être utilisée à la fois
dans la procédure additionner() et dans l’algorithme principal. La variable y est une variable
locale qui est déclarée et utilisée uniquement dans la procédure additionner(). Ainsi, dans la
procédure, nous pouvons accéder à la fois à la variable globale x et à la variable locale y.

• Une variable déclarée dans une routine est appelée variable locale ou variable de portée lo-
cale. Il n’est accessible qu’à la procédure dans laquelle il est défini et n’est pas accessible aux
autres procédures. La durée de vie d’une variable locale est limitée à l’exécution de la procédure.

Exemple 2.10. Considérons l’algorithme suivant :

#Déclaration d’une variable globale


Var x en entier
x←4

#La procédure avec une variable locale du même nom

78
Procédure aficchage()
#Déclaration d’une variable locale du même nom
Var x en entier
x ← 12
Afficher x #Accès à la variable locale
Fin Procédure affichage

#L’algorithme principal
Début
x #Accès à la variable globale
Fin

Dans cet exemple, nous avons à la fois une variable globale x et une variable locale x dans
la procédure affichage(). Lorsque nous accédons à la variable x à l’intérieur de la routine,
nous nous référons à la variable locale du même nom. D’autre part, lorsque nous accédons à la
variable x en dehors de la procédure, nous nous référons à la variable globale. Ainsi, l’utilisation
du même nom de variable crée une distinction entre la variable globale et la variable locale.

Remarque 2.1. Les variables globales sont à éviter pour la maintenance des programmes.

2.6 Fonctions imbriquées


Définition 2.2. Une fonction imbriquée, également appelée fonction interne ou fonction locale, est une
fonction définie à l’intérieur d’une autre fonction.

Elle peut être appelée uniquement par l’algorithme principal ou par d’autres routines imbriquées,
directement ou indirectement, dans le même algorithme principal.

Exemple 2.11. Prenons l’exemple d’une fonction qui calcule le triple d’un nombre. Ce programme peut
être écrit de manière simple en utilisant une opération de multiplication par 3, ou bien il peut être
formulé comme suit :

Fonction externe (x en entier) en entier


Fonction interne (y en entier) en entier
Retourner x × y
Fin interne
Retourner interne(3)
Fin externe

La fonction externe() prend un argument x de type entier et renvoie également un entier. À l’intérieur
de cette fonction, nous trouvons une autre fonction appelée interne() qui prend un argument y de
type entier et renvoie un entier. La fonction interne() retourne simplement la multiplication de x et y.

Ensuite, à l’intérieur de la fonction externe(), nous utilisons l’instruction Retourner pour ren-
voyer le résultat de l’appel de la fonction interne() avec l’argument 3. D’où, la fonction externe()
renvoie le résultat de la multiplication de x par 3.

2.7 Fonctions récursives


Définition 2.3. Une routine récursive est une routine qui s’appelle elle-même dans sa définition.

79
La récursivité offre la capacité de définir un ensemble infini d’objets à l’aide d’une déclaration finie.
De manière similaire, un programme récursif fini peut décrire un nombre infini de calculs, même s’il
ne contient pas de boucles explicites (Wirth, 1976).

Exemple 2.12. Supposons que nous souhaitons écrire une fonction qui calcule la factorielle d’un entier
n. Pour rappel, la factorielle d’un nombre, notée n!, se calcule comme suit :

n! = n × (n − 1) × (n − 2) × · · · × 2 × 1. (1)
Autrement dit :

n! = n × (n − 1)!. (2)
Cette fonction peut encore se définir de manière équivalente comme suit :
(
1 si n = 0;
n! = (3)
n × (n − 1)! si n > 0.
Cette définition indique que si n est égal à zéro, le résultat est 1. Sinon, si n est supérieur à zéro,
le résultat est n multiplié par la factorielle de (n − 1). D’où l’algorithme suivant :

Fonction factorielle (n en entier) en entier


Si n = 0 alors
Retourner 1
Sinon
Retourner n× factorielle(n − 1)
Fin Fonction factorielle

La fonction factorielle() prend un paramètre n de type entier et renvoie également un entier. Elle
utilise une structure conditionnelle pour déterminer si n est égal à zéro. Si c’est le cas, cela signifie
que nous atteignons le cas de base ou le cas de terminaison, car la factorielle de zéro est défini comme
égal à 1, en d’autres termes, la chaîne de récursivité est rompu. Sans sa présence, l’algorithme ne peut
pas se terminer.

Lorsque n n’est pas égal à zéro, cela indique que nous sommes dans le cas général ou le cas de
propagation. Dans ce cas, nous devons effectuer le calcul récursif. La fonction renvoie le résultat de la
multiplication de n par l’appel récursif de la fonction factorielle() avec le paramètre n − 1. Cette
approche permet de réduire le problème initial en un problème plus petit en calculant récursivement
la factorielle de n − 1 jusqu’à atteindre le cas de base.

En résumé, une fonction récursive est définie par un ou plusieurs cas de base, où la fonction produit
un résultat direct sans se répéter, ainsi que par un ou plusieurs cas de propagation, où la fonction
s’appelle elle-même pour résoudre un problème plus petit. Cependant, aucun de ces cas ne constitue
une définition complète en soi. Par conséquent, la conception d’algorithme d’une fonction récursive
nécessite de spécifier à la fois les cas de base et les cas de propagation pour définir complètement son
comportement.

Considérons une autre illustration : l’Algorithme d’Euclide, l’un des plus anciens algorithmes
connus (Knuth, 1997b), est décrit dans le livre VII (Proposition 1-3) des Éléments d’Euclide, écrit
vers 300 av. J.-C. et présenté sous forme d’anthyphérèse (Euclide, 1994).

Exemple 2.13 (Algorithme d’Euclide). Une formulation courante de cet algorithme, présentée dans
l’ouvrage de Cormen et al. (2004), est la suivante : le PGCD (Plus Grand Commun Diviseur) de deux

80
entiers a et b peut être calculé en utilisant la relation pgcd(a, b) = pgcd(b, r), où r est le reste de la
division euclidienne de a par b, c’est-à-dire r = a mod b.
Ainsi, l’algorithme d’Euclide peut être réécrit de la manière suivante :
• Si b = 0, l’algorithme se termine et renvoie la valeur a : c’est le cas de base.
• Sinon, l’algorithme calcule le reste r de la division euclidienne de a par b, puis répète le processus
en remplaçant a par b et b par r (c’est-à-dire a ← b et b ← r). On applique ensuite la relation
pgcd(a, b) = pgcd(b, r) : c’est le cas de propagation.

Fonction pgcd(a, b en entiers) en entier


Si b = 0 alors
Retourner a
Sinon
Retourner pgcd(b, a mod b)
Fin Fonction pgcd

2.8 Fonctions anonymes


Définition 2.4. Une fonction anonyme, également appelée fonction littérale, abstraction lambda, fonc-
tion lambda, lambda expression, bloc lambda ou fonction jetable (Davies, 2016) est une définition de
fonction qui n’est pas liée à un identifiant.

Les fonctions anonymes trouvent leur origine dans le calcul lambda, un système mathématique
développé par Alonzo Church en 1936 (Fernandez, 2009). Dans ce système, toutes les fonctions sont
anonymes, ce qui signifie qu’elles n’ont pas de noms explicites qui leur sont attribués. Alonzo Church,
mathématicien, informaticien, logicien et philosophe américain, a introduit le concept de fonctions
anonymes dans le cadre de ses travaux novateurs dans le domaine de la théorie de la calculabilité,
antérieurement à l’avènement des ordinateurs électroniques.

D’ailleurs, les termes «abstraction lambda», «fonction lambda» et «expression lambda» font ré-
férence à la notation de l’abstraction de fonction dans le calcul lambda, où la fonction habituelle
f (x) = M serait écrite (λx.M ) (M est une expression qui utilise x).

La déclaration d’une fonction anonyme se fait de la manière suivante :

f_anonyme ← Fonction (par1 en type_par1, ... , parn en type_parn) en type_fonction :


Retourner Expression
Fin Fonction

Où Expression représente l’expression, c’est-à-dire la valeur ou le calcul, dont le résultat doit être
renvoyé.

Exemple 2.14.

f ← Fonction (x en réel) en réel :


Retourner x2
Fin Fonction

Par souci de simplicité d’écriture, nous pouvons écrire le format général des fonctions anonymes comme
suit :

81
f_anonyme ← Fonction (par1 en type_par1, ... , parn en type_parn) en type_fonction :
Expression

Exemple 2.15. La fonction anonyme de l’exemple 2.14 peut être réécrite de manière simplifiée comme
suit :

f ← Fonction (x en réel) en réel : x2

L’utilisation de fonctions anonymes relève d’une question de style. Ce n’est jamais la seule solution
pour résoudre un problème, car chaque fonction anonyme pourrait à la place être définie comme une
fonction nommée et appelée par son nom.

Dans le cadre de ce document, nous n’utiliserons que des fonctions anonymes pour effectuer du
curryings.

Cependant, il est important de noter que les fonctions anonymes sont limitées en termes de com-
plexité et de fonctionnalités. Elles sont généralement utilisées pour des opérations simples et ne sont
pas destinées à remplacer les fonctions définies par le nom lorsque des fonctionnalités avancées sont
requises.

Les fonctions anonymes peuvent être utilisées pour contenir des fonctionnalités qui n’ont pas besoin
d’être nommées et éventuellement pour une utilisation à court terme. Des exemples notables sont les
curryings 2 .

Définition 2.5 (Currying). Le currying est une technique qui consiste à transformer une fonction à
plusieurs paramètres en une séquence de fonctions qui prennent, chacune un seul paramètre.

Exemple 2.16. Soit la fonction permettant de calculer la somme de trois nombres réels suivant :

Fonction somme(x, y, z en réel) en réel


Retourner x + y + z
Fin Fonction somme

En utilisant le currying, le programme peut se réécrire de la manière suivante :

Fonction somme_c (x en réel) en réel


Retourner Fonction (y en réel) en réel :
Retourner Fonction (z en réel) en réel :
x+y+z
Fin Fonction
Fin Fonction
2. Le terme «currying» est un concept utilisé par le logicien et mathématicien Haskell B. Curry (1980), bien
que Moses Schönfinkel l’ait développé six ans auparavant. Il est également connu sous le nom de «Schönfin-
kelisation» (Heim and Kratzer, 1998). L’origine précise du terme n’est pas claire, mais il est mentionné que
Christopher Strachey l’a peut-être inventé dans ses notes de cours de 1967 (Turner, 1997). Cependant, le mot
lui-même n’apparaît pas dans ces notes. John C. Reynolds (1972) a ensuite défini le Currying dans un article,
sans revendiquer l’invention du terme. Le principe du currying remonte également aux travaux mathématiques
de Frege en 1893 (Quine, 1967; Turner, 1997)

82
Fin Fonction somme_c

La fonction somme_c() prend un paramètre x de type réel et retourne une fonction anonyme prenant
un paramètre y de type réel. Cette fonction anonyme renvoie à son tour une autre fonction anonyme
prenant un paramètre z de type réel. A l’intérieur de cette dernière fonction anonyme, la somme
x + y + z est calculée et retournée.

L’idée principale est que chaque appel de la fonction somme_c() avec un paramètre x retourne une
fonction qui prendra le paramètre suivant (y), puis cette fonction retournera une autre fonction qui
prendra le dernier paramètre (z) et calculera la somme finale.

L’algorithme principal accepte donc les appels suivants :

#L’algorithme principal
Début
# Appel des paramètres un par un
etape1 = somme_c(5)
etape2 = etape1(-3)
resultat = etape2(5.0)
Afficher resultat
Fin

La fonction somme_c() prend un paramètre x de type réel et retourne une fonction anonyme prenant
un paramètre y de type réel. Cette fonction anonyme à son tour retourne une autre fonction anonyme
prenant un paramètre z de type réel. À l’intérieur de cette dernière fonction anonyme, la somme
x + y + z est calculée et renvoyée. L’idée principale est que chaque appel de la fonction somme_c() avec
un paramètre x renvoie une fonction qui prendra l’paramètre suivant (y), puis cette fonction renverra
une autre fonction qui prendra le dernier paramètre (z) et calculera la somme finale.

Ce programme principal peut s’expliquer comme suit :


• Nous utilisons la première étape etape1 = somme_c(5) pour créer une nouvelle fonction etape1
en lui passant l’argument 5. Cette fonction etape1 correspond à la première étape du currying,
où x est fixé à 5 et nous attendons l’argument y.
• Ensuite, nous utilisons la deuxième étape etape2 = etape1(-3) pour créer une nouvelle fonc-
tion etape2 en lui passant l’argument −3. Cette fonction etape2 correspond à la deuxième
étape du currying, où y est fixé à −3 et nous attendons l’argument z.
• Enfin, nous utilisons la dernière étape resultat = etape2(5.0) pour appeler la fonction etape2
avec l’argument 5.0. Cela calcule la somme de x (qui est 5), y (qui est −3) et z (qui est 5.0) et
stocke le résultat dans la variable resultat.
• A l’affichage de la valeur de resultat, le programme va faire apparaitre 7.0.

L’algorithme principal accepte donc les appels suivants :

#L’algorithme principal
Début
# Appel de la séquence de paramètres a la fois
somme_c(5)(-3)(5.0)
Fin

83
Voici comment s’explique le programme principal précédent :

• somme_c(5) correspond à l’appel initial de la fonction somme_c(5) d’argument x égal à 5. Cette


fonction prend un paramètre y et retourne une autre fonction anonyme
Fonction (z en réel) en réel : 5 + y + z
• somme_c(5)(-3)=(somme_c(5))(-3) correspond à l’appel de la fonction anonyme retournée à
l’étape précédente avec l’argument y égal à −3. Cela retourne une deuxième fonction anonyme
Fonction (z en réel) en réel : 5 + (−3) + z.
Cette fonction prend un paramètre z et retourne la somme de 5, -3 et z.
• somme_c(5)(-3)(5.0) =((somme_c(5))(-3))(5.0) correspond à l’appel de la deuxième fonc-
tion anonyme retournée à l’étape précédente avec l’argument z égal à 5.0. Cette dernière fonction
effectue la somme des trois nombres x, y et z (5 + (−3) + 5.0) et renvoie le résultat.

3 Procédures et fonctions en Python


3.1 Notion de procédure et de fonction en Python
En Python, le terme «fonction» est utilisé pour englober à la fois les fonctions strictes (qui re-
tournent une valeur) et les procédures (qui n’en retournent pas). Python utilise la même instruction
def pour définir les deux types. Voici la syntaxe générale pour définir une fonction en Python :
def nom_fonction ( par1 , par2 , ... , parn ) :
# Declaration des variables locales
variable1 : valeur_variable1
variable2 : valeur_variable2
# ...
variablen : valeur_variablen

# Corps de la routine
# Suites d ’ instructions
# ...

# Optionnellement , un retour de valeur avec l ’ instruction ( s ’


agissant d ’ une procedure ou une fonction stricte )

return val eu r_ a_ re to ur ne r

Avec :
• def nom_fonction(par1, par2 ..., parn) : est la déclaration de la fonction, où l’on doit
spécifier le nom de la fonction, les paramètres avec leurs types et le type de valeur de retour.
• Suites d’instructions : est l’endroit où sera écrit le code qui sera exécuté lorsque la fonction
est appelée.
• return valeur_a_retourner : est l’instruction return qui retourne la valeur spécifiée comme
résultat de la routine.
Il est possible de choisir n’importe quel identificateur pour nommer une routine en Python, à
condition de ne pas utiliser les mots réservés du langage (voir le papier de Kamingu (2022)). De plus,
il est recommandé de n’utiliser aucun caractère spécial ou accentué (à l’exception du caractère souligné
«_»), et d’adopter le style de casse snake_case, tout comme pour les noms de variables en Python.

84
3.2 Procédures sans paramètre en Python
En Python, il est possible de créer une procédure sans paramètre. Cela peut être illustré avec
l’exemple suivant :
Exemple 3.1.

In [14]: def salutation () :


print ( " Salut ! " )

Il est important de noter que, tout comme pour les boucles et les conditions, l’indentation du corps
d’une procédure est obligatoire.

Si nous appelons ultérieurement la procédure salutation() dans le script, le message Salut! sera
affiché.

Cependant, l’introduction d’un paramètre dans la procédure entraîne une erreur, comme le montre
l’exemple suivant :
Exemple 3.2.

In [17]: salutation ( " Salut ! " )


------------------------------------------------------------
TypeError Traceback ( most recent call last )
< ipython - input -4 -873 f4b694044 > in < module >
----> 1 salutation ( " Salut ! " )

TypeError : salutation () takes 0 positional arguments but 1


was given

De manière similaire à la section précédente, nous pouvons modifier le programme pour inclure le
prénom de l’utilisateur.
Exemple 3.3.

In [20]: # La procedure
def salutation () :
prenom = input ( " Entrer votre prenom : " )
print ( " Salut " , prenom , " ! " )
...

In [28]: # L ’ appel de la procedure


salutation ()

Entrer votre prenom : Pierre


Salut Pierre !

3.3 Procédures avec paramètres en Python


Les paramètres sont utilisés de la même manière que dans l’algorithme. Si la procédure comporte
plusieurs paramètres, les arguments doivent être fournis dans l’ordre correspondant lors de l’appel de
la procédure, en les séparant également par des virgules.

La version de l’exemple 3.3 avec un paramètre peut être écrite comme suit :

85
Exemple 3.4.

In [29]: # La procedure
def salutation ( prenom ) :
print ( " Salut " , prenom , " ! " )
...

In [32]: # L ’ appel de la procedure


print ( " Entrer votre prenom : " )
votre_prenom = input ()
salutation ( votre_prenom )

Reprenons l’exemple de l’écriture d’un programme affichant un fragment de la table de multiplication


que nous avons mentionné précédemment (exemple 2.4). Voici le script correspondant :
Exemple 3.5 (Table de multiplication en Python).

In [1]: def tableMulti ( base , depart , fin ) :


print ( " Fragment de la table de multiplication par " , base , " : " )
print ( " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " )

n = depart
while n <= fin :
print (n , " x " , base , " = " , n * base )
n += 1

In [2]: tableMulti (4 , 1 , 12)

Après avoir appelé la procédure tableMulti(4, 1, 12), le résultat obtenu est le suivant :

Fragment de la table de multiplication par 4 :


----------------------------------------------------
1 x 4 = 4
2 x 4 = 8
3 x 4 = 12
4 x 4 = 16
5 x 4 = 20
6 x 4 = 24
7 x 4 = 28
8 x 4 = 32
9 x 4 = 36
10 x 4 = 40
11 x 4 = 44
12 x 4 = 48

Remarque 3.1. Dans le script de l’exemple 3.5, nous avons utilisé l’instruction d’affectation n += 1
au lieu de n = n+1. Cela est dû au fait que la notation += est un opérateur d’assignation combinée
en Python. Il permet de mettre à jour la valeur d’une variable en ajoutant une autre valeur à celle
existante et de stocker le résultat dans la même variable. Ainsi, l’expression x += y est équivalente à
x = x + y, où x et y peuvent être des variables ou des expressions, et Opt représente une opération
d’arithmétique telle que Opt ∈ {+, -, *, /, %}.

86
3.4 Fonctions en Python
Comme indiqué précédemment, les fonctions en Python sont similaires aux procédures, à la diffé-
rence qu’elles doivent obligatoirement renvoyer une valeur.

Exemple 3.6. La fonction suivante peut permettre de calculer la somme de deux nombres :

In [42] def somme ( nbr_1 , nbr_2 ) :


som = nbr_1 + nbr_2
return som

3.5 Paramètres de routine en Python


3.5.1 Passages de paramètre en Python
En Python, les paramètres sont passés par référence. Cela signifie que lorsqu’un objet est passé
à une routine en tant que paramètre, la référence de cet objet est passée plutôt que sa valeur. Par
conséquent, toute modification apportée à l’objet à l’intérieur de la routine sera reflétée à l’extérieur
de celle-ci.

Cependant, il est important de noter que le comportement peut varier selon le type d’objet passé
en paramètre. Deux cas peuvent être distingués :

1. Les objets immuables (comme les variables (les entiers, les réels, les chaînes de caractères,
les tuples 3 ) sont passés par valeur. Cela signifie que lorsqu’un objet immuable est passé en
argument, une copie de sa valeur est créée dans la routine. Toute modification apportée à
l’objet à l’intérieur de la routine n’affectera pas l’objet d’origine en dehors de la routine.

Exemple 3.7.

In [43]: # La fonction incrementer


def incrementer ( valeur ) :
valeur += 1

In [44]: # Le programme principal


x = 5
incrementer ( x )
print ( x ) # Affiche 5 , la valeur de x n ’a pas ete
modifiee .

2. Les objets mutables 4 (comme les listes, les dictionnaires) sont passés par référence. Cela signifie
que lorsqu’un objet modifiable en tant que paramètre est passé en tant qu’argument, les modi-
fications apportées à cet objet à l’intérieur de la routine seront reflétées dans l’objet d’origine
en dehors de la routine.

Il est important de comprendre ces différences lors de la manipulation de paramètres dans une
routine Python, car cela peut avoir un impact sur le comportement du code.
3. Ce type d’objets sera traité dans le volume 001, numéro 004
4. Ces types d’objets seront également traités dans le volume 001, numéro 004

87
Une particularité des routines en Python est qu’il n’est pas nécessaire de spécifier le type des
paramètres passés, tant que les opérations effectuées avec ces arguments sont valides. Python est en
effet connu comme un langage «typé dynamiquement», c’est-à-dire qu’il reconnaît pour vous le type
des variables à l’exécution.

Exemple 3.8.

In [45]: def fois (x , y ) :


return x * y

In [46]: fois (2 , 3)
Out [46]: 6

In [47]: fois (3.1415 , 5.23)


Out [47]: 16 .4 30 04 50 00 00 000 3

In [48]: fois ( " pa " , 2)


Out [48]: ’ papa ’

L’opérateur * en Python est capable de traiter différents types de données tels que les entiers, les
nombres à virgule flottante, les chaînes de caractères et les listes. Cela signifie que notre fonction
fois() peut effectuer différentes tâches en fonction des types des arguments fournis. Cependant, il est
important d’être conscient de cette grande flexibilité offerte par Python, car cela peut parfois entraîner
des résultats inattendus dans vos programmes.

Il est généralement préférable que chaque argument ait un type spécifique et clairement défini,
plutôt que de permettre différents types d’entrées. Par exemple, il est plus clair et moins propice aux
erreurs de conception si nous définissons que la fonction fois() ne fonctionne qu’avec des entiers,
des nombres à virgule flottante ou des chaînes de caractères spécifiquement. Cela permet de garantir
des résultats cohérents et d’éviter les comportements indésirables. Il est donc recommandé de faire
attention à la flexibilité offerte par Python et de spécifier les types d’arguments attendus dans vos
fonctions, afin d’éviter des problèmes potentiels et de rendre votre code plus robuste et prévisible.

La fonction fois() peut ainsi être modifié de manière à ce que x et y puissent recevoir au moins
un paramètre numérique.

Exemple 3.9.

In [50]: def fois (x , y ) :


if isinstance (x , ( int , float ) ) or isinstance (y , ( int ,
float ) ) :
return x * y
else :
raise TypeError ( " Au moins l ’ un des arguments doit etre
numerique . " )

In [51]: # Exemples d ’ appels a la fonction fois ()


Out [51]: print ( fois (2 , 3) )
6

In [52]: print ( fois (3.1415 , 5.23) )

88
16 .4 30 04 50 00 00 00 03

In [53]: print ( fois ( " pa " , 2) )


’ papa ’

In [54]: print ( fois ( " pa " , " pa " ) )


------------------------------------------------------
TypeError Traceback ( most recent call last )
< ipython - input -15 -07 de78aeb39f > in < module >
----> 1 fois ( " pa " , " pa " )

< ipython - input -13 - f37b48f62162 > in fois (x , y )


3 return x * y
4 else :
----> 5 raise TypeError ( " Au moins l ’ un des arguments
doit etre numerique . " )

TypeError : Au moins l ’ un des arguments doit etre numerique .

Dans cette version, nous utilisons la fonction isinstance() pour vérifier si x est un entier ou un
nombre à virgule flottante, ou si y est un entier ou un nombre à virgule flottante. En effet, la fonction
isinstance() renvoie True si l’objet spécifié est du type spécifié, sinon elle renvoie False. Dans notre
cas, si au moins un des deux paramètres est numérique, la fonction effectue la multiplication x * y et
renvoie le résultat. Sinon, une exception de type TypeError est levée pour indiquer qu’au moins un des
paramètres doit être numérique. Avec ce changement, la fonction times() acceptera les paramètres
numériques et n’effectuera la multiplication que si au moins un des paramètres est numérique.

3.5.2 Arguments par défaut en Python


Dans la définition d’une routine, il est possible (et souvent souhatable) (Swinnen, 2012) de définir
un argument par défaut pour chacun des paramètres. On obtient ainsi une routine qui peut être ap-
pelée avec seulement une partie des arguments attendus.

Revenons à l’exemple 3.3. Nous pouvons personnaliser la salutation comme dans l’exemple suivant :

Exemple 3.10.

In [65]: def salutation ( prenom , message = " Salut " ) :


print ( message , prenom , " ! " )

In [66]: salutation ( " Paul " )


Salut Paul !

In [67]: salutation ( " Paul " , " Bonjour " )


Bonjour Paul !

Il est important de placer les paramètres sans valeur par défaut avant les paramètres avec des valeurs
par défaut dans la définition d’une routine en Python. Cela est dû au mécanisme d’association des
arguments aux paramètres lors de l’appel de la routine. Python associe les arguments aux paramètres
dans l’ordre où ils sont définis dans la définition de la routine. En plaçant d’abord les paramètres sans
valeur par défaut, Python peut les associer aux premiers arguments fournis lors de l’appel. Ensuite,

89
les paramètres avec des valeurs par défaut peuvent être associés aux arguments restants, s’ils sont
fournis. Cette approche assure une correspondance cohérente entre les arguments et les paramètres,
ce qui facilite la compréhension et l’utilisation de la routine.

Ci-après un exemple pour illustrer l’importance de l’ordre des paramètres :

def exemple(parametre1, parametre2 = “valeur par defaut”, parametre3)

Dans cet exemple, si nous définissons le paramètre parameter2 avec une valeur par défaut avant
parameter1, cela provoquera une erreur de syntaxe. Python ne saura pas comment faire correspondre
les arguments fournis lors de l’appel de la routine aux paramètres correspondants. En respectant l’ordre
des paramètres sans valeur par défaut avant les paramètres avec valeurs par défaut, l’association entre
les arguments et les paramètres se fait correctement lors de l’appel de la routine. Il assure également
la cohérence et la prévisibilité du comportement de routine.

3.5.3 Arguments avec étiquettes en Python


Dans la plupart des langages de programmation, il est généralement nécessaire de fournir les ar-
guments dans le même ordre que les paramètres correspondants dans la définition d’une routine.
Cependant, Python offre une plus grande flexibilité à cet égard. Lorsque les paramètres de la routine
sont dotés de valeurs par défaut, on peut appeler la routine en fournissant les arguments dans n’im-
porte quel ordre, à condition de spécifier explicitement les noms des paramètres correspondants.

Reprenons l’exemple de l’écriture d’un programme affichant un fragment de la table de multiplica-


tion que nous avons mentionné précédemment. Nous pouvons le modifier de la manière de la manière
suivante :

Exemple 3.11 (Table de multiplication en Python).

In [1]: def tableMulti ( base = 4 , depart = 1 , fin = 12) :


print ( " Fragment de la table de multiplication par " , base , " : " )
print ( " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " )

n = depart
while n <= fin :
print (n , " x " , base , " = " , n * base )
n += 1

In [2]: tableMulti ( depart =3 , fin =14 , base =5)

Après avoir appelé la procédure tableMulti(depart=3, fin=14, base=5), le résultat obtenu est le
suivant :

Fragment de la table de multiplication par 5 :


----------------------------------------------------
3 x 5 = 15
4 x 5 = 20
5 x 5 = 25
6 x 5 = 30
7 x 5 = 35
8 x 5 = 40

90
9 x 5 = 45
10 x 5 = 50
11 x 5 = 55
12 x 5 = 60
13 x 5 = 65
14 x 5 = 70
En utilisant les noms des paramètres, nous pouvons spécifier les arguments dans n’importe quel
ordre, ce qui offre une plus grande flexibilité lors de l’appel de la routine.

3.6 Portée d’une variable en Python


Ci-après l’exemple de la variable à portée globale :
Exemple 3.12 (Variable globale en Python).

In [25]: # Declaration d ’ une variable globale


x = 5

In [26]: # La procedure avec une variable locale


def additionner () :
# Declaration d ’ une variable locale
y = 12
print ( x + y ) # Acces a la variable globale et a la
variable locale

In [27]: # Appel de la procedure


additionner ()

Ci-après l’exemple de la variable à portée locale :


Exemple 3.13 (Variable globale en Python).

In [28]: # Declaration d ’ une variable globale


x = 4

In [29]: # La procedure avec une variable locale du meme nom


def affichage () :
# Declaration d ’ une variable locale du meme nom
x = 12
print ( x ) # Acces a la variable locale

In [30]: # Appel de la procedure


affichage ()
12

In [31]: print ( x ) # Acces a la variable globale


Out [31]: 4

Remarque 3.2. En Python, il est possible de définir une routine capable de modifier une variable
globale en utilisant l’instruction global. Cette instruction est utilisée à l’intérieur de la définition
de la routine pour indiquer quelles variables doivent être traitées comme des variables globales. Cela
permet d’accéder à ces variables globales et de les modifier à l’intérieur de la routine.

91
Exemple 3.14 (Exemple d’utilisation de l’instruction global).

In [35]: # Declaration d ’ une variable globale


x = 4

In [36]: # La fonction avec une variable locale du meme nom


def affichage () :
global x # Declaration de la variable globale
x = 12 # Modification de la variable globale
print ( x ) # Affiche la variable globale modifiee

In [37]: # Appel de la fonction


affichage ()
12

In [38]: print ( x ) # Affiche la variable globale modifiee


Out [38]: 12
Dans l’exemple précédent, nous voulons utiliser la variable globale x plutôt que de créer une
nouvelle variable locale du même nom. Ainsi, lorsque nous modifions la valeur de x à l’intérieur de la
fonction en utilisant x = 12, nous modifions la variable globale elle-même. Lorsque nous affichons x à
la fin, nous pouvons voir que la variable globale a été modifiée et que la valeur est maintenant 12.

3.7 Fonctions récursives en Python


L’utilisation de la récursion est permise en Python. D’où les fonction factorielle() et de l’algo-
rithme d’Euclide (la fonction pgcd()).

Exemple 3.15 (Fonction factorielle()).

In [1]: def factorielle ( n ) :


if n == 0:
return 1
else :
return n * factorielle ( n - 1)

In [2]: # Utilisation de la fonction factorielle ()


factorielle (10)
Out [2]: 3628800

Exemple 3.16 (Fonction de l’Algorithme d’Euclide).

In [3]: def pgcd (a , b ) :


if b == 0:
return a
else :
return pgcd (b , a % b )

In [4]: # Utilisation de la fonction pgdc ()


pgcd (245 , 3500)
Out [4]: 35

92
3.8 Fonctions anonymes en Python
En Python, les fonctions anonymes sont créées à l’aide du mot-clé lambda, suivi des paramètres
de la fonction et d’une expression.
lambda arguments : expression

Exemple 3.17 (Exemple simple d’une fonction anonyme en Python).

In [450]: f = lambda x : 2* x **2+4

In [451]: f (5)
Out [451]: 54

Exemple 3.18 (Currying en Python).

In [454]: def somme_c ( x ) :


def fonction ( y ) :
def fonction_interne ( z ) :
return x + y + z
return fonction_interne
return fonction

In [455]: somme_c (5) ( -3) (5.0)


Out [454]: 7.0

4 Procédures et fonctions en R
4.1 Notion de procédure et de fonction en R
Comme dans le langage Python, le terme fonction est utilisé pour désigner des fonctions strictes
(qui renvoient une valeur) et des procédures (qui ne le font pas). Cependant, pour définir une fonction
ou une procédure, R utilise la même instruction function pour définir les deux types. Voici la syntaxe
générale pour définir une fonction en Python :
nom_fonction <- function ( par1 , par2 , ... , parn ) {
# Declaration des variables locales
variable1 <- valeur_variable1
variable2 <- valeur_variable2
# ...
variablen <- valeur_variablen

# Corps de la fonction
# Suites d ’ instructions
# ...

# Optionnellement , un retour de valeur avec l ’ instruction ( s ’


agissant d ’ une procedure ou une fonction stricte )

return ( val eu r_ a_ re to ur ne r )
}

93
Avec :
• nom_fonction <- _fonction(par1, par2 ..., parn) : est la déclaration de la fonction, où
l’on doit spécifier le nom de la fonction, les paramètres avec leurs types et le type de valeur de
retour.
• Suites d’instructions : est l’endroit où sera écrit le code qui sera exécuté lorsque la fonction
est appelée.
• return valeur_a_retourner : est l’instruction return qui retourne la valeur spécifiée comme
résultat de la fonction.
Il est possible de choisir n’importe quel identificateur pour nommer une fonction en R, à condition
de ne pas utiliser les mots réservés du langage (voir Kamingu (2022)). De plus, il est recommandé de
n’utiliser aucun caractère spécial ou accentué, et d’adopter le style de casse camelCase, tout comme
pour les noms de variables en R.

4.2 Procédures sans paramètre en R


En R, il est possible de créer une procédure sans paramètre. Cela peut être illustré avec l’exemple
suivant :
Exemple 4.1.

salutation <- function () {


print ( " Salut ! " )
}
Lorsque la procédure est appelé, nous obtenons :
> salutation ()
[1] " Salut ! "

Il est important de noter qu’en R, tout comme pour les boucles et les conditions, l’indentation du
corps d’une fonction ou d’une procédure est facultative du fait de l’utilisation des accolades.

Si nous appelons ultérieurement la fonction ou la procédure salutation() dans le script, le mes-


sage Salut! sera affiché.

Cependant, si nous introduisons un paramètre dans la fonction ou la procédure, cela peut entraîner
une erreur, comme le montre l’exemple suivant :
Exemple 4.2.

> salutation ( " Salut ! " )


Error in salutation ( " Salut ! " ) : unused argument ( " Salut ! " )

Le programme précédent peut être modifié pour inclure le prénom de l’utilisateur.


Exemple 4.3.

# La procedure
salutation <- function () {
prenom <- readline ( prompt = " Entrer votre prenom : " )
print ( paste ( " Salut " , prenom , " ! " ) )
}

94
Lorsque la procédure est appelée, nous obtenons le résultat suivant :
> salutation ()
Entrer votre prenom : Gradi
[1] " Salut Gradi ! "

4.3 Procédures avec paramètres en R


Dans le langage R, lors de l’appel d’une procédure avec plusieurs paramètres, il est important de
fournir les arguments dans l’ordre correspondant aux paramètres. Les paramètres sont utilisés de la
même manière que dans l’algorithme, et les arguments doivent être séparés par des virgules.

La version de l’exemple 4.3 avec un paramètre peut être écrite comme suit :

Exemple 4.4.

# La procedure
salutation <- function ( prenom ) {
print ( paste ( " Salut " , prenom , " ! " ) )
}

Lorsque la procédure est appelée, nous obtenons le résultat suivant :


> # L ’ appel de la procedure
> votrePrenom <- readline ( " Entrer votre prenom : " )
Entrer votre prenom : Gradi
> salutation ( votrePrenom )
[1] " Salut Gradi ! "

Voici le script correspondant à l’exemple précédent où nous avons écrit un programme pour afficher
un fragment de la table de multiplication (exemple 2.4).

Exemple 4.5 (Table de multiplication en R).

tableMulti <- function ( base , depart , fin ) {


print ( paste ( " Fragment de la table de multiplication par " , base , " : " )
)
print ( " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " )

n <- depart
while ( n <= fin ) {
print ( paste (n , " x " , base , " = " , n * base ) )
n <- n + 1
}
}

Après avoir appelé la procédure tableMulti(4, 1, 12), le résultat obtenu est le suivant :

95
> tableMulti (4 , 1 , 12)
[1] " Fragment de la table de multiplication par 4 : "
[1] " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "
[1] " 1 x 4 = 4 "
[1] " 2 x 4 = 8 "
[1] " 3 x 4 = 12 "
[1] " 4 x 4 = 16 "
[1] " 5 x 4 = 20 "
[1] " 6 x 4 = 24 "
[1] " 7 x 4 = 28 "
[1] " 8 x 4 = 32 "
[1] " 9 x 4 = 36 "
[1] " 10 x 4 = 40 "
[1] " 11 x 4 = 44 "
[1] " 12 x 4 = 48 "

4.4 Fonctions
En langage R, les fonctions sont structurées de la même manière que les procédures, mais elles
diffèrent dans leur capacité à renvoyer une seule valeur. Ceci peut être illustré par l’exemple suivant,
permettant de calculer la somme de deux nombres :

Exemple 4.6.

somme <- function ( nbr_1 , nbr_2 ) {


som <- nbr_1 + nbr_2
return ( som )
}

4.5 Paramètres de routine en R


4.5.1 Passages de paramètre en R
En R, les paramètres sont passés par valeur. Cela signifie que lorsqu’un objet est passé à une
routine en tant que paramètre, une copie de la valeur de l’objet est créée et transmise à la routine.
Ainsi, toute modification apportée à l’objet à l’intérieur de la routine n’affectera pas l’objet d’origine
à l’extérieur de la routine.

Exemple 4.7.

# La procedure incrementer
incrementer <- function ( valeur ) {
valeur <- valeur + 1
}

L’affectation d’une valeur dans la variable x et l’appel de la procédure incrementer, et l’affichage de


la variable produit le résultat suivant
> # Le programme principal
> x <- 5
> incrementer ( x )

96
> print ( x )
[1] 5

Cependant, il y a une exception pour les objets de type [Link] et matrix qui peuvent être
passés par référence. Cela signifie que lorsqu’un Dataframe ou une matrice est passé à une fonction en
tant que paramètre, les modifications apportées à l’objet à l’intérieur de la fonction seront reflétées à
l’extérieur de celle-ci. Cela est dû à la façon dont ces objets sont stockés en mémoire dans R.

4.5.2 Arguments par défaut en R


Dans la définition d’une routine en R, il est possible (et souvent souhaitable) de définir des valeurs
par défaut pour les paramètres. Cela permet d’appeler la routine avec seulement une partie des argu-
ments attendus.

Prenons l’exemple de la routine de salutation. Nous pouvons personnaliser le message de salutation


comme illustré ci-dessous :

Exemple 4.8.

salutation <- function ( prenom , message = " Salut " ) {


print ( paste ( message , prenom , " ! " ) )
}

L’utilisation de cette routine peut donner ce qui suit :


> salutation ( " Paul " )
[1] " Salut Paul ! "
> salutation ( " Paul " , " Bonjour " )
[1] " Bonjour Paul ! "

Il est important de noter que les paramètres sans valeur par défaut doivent être placés avant les para-
mètres avec des valeurs par défaut dans la définition de la routine en R. Cela est dû à la façon dont
les arguments sont associés aux paramètres lors de l’appel de la routine. En respectant cet ordre, les
premiers arguments fournis lors de l’appel sont associés aux paramètres correspondants. Ensuite, les
paramètres avec des valeurs par défaut sont associés aux arguments restants, s’ils sont fournis. Cette
approche assure une correspondance cohérente entre les arguments et les paramètres, ce qui facilite la
compréhension et l’utilisation de la routine.

Voici un exemple pour illustrer l’importance de l’ordre des paramètres :


exemple <- function ( parametre1 , parametre2 = " valeur par defaut " ,
parametre3 ) {
# Corps de la routine
}

# Appel de la routine avec des parametres


exemple ( parametre1 , parametre3 ) # Correct
exemple ( parametre1 , parametre2 , parametre3 ) # Correct

# Erreur de syntaxe si l ’ ordre des parametres est incorrect


exemple ( parametre2 , parametre1 , parametre3 ) # Erreur !

97
Dans cet exemple, si nous définissons le paramètre parametre2 avec une valeur par défaut avant
parametre1, cela provoquera une erreur de syntaxe. En respectant l’ordre des paramètres sans valeur
par défaut avant les paramètres avec des valeurs par défaut, l’association entre les arguments et les
paramètres se fait correctement lors de l’appel de la routine. Cela assure également la cohérence et la
prévisibilité du comportement de la routine.

4.5.3 Arguments avec étiquettes


En langage R, il est généralement nécessaire de fournir les arguments dans le même ordre que les
paramètres correspondants dans la définition d’une fonction. Cependant, R offre également la possi-
bilité de spécifier les arguments en utilisant leurs noms, ce qui permet de les fournir dans n’importe
quel ordre.

Reprenons l’exemple de la table de multiplication que nous avons mentionné précédemment et


adaptons-le en langage R :

Exemple 4.9 (Table de multiplication en R).

tableMulti <- function ( base = 4 , depart = 1 , fin = 12) {


print ( paste ( " Fragment de la table de multiplication par " , base , " : " )
)
print ( " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - " )

n <- depart
while ( n <= fin ) {
print ( paste (n , " x " , base , " = " , n * base ) )
n <- n + 1
}
}

Après avoir appelé la procédure tableMulti(depart=3, fin=14, base=5), le résultat obtenu est le
suivant :

> tableMulti ( depart =3 , fin =14 , base =5)


[1] " Fragment de la table de multiplication par 5 : "
[1] " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - "
[1] " 3 x 5 = 15 "
[1] " 4 x 5 = 20 "
[1] " 5 x 5 = 25 "
[1] " 6 x 5 = 30 "
[1] " 7 x 5 = 35 "
[1] " 8 x 5 = 40 "
[1] " 9 x 5 = 45 "
[1] " 10 x 5 = 50 "
[1] " 11 x 5 = 55 "
[1] " 12 x 5 = 60 "
[1] " 13 x 5 = 65 "
[1] " 14 x 5 = 70 "

98
4.6 Portée d’une variable
Ci-après l’exemple de la variable à portée globale :

Exemple 4.10 (Variable globale en R).

# Declaration d ’ une variable globale


x <- 5

# La fonction avec une variable locale


additionner <- function () {
# Declaration d ’ une variable locale
y <- 10
print ( x + y ) # Acces a la variable globale et a la variable
locale
}

> additionner () # Appel de la fonction


[1] 15

Ci-après l’exemple de la variable à portée locale :

Exemple 4.11 (Variable globale en Python).

# Declaration d ’ une variable globale


x <- 4

# La fonction avec une variable locale du meme nom


affichage <- function () {
# Declaration d ’ une variable locale du meme nom
x <- 12
print ( x ) # Acces a la variable locale
}

> affichage () # Appel de la fonction


[1] 12
> print ( x ) # Acces a la variable globale
[1] 4

En R, il n’est pas possible de modifier directement une variable globale à l’intérieur d’une routine.
Cependant, il existe une approche alternative pour obtenir un effet similaire en utilisant une fonction
de retour.

Exemple 4.12 (Variable globale en Python).

# Declaration d ’ une variable globale


x <- 4

# La fonction avec une variable locale du meme nom


affichage <- function () {
x <<- 12 # Modification de la variable globale
print ( x ) # Affiche la variable globale modifiee
}

99
> affichage ()
[1] 12
> print ( x )
[1] 12

4.7 Fonctions récursives en R


R aussi autorise l’utilisation des fonctions récursives. Voici quelques exemples illustratifs :

Exemple 4.13 (Factorielle d’un nombre en R).

factorielle <- function ( n ) {


if ( n == 0) {
return (1)
} else {
return ( n * factorielle ( n - 1) )
}
}

Exemple 4.14 (Algorithme d’Euclide en R).

pgcd <- function (a , b ) {


if ( b == 0) {
return ( a )
} else {
return ( pgcd (b , a %% b ) )
}
}

4.8 Fonctions anonymes en R


En R, les fonctions anonymes sont créées à l’aide du mot-clé function, suivie des paramètres de
la fonction et du corps de la fonction entre accolades.
function ( arguments ) {
expression
}

Exemple 4.15 (Exemple simple d’une fonction anonyme en R).

f <- function ( x ) {
return (2* x ^2+4)
}

Le programme de l’exemple 4.15 peut s’écrire tout simplement de la manière suivante :


> f <- function ( x ) 2* x ^2+4

Voici ce que donne l’exécution de la fonction :


> f (5)
[1] 25

100
Exemple 4.16 (Currying en R).

sommeC <- function ( x ) {


fonction <- function ( y ) {
fonction_interne <- function ( z ) {
return ( x + y + z )
}
return ( fonction_interne )
}
return ( fonction )
}

> sommeC (5) ( -3) (5.0)


[1] 7

Voici ce que donne l’exécution de la fonction :


> f (5)
[1] 25

101
5 Comparaison entre Python et R en termes de routines
Ci-après un tableau comparatif des notions de procédure et fonction en Python et R :

Table 1 – Comparaisons des notions sur les fonctions et procédures en Python et en R.

Notion Python R
Définition
def nom_procedure ( nomProcedure <- function
parametres ) : ( parametres ) {
instructions instructions
}

Appel
nom_procedure ( arg1 , arg2 nomProcedure ( arg1 , arg2 )
)

Valeur de retour
return valeur return ( valeur )
Contrairement à Python, l’utili-
sation du mot-clé return n’est
pas nécessaire, car la valeur de
retour est déterminée par la der-
nière expression évaluée. Les pro-
cédures peuvent avoir un environ-
nement qui contient les variables
locales de la fonction.

Passage de para- Les arguments sont généralement Les paramètres sont générale-
mètres passés par référence. ment passés par valeur.

Variables locales
variable_locale = valeur variableLocale <- valeur

Variables globales
global variable_globale variableGlobale <<-
valeur

102
Table 2 – Comparaisons des notions sur les fonctions et procédures en Python et en R. (suite)

Notion Python R
Fonction anonyme
lambda arguments : function ( arguments ) {
expression expression
}

6 Conclusion
En conclusion, les procédures et les fonctions sont des éléments essentiels de la programmation
structurée, permettant de résoudre des problèmes en les divisant en tâches plus petites et réutilisables.
Tant Python que R offrent aux data scientists la capacité de programmer avec des procédures et des
fonctions de manière simple, ce qui facilite l’organisation et la réutilisation du code, améliorant ainsi
l’efficacité et la maintenance des projets.

Par ailleurs, Python et R offrent la possibilité de mettre en œuvre la programmation fonctionnelle,


un paradigme de programmation particulièrement bien adapté aux applications de la Data Science.
Ce paradigme offre des concepts puissants pour manipuler et analyser les données, ainsi que pour
développer des algorithmes sophistiqués.

Dans une publication ultérieure, nous aborderons également la manière de regrouper ces fonc-
tions et/ou procédures pour former des modules, offrant ainsi une approche encore plus structurée et
modulaire à la programmation.

103
Références
Cormen, T., Leiserson, C., Rivest, R., and Stein, C. (2004). Introduction à l’Algorithmique. Cours et
exercices. Dunod, Paris, 2ème éd. edition.

Curry, H. B. (1980). Some Philosophical Aspects of Combinatory Logic. Studies in Logic and the
Foundations of Mathematics, 101 :85–101.

Darmangeat, C. (2008). Algorithme et Programmation pour les non-matheux. Cours complet avec
exercices, corrigés et citations philosophiques. Université Paris 7.

Dasgupta, S. (2014). It Began with Babbage : The Genesis of Computer Science. Oxford University
Press, Oxford.

Davies, T. M. (2016). The Book of R - A First Course in Programming and Statistics. William
Pollock, San Francisco.

Euclide (1994). Les Éléments, volume vol. 2. Livres V à IX. Notes et commentaires par Bernard
Vitrac. PUF, Paris.

Fernandez, M. (2009). Models of Computation : An Introduction to Computability Theory. Undergra-


duate Topics in Computer Science. Springer Science & Business Media.

Heim, I. and Kratzer, A. (1998). Semantics in Generative Grammar. Blackwell.

Kamingu, G. L. (2022). Python vs. R pour Data Scientists : Structures algorithmiques. Série Optimall
Python vs. R pour Data Scientists, 001(003).

Knuth, D. E. (1997a). The Art of Computer Programming : Fondamental Algorithms, volume 1.


Addison-Wesley Longman Publishing Co., Inc., USA, 3rd edition.

Knuth, D. E. (1997b). The Art of Computer Programming : Seminumerical Algorithms, volume 2.


Addison-Wesley Longman Publishing Co., Inc., USA, 3rd edition.

Mauchly, J. W. (1982). Preparation of problems for EDVAC-type machines. In Randell, B., editor,
The Origins of Digital Computers, pages 393–397. Springer.

Quine, W. V. O. (1967). On the building blocks of mathematical logic. In van Heijenoort, J., edi-
tor, A Source Book in Mathematical Logic, 1879–1931, pages 355–366. Harvard University Press,
Cambridge, MA. Translated by Stefan Bauer-Mengelberg.

Reynolds, J. C. (1972). Definitional Interpreters for Higher-Order Programming Languages. In Pro-


ceedings of the ACM Annual Conference, volume 2, pages 717–740.

Swinnen, G. (2012). Apprendre à programmer avec Python 3. Eyrolles, Paris.

Turing, A. M. (1945). Report by Dr. A.M. Turing on proposals for the development of an Automatic
Computing Engine (ACE) : Submitted to the Executive Committee of the NPL in February 1946
reprinted in Copeland, B. J., ed. (2005). Alan Turing’s Automatic Computing Engine. Oxford
University Press, Oxford.

Turner, D. (1997). Programming language, Currying, or Schonfinkeling ? Consulté le 3 mars 2022.

Wheeler, D. J. (1952). The use of sub-routines in programmes. In Proceedings of the 1952 ACM
national meeting, page 235, Pittsburgh. ACM.

104
Wilkes, M. V., Wheeler, D. J., and Gill, S. (1951). Preparation of Programs for an Electronic Digital
Computer. Addison-Wesley.

Wirth, N. (1976). Algorithms + Data Structures = Programs. Prentice-Hall, New Jersey.

105

Vous aimerez peut-être aussi