Aller au contenu

Définir une fonction personnelle

Nous pouvons définir des fonctions pour notre propre usage ou pour la communauté de programmeurs.

Fonctions sans paramètre ni valeur de retour

Supposons que je veuille écrire la même phrase à différents endroits d'un programme :

...
print("Vous trouverez plus d'informations en vous rendant sur notre site internet")
...
...
print("Vous trouverez plus d'informations en vous rendant sur notre site internet")
...

alors je peux remarquer deux problèmes :

  • c'est clairement une perte de temps de devoir retaper le même texte (oui, il y a le copier-coller) ;
  • si je veux améliorer mon texte, il faudra le faire partout où il apparaît (oui, il y a la fonction Remplacer...).

Bref, il serait préférable de se conformer à la philosophie DRY : "Don't Repeat Yourself".

Pour cela, nous allons définir une fonction avec le mot clé def :

def afficher_texte_site():
    print("Vous trouverez plus d'informations en vous rendant sur notre site internet")

Il ne nous reste plus qu'à appeler cette fonction là où c'est utile :

...
afficher_texte_site()
...
...
afficher_texte_site()
...

À vous : définissez puis appelez la fonction afficher_texte_site() :

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

À retenir

Définition : une fonction est un bloc d'instructions qui sont exécutées quand cette fonction est appelée.

Pour définir une fonction sans paramètre ni valeur de retour :

def ma_fonction():
    instruction_1
    instruction_2
    instruction_3
    ...
    dernière instruction

Remarquez :

  • le : indispensable à la fin de la ligne du def ;
  • que les instructions sont regroupées dans un bloc qui est délimité grâce à des tabulations (touche Tab ↹) ou par 4 espaces parfois, ce décalage vers la droite est appelé indentation ;
  • que ce bloc d’instructions n'est exécuté que si j'appelle ma fonction (en écrivant ma_fonction() plus loin dans le programme) ;
  • que notre fonction afficher_texte_site n'a pas de valeur de retour (essayez de taper type(afficher_texte_site())), elle ne renvoie rien : elle procède juste à un affichage ; une telle fonction est parfois appelée procédure. L'affichage du texte est un effet de bord.

Exercice

  • Sans utiliser de copier-coller, définissez une fonction nommée propagande et qui affiche le texte "Longue vie à notre cher président Tapioca".
    Utilisez ensuite cette fonction pour afficher 4 fois ce texte.

  • Modifiez la fonction afin de pouvoir afficher "Gloire à notre nouveau président Alcazar !"

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Appel d'une fonction

Exercice

  1. Observez et exécutez le script ci-dessous, que remarquez-vous ?
  2. Ajoutez l'appel aux deux fonctions à la fin du script.
  3. Placez ces appels au bon endroit.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Explication

Normalement, les instructions sont exécutées du haut vers le bas. Ici, l'introduction de fonctions semblent casser cet ordre mais retenez bien que tant qu'une fonction n'est pas appelée, ses instructions ne sont pas exécutées.

Exercice

  1. Tapez le script suivant :
    aff_texte()
    
    def aff_texte():
        print("La NSI c'est cool !")
    
  2. Exécutez-le puis corrigez l'erreur.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Explication

Vous l'aurez compris, l'erreur ne vient pas du texte mais du fait qu'une fonction ne peut pas être appelée avant d'être définie ! C'est un peu comme si vous parliez chinois à quelqu'un qui ne le parle pas !

Enfin, il est possible d'appeler une fonction dans une autre fonction, testez ceci par exemple :

def aff_texte():
    print("La NSI c'est cool !")

def trois_fois_texte():
    aff_texte()
    aff_texte()
    aff_texte()

trois_fois_texte()# appel de la fonction
###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Fonctions avec paramètre(s) mais sans valeur de retour (procédures)

Supposons maintenant que notre texte change un peu :

...
print("Plus d'informations à l'adresse http://site_bidon.com, onglet Actualités")
...
...
print("Plus d'informations à l'adresse http://www.autre_site_bidon.fr, onglet Conseils")
...

Là encore, évitons de nous répéter en définissant une fonction avec ici 2 paramètres :

