10 KiB
title, author
title | author |
---|---|
Découvrir les fonctions | Steve Kossouho |
Découvrir les fonctions
L'utilité des fonctions
Une fonction, c'est :
- Minimaliste si possible,
- Réutilisable,
- Un gain de temps et d'espace
Syntaxe de déclaration de fonctions
def my_first_function():
# Affiche un texte à chaque fois qu'on l'exécute
print("Voici le code de la fonction")
my_first_function()
Typographie des fonctions
Les noms de fonctions se choisissent, par convention, comme toute autre variable :
- Tout en minuscules (ex.
exponential
) - Mots séparés par des underscores (ex.
get_warning_count
) - Peuvent contenir des chiffres sauf au début (ex.
log4
)
Référence versus appel de fonction
Lorsque vous définissez une fonction appelée action
:
action
est une variable de type fonction dont vous pouvez ensuite exécuter le code associé.
action
est donc la référence de la fonction.action()
{.python} exécute le code deaction
, et récupère son expression de retour.
Valeurs de retour d'une fonction
En mathématiques, une fonction renvoie toujours une valeur.
Par exemple, on peut déclarer Pour tout x dans les nombres réels, f(x) = x × 15
.
En Python, pour qu'une fonction qu'on déclare renvoie une valeur (transmette une valeur au code qui l'exécute)
lorsqu'on l'exécute, il faut utiliser le mot-clé return
{.python}.
Lorsque le mot-clé est rencontré par l'interpréteur, il interrompt immédiatement l'exécution de la fonction et l'instruction qui a appelé la fonction récupère la valeur de l'expression qui a été retournée.
def multiply_by_five(value): # Fonction qui prend un argument nommé value
return value * 5
result = multiply_by_five(10) # l'expression `10 * 5` est assignée à la variable
print(result) # affiche 50
Valeurs de retour spécifiques
Le mot-clé return
{.python} a quelques comportements implicites :
- Il peut être utilisé tout seul, sans expression :
return
{.python}. C'est équivalent à écrirereturn None
{.python}, mais moins explicite. - Si une fonction se termine sans avoir utilisé le mot-clé
return
{.python} :- C'est toujours une fonction valide (on l'a vu dans le premier exemple)
- Implicitement, l'interpréteur Python retourne également la valeur
None
{.python}.
. . .
En clair, cela signifie qu'une fonction en Python renvoie toujours une valeur qui peut être assignée
à une variable, même si la valeur None
{.python} a souvent peu d'utilité.
Passer quelques arguments aux fonctions
Déclarer une fonction simple, c'est déjà pas mal, mais en déclarer une qui dépend de un ou plusieurs arguments reçus en entrée, c'est bien plus utile !
Python propose au moins 4 types d'arguments différents, dont les usages sont évidemment différents, et parmi ceux-ci, deux sont absolument essentiels et nous allons les aborder :
- Arguments positionnels
- Arguments par défaut (avec valeur par défaut)
Arguments : Positionnels
Derrière cet adjectif un peu pompeux se cache le type d'argument le plus simple à déclarer et à utiliser :
def f(x, y):
# Accepte deux arguments, affiche leur valeur
# Mais ne renvoie rien d'autre que `None`
print(x, y)
f(1, 2) # exécute la fonction, donc affiche "1 2"
. . .
Passer des valeurs à ces arguments est obligatoire lorsqu'on souhaite exécuter la fonction,
et les valeurs sont passées aux arguments dans le même ordre que dans la signature;
ici, à la ligne 5, 1
{.python} va dans x
{.python} et 2
{.python} va dans y
{.python}.
C'est de ce comportement que vient la notion de positionnalité.
Arguments : Valeurs par défaut
def f(x, alpha=15, beta=16):
# Accepte trois arguments, dont deux avec une valeur par défaut
print(x, alpha, beta)
return (x, alpha, beta) # renvoie un tuple
f(1) # ça marche, alpha vaut 15, beta vaut 16
f(46, 10, 12) # acceptable
f(99, alpha=23) # conseillé
f(99, 23) # équivalent à l'exemple du dessus
f(True, beta=23) # conseillé et obligatoire
f(True, , 23) # ceci est une erreur de syntaxe, on ne met pas deux virgules de suite en vrac
f(beta=23, x=50) # passer un arg. positionnel par son nom : déconseillé
. . .
Les arguments avec valeur par défaut sont facultatifs; cela signifie que si le développeur les omet lorsqu'il exécute la fonction, Python choisira pour ces arguments leur valeur par défaut.
Arguments : ordre
Malheureusement, mais c'est techniquement nécessaire, il y a un ordre imposé par l'interpréteur Python lorsque vous déclarez les arguments acceptés par une fonction : les arguments positionnels doivent être déclarés en premier dans la liste des arguments, s'il y en a.
. . .
Tous les arguments, positionnels (obligatoires) et par défaut, peuvent cependant être passés par leur nom, mais ne faites jamais ça, vous induirez vos relecteurs en erreur :
def f(x, alpha=15, beta=16):
return (x, alpha, beta) # renvoyer un tuple avec x, alpha et beta
# x peut être passé par son nom, non positionnellement, mais c'est déconseillé
print(f(beta=23, x=50))
Bonus : Argument "étoile" (séquence)
Il existe un type d'argument, qui n'apparaît qu'une seule fois maximum, et dont le nom est précédé d'une étoile dans la signature de la fonction.
Cet argument apparaît après les arguments positionnels, et de forte préférence avant les arguments avec valeur par défaut. Lors de l'exécution de la fonction, cet argument contient toujours un tuple valide, même vide. Également, comme cet argument contient toujours un tuple, il est généralement nommé avec un nom au pluriel.
def stretchable(number, *words):
print(number, words) # words est toujours un tuple
stretchable(15, "word 1", "word 2", "word 3") # les 3 arguments vont dans le tuple `words`
stretchable(15, True, 3.14159) # les 2 arguments vont dans le tuple `words`
stretchable(1) # le tuple `words` sera vide
Argument "étoile" : usage
Un argument de ce type accepte, lors de l'appel de la fonction, un nombre de valeurs arbitraire (0 ou plus), et ces valeurs sont passées comme des arguments positionnels (sans nom d'argument).
Cette technique est utilisée dans la fonction print
{.python} pour pouvoir afficher à la suite plusieurs arguments.
On peut directement renseigner une liste pour ce type d'argument, en passant, lors de l'appel de fonction, une expression de liste (ou tuple) précédée par une étoile :
def star_function(number, *words):
print(number, words) # words est toujours une liste
star_function(15, *["word 1", "word 2", "word 3"]) # raccourci
TODO: Si arg étoile suivi de défaut, passer *[], suivi d'une valeur positionnelle, cette dernière s'ajoute quand même à l'argument étoile, et donc obligation passer l'argument par défaut via son nom.
Bonus : Argument "double-étoile" (dictionnaire)
Un dernier type d'argument, apparaît aussi une seule fois maximum, et généralement en tout dernier dans les arguments. Celui-ci s'utilise en passant des noms d'arguments qui n'existent pas ailleurs dans la signature de la fonction :
def f_keywords(other=15, **kwargs):
print(kwargs) # toujours un dictionnaire
f_keywords(plop="Hello", foo=19) # vont dans le dictionnaire `kwargs`.
On appelle aussi cet argument l'argument "mots-clés", et s'appelle très fréquemment kwargs
.
Si l'on appelle f_keywords
{.python} avec un argument plop
, Python regarde si un argument de ce nom existe. Si oui, la valeur de cet argument est modifiée. Si non, l'argument est ajouté comme association dans kwargs
, de telle façon que kwargs == {"plop": "Hello"}
{.python}.
Souvent utilisé par coquetterie, mais l'argument pourrait être généralement remplacé par le simple passage d'un dictionnaire dans un argument positionnel.
Arguments : Ordre de déclaration
Si vous deviez avoir dans vos fonctions tous les types d'arguments que nous avons vus, l'ordre de leur apparition devrait être le suivant :
positionnel
(toujours premier)étoile
(utilisé positionnellement, toujours second)par défaut
(utilisé de préférence par nom, de préférence troisième)double-étoile
(utilisé par nom)
Superbonus : Arguments spéciaux
Arguments spéciaux : Slash
Depuis Python 3.8 (2019), vous pouvez contrôler l'utilisation de vos fonctions en ajoutant dans votre signature un argument
simplement nommé /
{.python}. Il ne peut exister qu'une fois au maximum.
Lorsque vous spécifiez cet argument dans votre signature, tous les arguments qui le précèdent ne peuvent pas être spécifiés autrement que positionnellement :
def my_function(a, b, /, c, d):
print(a, b, c, d)
my_function(1, 2, 3, 4) # autorisé
my_function(1, 2, c=3, d=4) # autorisé
my_function(1, b=2, c=3, d=4) # impossible, b est positionnel uniquement
Lorsqu'un argument /
{.python} ou *
{.python} est présent, les arguments *args
{.python} sont interdits. La raison est que, si un tel
argument est présent, on est automatiquement tenu de passer les arguments qui suivent par leur nom.
Arguments spéciaux : Étoile
Vous pouvez contrôler l'utilisation de vos fonctions en ajoutant dans votre signature un argument
simplement nommé *
{.python}. Il ne peut exister qu'une fois au maximum, et se trouver après l'argument
/
{.python}.
Lorsque vous spécifiez cet argument dans votre signature, tous les arguments qui le suivent ne peuvent être spécifiés autrement qu'en précisant leur nom :
def my_function(a, b, c=3, *, d=4):
print(a, b, c, d)
my_function(1, 2, 3, d=4) # autorisé
my_function(1, 2, 3, 4) # impossible, d ne peut pas être utilisé positionnellement