Procédures Python et R pour Data Science
Procédures Python et R pour Data Science
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).
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é).
2.2 Procédures
La déclaration d’une procédure se fait de la manière suivante :
# 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 :
#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.
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 :
# 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 :
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
#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.
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.
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.
#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
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.
#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.
• 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.
#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.
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.
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 :
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.
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 :
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.
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).
Où Expression représente l’expression, c’est-à-dire la valeur ou le calcul, dont le résultat doit être
renvoyé.
Exemple 2.14.
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 :
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 :
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
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.
#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 :
# Corps de la routine
# Suites d ’ instructions
# ...
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.
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.
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 , " ! " )
...
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 , " ! " )
...
n = depart
while n <= fin :
print (n , " x " , base , " = " , n * base )
n += 1
Après avoir appelé la procédure tableMulti(4, 1, 12), le résultat obtenu est le suivant :
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 :
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.
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 [46]: fois (2 , 3)
Out [46]: 6
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.
88
16 .4 30 04 50 00 00 00 03
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.
Revenons à l’exemple 3.3. Nous pouvons personnaliser la salutation comme dans l’exemple suivant :
Exemple 3.10.
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.
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.
n = depart
while n <= fin :
print (n , " x " , base , " = " , n * base )
n += 1
Après avoir appelé la procédure tableMulti(depart=3, fin=14, base=5), le résultat obtenu est le
suivant :
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.
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).
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
In [451]: f (5)
Out [451]: 54
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
# ...
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.
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.
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.
# 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 ! "
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 , " ! " ) )
}
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).
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.
Exemple 4.7.
# La procedure incrementer
incrementer <- function ( valeur ) {
valeur <- valeur + 1
}
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.
Exemple 4.8.
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.
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.
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 :
98
4.6 Portée d’une variable
Ci-après l’exemple de la variable à portée globale :
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.
99
> affichage ()
[1] 12
> print ( x )
[1] 12
f <- function ( x ) {
return (2* x ^2+4)
}
100
Exemple 4.16 (Currying en R).
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 :
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.
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.
Kamingu, G. L. (2022). Python vs. R pour Data Scientists : Structures algorithmiques. Série Optimall
Python vs. R pour Data Scientists, 001(003).
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.
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.
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.
105