def afficher_texte_site(adresse, onglet):
    print("Plus d'informations à l'adresse", adresse, ", onglet", onglet)

(observez bien la différence entre le mot "onglet" qui n'est que du texte et la variable onglet qui est un des paramètres).

Il ne nous reste plus qu'à appeler cette fonction ainsi :

...
afficher_texte_site("http://site_bidon.com", "Actualités")
...
...
afficher_texte_site("http://www.autre_site_bidon.fr", "Conseils")
...

À vous : redéfinissez puis appelez la fonction afficher_texte_site() :

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

À retenir

Pour définir une fonction avec paramètres mais sans valeur de retour :

def ma_fonction(param1, param2, ...):
    bloc dinstructions à exécuter dans la fonction
graph LR
%%{init: {'curve': 'basis'}}%%
val([valeur1])--> fonc[["ma_fonction(param1, param2, ...)"]]
val2([valeur2])--> fonc
val3([...])-.-> fonc
classDef params fill:#00BFFF,stroke:#333
classDef foncs fill:#f96,stroke:#333
classDef paramsfac fill:#00BFFF,stroke:#333,stroke-dasharray: 5, 5;
class fonc foncs
class val,val2 params
class val3 paramsfac
Plus d'explications
def ma_fonction(param1, param2, ..., paramN):
    instructions

se lit "je définis une fonction nommée ma_fonction ayant les paramètres param1, param2, ..., paramN qui va exécuter certaines instructions". Les valeurs des paramètres ne seront connues qu’à l’appel de la fonction. Il s'agit d'écrire quelque chose qui s'adapte aux valeurs des paramètres.

Exercice

Considérons les fonctions suivantes :

    def afficher_trois_dieses():
        print("###")

    def afficher_trois_etoiles():
        print("***")

    def afficher_trois_plus():
        print("+++")

Nous voyons qu'il y a ici une répétition, non pas de texte, mais de principe.

  • Écrivez une fonction afficher_trois qui aura un paramètre nommé symbole et qui permettra de remplacer les trois fonctions (et même plus).
  • Écrivez une fonction afficher_plusieurs qui aura deux paramètres nommés symbole et nb_fois et qui permettra d'afficher un nombre quelconque de fois un symbole.
  • Appelez cette fonction avec afficher_plusieurs("$", 10), afficher_plusieurs("$") et afficher_plusieurs(10, "$").

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Commentaire

Attention de bien respecter le nombre (et les types) des paramètres d'une fonction lors de l'appel de celle-ci !

Fonctions sans paramètre mais avec valeur(s) de retour

Bien souvent, une fonction renvoie des valeurs. Pour cela, il faut utiliser le mot-clé return.

Par exemple, si je veux stocker la date de l'armistice de 1945 :

def armistice_2eme_gm():
    return "8 mai 1945"

il ne me reste plus ensuite qu'à appeler cette fonction pour récupérer cette date importante :

armistice_2eme_gm()
Remarque

Bien sûr il serait ici plus pertinent de définir une constante plutôt qu'une fonction : ARMISTICE_2EME_GM = "8 mai 1945").

Copiez et exécutez les trois lignes de code précédent dans une console (n'oubliez pas l'indentation de 4 espaces pour la deuxième ligne) :

Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Faîtes maintenant la même chose dans un éditeur :

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Explications

Nous avons appelé notre fonction mais rien ne s'affiche !?

En fait cette fonction renvoie bien la valeur "8 mai 1945"... mais à qui ?

  • si nous faisons un simple appel comme ci-dessus, la fonction est exécutée, une valeur est renvoyée mais perdue (sauf si nous travaillons dans la console, où elle est affichée);
  • nous pouvons utiliser une variable pour récupérer cette valeur : arm = armistice_2eme_gm() ;
  • nous pouvons aussi vouloir que la valeur renvoyée soit affichée à l'écran : print(armistice_2eme_gm()) ;
  • nous pourrions enfin envoyer cette valeur à une autre fonction...

Attention

Ne confondez pas print et return. La première fonction ne fait qu'envoyer des valeurs vers l'affichage à l'écran, la seconde renvoie une ou des valeurs, qui pourront être stockées (dans une variable) et utilisées plus tard.

Je ne vois toujours pas la différence !

Par analogie, imaginez que vous jouiez à un jeu sur console et que vous dirigez le joystick vers le haut :

  • la manette détecte un mouvement mécanique et renvoie (return) à la console un code du genre "dir_haut" ;
  • une première fonction du programme de la console reçoit le code "dir_haut" et l'envoie (return) à d'autres fonctions :
    • une qui calcule si le personnage peut se déplacer dans cette direction, si oui celle-ci renvoie (return) alors les nouvelles coordonnées du personnage ;
    • une qui récupère ces coordonnées et s'occupe de déplacer/re-dessiner le personnage ;
    • une qui s'occupe de gérer les effets du mouvement : changement de score, mort du personnage, etc. et renvoie (return) ces informations.

Remarquez qu'il n'y a pas forcément d'affichage à l'écran de texte donc de print (heureusement, la console ne va pas vous dire toutes les opérations qu'elle effectue !!).

Au final, la commande return est bien plus utilisée et importante que print !

À retenir

Pour définir une fonction sans paramètre mais avec valeur(s) de retour :

def ma_fonction():
    instruction_1
    instruction_1
    ...
    dernière instruction

    return resultat1, resultat2, ...
graph LR
%%{init: {'curve': 'basis'}}%%
fonc[["fonc()"]] -->|return| res([resultat 1])
fonc --> res2([resultat 2])
fonc -.-> res3([...])
classDef foncs fill:#f96,stroke:#333
classDef results fill:#9f6,stroke:#333
classDef resfacs fill:#9f6,stroke:#333,stroke-dasharray: 5, 5
class fonc foncs
class res,res2 results
class res3 resfacs

Nous verrons plus tard que la commande return interrompt le déroulement d'une fonction et n'est pas forcément à la fin de celle-ci.

Une fonction ne renvoie qu'une valeur. Toujours !

En fait techniquement une fonction ne renvoie qu'une valeur. Par exemple :

def fonction_idiote():
    return 5, 2

nous voyons que deux valeurs sont renvoyées : 5 et 2. En vérité, la fonction renvoie le couple (5, 2) donc une valeur.

Essayez, pour le vérifier, d'entrer cela dans l'éditeur :

def fonction_idiote():
    return 5, 2
resultat = fonction_idiote()
print(resultat)

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Exercice

Essayez d'écrire une fonction moyenne_alea qui :

  • choisit trois nombres entiers compris entre 1 et 100 au hasard ;
  • calcule et renvoie leur moyenne.

Appelez ensuite cette fonction en affectant le résultat à une variable appelée moy.

Enfin affichez la valeur de moy.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Une réponse possible
import random
def moyenne_alea():
    somme = random.randint(1, 100) + random.randint(1, 100) + random.randint(1, 100)
    return somme / 3
moy = moyenne_alea()
print(moy)

Fonctions avec paramètre(s) et valeur(s) de retour

La plupart du temps, une fonction reçoit des données (les paramètres) et en renvoie d'autres.

En voici un exemple :

def euro_vers_dollar(montant):
    return montant*0.9953 # en supposant qu'un euro vaut 0,9953 dollar

print(euro_vers_dollar(5)) # pour convertir 5 €
graph LR
val([montant en euros])--> fonc[[euro_vers_dollar]] --> res([montant en dollars])
classDef params fill:#00BFFF,stroke:#333
classDef foncs fill:#f96,stroke:#333
classDef results fill:#9f6,stroke:#333
class fonc foncs
class val params
class res results

À retenir

Pour définir une fonction dans le cas général :

def ma_fonction ( param1, param2, ... ):
    instruction_1
    instruction_2
    ...
    instruction_n
    return resultat1, resultat2, ...

graph LR
%%{init: {'curve': 'basis'}}%%
val([valeur1])--> fonc[["fonc1(param1, param2)"]] -->|return| res([resultat 1])
val2([valeur2])--> fonc
val3([...])-.-> fonc
fonc --> res2([resultat 2])
fonc -.-> res3([...])
classDef params fill:#00BFFF,stroke:#333
classDef foncs fill:#f96,stroke:#333
classDef paramsfac fill:#00BFFF,stroke:#333,stroke-dasharray: 5, 5
classDef results fill:#9f6,stroke:#333
classDef resfacs fill:#9f6,stroke:#333,stroke-dasharray: 5, 5
class fonc,fonc2 foncs
class val,val2 params
class val3 paramsfac
class res,res2 results
class res3 resfacs
Ne rien renvoyer ou renvoyer rien
  • Nous l'avons vu, certaines fonctions, dites procédures, ne renvoient rien (elles n'ont pas de return). Il est donc inutile de taper dans ce cas quelque chose du genre a = ma_fonction(...).
  • Dans ce cas, la fonction renvoie la valeur rien (None en Python). Par exemple, une fonction qui prend trois nombres entiers et renvoie ceux qui sont pairs devra parfois renvoyer... rien (return None). Ce rien constitue alors une information (ici : il y a pas de nombres pairs parmi les trois nombres).

Un bouton en plus

Les éditeurs des exercices suivants comportent le bouton en plus. Quand vous aurez modifié le code, cliquez sur ce bouton pour le faire vérifier.

Exercice

Écrivez puis testez (avec un print) une fonction qui convertit des degrés Celsius en degrés Fahrenheit (je vous laisse chercher la formule sur le net).

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 5/5

.128013)_ vp1:udn2ow/3(mF.gi+afhP8bckeS*ytl=rs050j0F0J0x0v0K0N0d0D0K0x0N0N0L010J0v0f010406050N0i0r0r0x0M0I040G0m0K0i0(0m0k050o0/0;0?0^0-0f040518111b0o180-0j0v0e0W0Y0!0$0z0v0u0z0K1p0z0J0+050R0C0K0F1k0Z0#011o1q1s1q0J1y1A1w0J0M190J0z0W0{0N0f0x0k0$0l011C1m010y0T0F0k0x0r0F1w1V1X1$1E1)1A1,1.0+0a0d0A0M0m0f0m0N0v0~0k0d0P1T0M0M0F0D26111;0k190o1R2j1O1Q1P1x0j1?0$1s0k1+231w1h1j0X1D2t0v2v0k0m2z1w0f2c192h2j2N0.1W272B1%2G0M0=0K0+0g2g2R0,2Q1=2T1E2V2X0+0l2#1X2j2K0F2j2z2m0j1Q2r2*0$0D2H1/192_1a2L2(2i2:38300P2M2R2s010E0+0P0y393d2)1l1E0n0+0d3l373f0k0y0+0D0F0U0v0i0N0c0e0F0M3E0s0x0z2c0k0z0F253t2h3f0*040q3S3e2~010k3i0F0u2c0N3Y3n2C013V0b0h3l060d3^3s3T3!3h042c0J0i0M10122$3`3Z3o0$3$040P3)0F3+442;463-1%0m0+0H3l4i2S48010r3x040g0t0B4o3u3!4l040w4z3{4r0r0v0+0p2/4g2i0-0o3b2@1c360o342k2{112n4Z0x1z4S4V1i2%4V0Q0S0U04.

Exercice

Écrivez et testez une fonction qui prend en paramètres deux nombres et renvoie leur produit et leur somme.

Exemple d'appel :

>>> produit_et_somme(5,3)
(15, 8)

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 5/5

.128013)_ vp1nud2ow/(mgi+afhPbcke,sS*ytl=r:050j0A0G0t0r0H0C0d0y0H0t0C0C0I010G0r0f010406050C0i0p0p0t0J0F040D0l0H0i0#0l0h050n0,0.0:0=0*0f0405150~180n150*0j0r0e0T0V0X0Z0v0r0q0v0H1m0v0G0(050O0x0H0A1h0W0Y011l1n1p1n0G1v1x1t0G0J160G0v0T0^0C0f0t0h0Z0k011z1j010u0Q0A0h0t0p0A1t1S1U1Z1B1$1x1)1+0(0a0d0w0J0l0f0l0C0r0{0h0d0M1Q0J0J0A0y230~1.0h160n1O2g1L1N1M1u0j1:0Z1p0h1(201t1e1g0U1A2q0r2s0h0l2w1t0f29162e2g2K0+1T242y1!2D0J0/0H0(0g2d2O0)2N1/2Q1B2S2U0(0k2Y1U2g2H0A2g2w2j0j1N2o2%0Z0y2E1,162?172I2#2f2-352}0M2J2O2p010z0(0M0u363a2$1i1B0m0(0d3i343c0h0u0(2H2E0i220c0N0c0C0l0.0A3q2e3c0%040o3H3b2{010h0(0t3N3k2z013K0B3i3p3I3P3R040x3U2P3l0Z3K0b0K3i060d3@3#3O3-3d0(290G0i0J0}0 2Z3_3V2R3S3!3r3P0l0(0E493$3{3(3*432.4a3{3Y4f3`3W3(3T4k2f453,3W4c040s4p462(0(4j2K0*0n382;19330n312h2^0~2k4S0t1w4L4O1f2!4O0N0P0R04.

Exercice

Écrivez et testez une fonction qui prend deux chaînes de caractères, par exemple "Marc" et "Julie" et renvoie dans ce cas la chaîne suivante : Marc + Julie = 💙.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier
Évaluations restantes : 5/5

.128013.128153) vp1nud2ow/(mgi+afhPbcke,sSytl=r:050j0A0F0t0r0G0C0d0y0G0t0C0C0H010F0r0f010406050C0i0p0p0t0I0E040D0l0G0i0!0l0h050n0+0-0/0;0)0f0405140}170n140)0j0r0e0S0U0W0Y0v0r0q0v0G1l0v0F0%050N0x0G0A1g0V0X011k1m1o1m0F1u1w1s0F0I150F0v0S0@0C0f0t0h0Y0k011y1i010u0P0A0h0t0p0A1s1R1T1Y1A1#1w1(1*0%0a0d0w0I0l0f0l0C0r0`0h0d0L1P0I0I0A0y220}1-0h150n1N2f1K1M1L1t0j1/0Y1o0h1%1 1s1d1f0T1z2p0r2r0h0l2v1s0f28152d2f2J0*1S232x1Z2C0I0.0G0%0g2c2N0(2M1.2P1A2R2T0%0k2X1T2f2G0A2f2v2i0j1M2n2$0Y0y2D1+152=162H2!2e2,342|0L2I2N2o010z0%0L0u35392#1h1A0m0%0d3h333b0h0u0%0G0l0e0A3p2d3b0$040o3z3a2`010h0%0f0A0I0C0{2r2W0~2Y3q3H3C0B3h3o3A3H3J043L3N3P0A2+3S2-3U3k0Y3C0c0J3h060d3`3Z3G3:3c0%280F0i0I0|3-2e3|3j2y3I3K3M3O0h3Q3Y3/4a0l0%0s4h3!3~0C1W041X0s0d014n3}4j4l4x492Q4c3)4f3+4B2O3~4k044m4604484J4a4q0%1X0H0d0b4w4O0)0n372:18320n302g2@0}2j4/0t1v4(4+1e2Z4+0M0O0Q04.

Fonctions utilisées dans des fonctions

Dans certains cas, les valeurs renvoyées par une fonction peuvent être utilisées par (deviennent les paramètres d') une autre fonction.

graph LR
%%{init: {'curve': 'basis'}}%%
val([val1])--> fonc[["fonc1(par1, par2)"]] -->|return| res[[res1]] --> fonc2[["fonc2(par1, par2, par3)"]] -->|return| rf[[res]] 
val2([val2])--> fonc
fonc --> res2[[res2]] --> fonc2
fonc --> res3[[res3]] --> fonc2
classDef params fill:#00BFFF,stroke:#333
classDef foncs fill:#f96,stroke:#333
classDef paramsfac fill:#00BFFF,stroke:#333,stroke-dasharray: 5, 5
classDef results fill:#9f6,stroke:#333
classDef rfs fill:#9f6,stroke:#333
class fonc,fonc2 foncs
class val,val2 params
class res,res2,res3 results
class rf rfs

En voici un exemple :

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

La fonction euro_vers_yuan appelle les deux fonctions euro_vers_dollar et dollar_vers_yuan.

Nous pourrions écrire cette fonction de façon plus concise (mais moins claire ?) :

def euro_vers_yuan(montant):
    return dollar_vers_yuan(euro_vers_dollar(montant))
graph LR
val([euros])--> fonc[[euro_vers_dollar]] -->|return| res([dollars])--> fonc2[["dollar_vers_yuan(montant)"]] -->|return| rf([yuans])
val--> fonc3[[euro_vers_yuan]] -->|return| rf
classDef params fill:#00BFFF,stroke:#333
classDef foncs fill:#f96,stroke:#333
classDef paramsfac fill:#00BFFF,stroke:#333,stroke-dasharray: 5, 5
classDef results fill:#9f6,stroke:#333
classDef rfs fill:#9f6,stroke:#333
class fonc,fonc2,fonc3 foncs
class val params
class res results
class rf rfs

Exercice

  1. Écrivez une fonction demande_prenom qui affiche "Quel est votre prénom ?", demande une réponse et renvoie cette réponse.
  2. Écrivez une fonction demande_naissance qui affiche "En quelle année êtes-vous né ?", demande une réponse et renvoie cette réponse.
  3. Écrivez une fonction demande_infos qui utilise les deux précédentes et affiche "Bonjour le prénom entré, vous avez environ l'âge approximatif de la personne".

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Exercice

dé 4 faces

  1. Écrivez une fonction de_4 qui simule un dé tétraédrique en renvoyant un nombre entier entre 1 et 4.
  2. Écrivez une fonction lancer_3_des qui utilise la précédente et renvoie la somme et la moyenne de trois lancers d'un dé tétraédrique.

###(Dés-)Active le code après la ligne # Tests (insensible à la casse)
(Ctrl+I)
Entrer ou sortir du mode "deux colonnes"
(Alt+: ; Ctrl pour inverser les colonnes)
Entrer ou sortir du mode "plein écran"
(Esc)
Tronquer ou non le feedback dans les terminaux (sortie standard & stacktrace / relancer le code pour appliquer)
Si activé, le texte copié dans le terminal est joint sur une seule ligne avant d'être copié dans le presse-papier

Petit bêtisier des erreurs courantes sur les fonctions

  1. N'utilisez pas des paramètres constants.
    Les paramètres d'une fonction sont toujours des variables.
    Par exemple, la fonction suivante :
    def mafonction(4, "Toto"):
        print(4 * "Toto")
    
    n'a aucune capacité d'adaptation (ses paramètres sont toujours 4 et "Toto", on pourrait tout aussi bien les retirer) et de toute façon Python n'acceptera pas cette syntaxe.
  2. N'écrasez pas les paramètres.
    Par exemple, dans la fonction suivante :
    def mafonction(a, b):
        a = 3
        print(a * b)
    
    il n'y a pas d'erreur de syntaxe mais à quoi sert le paramètre a si on écrase immédiatement sa valeur ?
  3. La valeur renvoyée par la fonction doit être récupérée ou affichée :
    def mafonction(a, b):
        produit = a * b
        return produit
    mafonction(4, 5)
    
    fait bien ce que l'on attend (calculer le produit de 4 et de 5) mais la valeur renvoyée (le produit) est perdu ! Il faut donc suivant les besoins soit affecter le résultat à une variable :
    def mafonction(a, b):
        produit = a * b
        return produit
    resultat = mafonction(4, 5)# stockage pour utilisation ultérieure
    
    soit l'afficher :
    def mafonction(a, b):
        produit = a * b
        return produit
    print(mafonction(4, 5))# affichage immédiat
    
    soit l'utiliser dans une autre fonction :
    def mafonction_idiote(a):
        print(a)
    def mafonction(a, b):
        produit = a * b
        return produit
    mafonction_idiote(mafonction(4, 5))# la fonction idiote va ici afficher 20
    
  4. N'utilisez pas le nom de la fonction en tant que variable :
    def mafonction(a, b):
        mafonction = a * b
        return mafonction
    
    fonctionne mais la lisibilité de l'ensemble est lamentable (et ça bugguerait peut-être dans d'autres langages moins permissifs).
  5. De préférence, utilisez des noms de fonctions et de variables "parlants" :
    def multiplier_texte(nb, texte):
        return nb * texte
    
    est mieux que :
    def f(a, b):
        return a * b
    
    Pensez à la personne (vous par exemple) qui va relire votre code dans 6 mois...