Les fonctions

Une fonction permet d’identifier une séquence de traitements par un nom. Une fonction peut alors être appelée par son nom à plusieurs endroits dans un programme pour réaliser ces traitements. Il s’agit ainsi de rendre un programme plus compréhensible tout en évitant de dupliquer une séquence à plusieurs points du programme. Un autre intérêt d’une fonction est qu’elle peut être écrite par un programmeur et être utilisée dans un code source écrit par un autre programmeur qui n’a pas besoin de connaître précisément le code exécuté par la fonction si son nom et sa documentation sont suffisamment explicites.

Appeler une fonction

Il existe beaucoup de fonctions déjà fournies avec l’environnement d’exécution Python. On les appelle les builtin functions. La plus célèbre d’entre-elles est sans doute print(). Elle affiche sur la sortie standard du programme une message fourni en paramètre. Pour appeler une fonction dans un programme, il faut préciser son nom et passer entre parenthèses la liste des paramètres. La fonction print() accepte en paramètre ce qu’elle doit afficher :

# appel de la fonction print
print("Bonjour le monde")

Il est possible de passer plusieurs paramètres à la fonction print(). Dans ce cas, il faut séparer la valeur des paramètres par une virgule.

# Cet appel affiche : Bonjour le monde
print("Bonjour", "le", "monde")

Il est également possible d’appeler la fonction print() sans aucun paramètre. La fonction se contentera d’afficher une ligne vide sur la sortie standard. Même s’il n’y pas de paramètre, les parenthèses sont obligatoires en Python 3.

# Cet appel affiche une ligne vide
print()

Si un paramètre peut être une valeur directement donnée par le programme, un paramètre peut aussi être une variable. Dans ce cas, c’est la valeur contenue dans la variable qui est passée à la fonction :

msg = "hello"
# Cet appel affiche : hello
print(msg)

Un paramètre peut aussi être une expression. Dans ce cas, c’est le résultat de l’évaluation de l’expression qui est passé à la fonction :

x = 2
# Cet appel affiche : Le résultat est 8
print("Le résultat est", x**3)

Une fonction peut retourner une valeur, c’est-à-dire fournir le résultat de son traitement. Cette valeur peut être affectée à une variable. Par exemple, la fonction abs() retourne la valeur absolue du nombre qui lui est passé en paramètre :

x = -2
valeur_absolue = abs(x)
# affiche 2
print(valeur_absolue)

L’appel d’une fonction peut être passé en paramètre d’une autre fonction. Dans ce cas, c’est la valeur retournée par l’appel de la fonction qui est passée à l’autre fonction.

# afficher 2
print(abs(-2))

Ce type d’écriture permet une plus grande concision dans l’expression.

Note

Une fonction qui ne produit aucun résultat est souvent appelée une procédure. On dit également qu’elle agit par effet de bord.

En Python, essayer d’affecter le résultat de l’appel d’une procédure à une variable ne produit pas d’erreur. La valeur de la variable est simplement positionnée à None.

# print est une procédure, elle ne retourne aucune valeur
x = print()
# affiche None
print(x)

Les fonctions utiles dans la console Python

Parmi les builtin functions, il existe cinq fonctions qui sont très pratiques lorsqu’on exécute des instructions Python dans une console :

exit() et quit()

Ces fonctions permettent d’arrêter la console Python

>>> quit()
repr(o)

Affiche des informations sur l’élément passé en paramètre.

>>> repr(print)
'<built-in function print>'

L’interpréteur appelle implicitement cette fonction à chaque fois que vous tapez la touche Entrer. L’interpréteur évalue l’expression saisie et, si elle produit un résultat, il affiche la chaîne de caractères retournée par l’appel à repr(o) auquel est passé en paramètre le résultat de l’expression.

>>> print
'<built-in function print>'
help(o)

Affiche la documentation de l’élément passé en paramètre. La console passe généralement en mode affichage de l’aide. Pour sortir de ce mode, il faut presser la touche Q pour quit.

>>> help(print)
dir(o)

Retourne une liste des attributs et des méthodes de l’élément passé en paramètre. Nous verrons beaucoup plus tard que, dans le langage Python, tout est un objet. Un objet se définit par ses attributs (les données) et par ses méthodes (son comportement).

>>> dir(print)
['__call__', '__class__', '__delattr__', '__dir__', '__doc__', '__eq__',
 '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '
 __init__', '__init_subclass__', '__le__', '__lt__', '__module__',
 '__name__', '__ne__', '__new__', '__qualname__', '__reduce__',
 '__reduce_ex__', '__repr__', '__self__', '__setattr__', '__sizeof__',
 '__str__', '__subclasshook__', '__text_signature__']

Les fonctions de conversion de type

Les fonctions int(), float(), bool() et str() permettent de réaliser des conversions d’un type à l’autre.

Convertir en nombre

La conversion entre entiers et nombres à virgule flottante :

>>> r = 3.5
>>> int(r)
3
>>> n = 2
>>> float(n)
2.0

Il est également possible de convertir une chaîne de caractères :

>>> int("3")
3
>>> float("5.25")
5.25

Dans ce cas, la fonction int() accepte un deuxième paramètre indiquant la base du nombre (par défaut la base est 10) :

>>> int("10", 8)
8
>>> int("0xFF", 16)
255

Prudence

Pour la conversion en nombre, la chaîne de caractères peut contenir des espaces avant et après mais si elle ne représente pas un nombre valide, les fonctions int() et float() produisent une erreur ValueError.

Convertir en valeur booléenne

La fonction bool() permet de convertir en valeur booléenne. Elle produit la valeur True pour un nombre différent de 0 et pour une chaîne de caractères non vide. La valeur None produit toujours la valeur False.

>>> bool(42)
True
>>> bool(0)
False
>>> bool("hello")
True
>>> bool("False")
True
>>> bool("")
False
>>> bool(None)
False

Convertir en chaîne de caractères

La fonction str() permet de convertir en chaîne de caractères :

>>> str(1)
'1'
>>> str(True)
'True'
>>> str(None)
'None'

Tester le type d’une valeur ou d’une variable

La fonction type() permet de connaître le type d’une variable ou d’une valeur:

>>> type(1)
<class 'int'>
>>> type(2.2)
<class 'float'>
>>> type("hello")
<class 'str'>
>>> type(1j)
<class 'complex'>

Cette fonction retourne un objet représentant le type de la valeur (nous reviendrons plus tard sur la notion de programmation objet).

Si vous voulez tester le type d’une variable ou d’une valeur, vous pouvez utiliser la fonction isinstance() qui prend la valeur à tester comme premier paramètre et le type attendu comme second paramètre.

>>> isinstance(True, bool)
True
>>> isinstance(1, int)
True
>>> isinstance(2.2, float)
True
>>> isinstance("hello", str)
True
>>> isinstance("hello", bool)
False
>>> isinstance(2.3, int)
False
>>> isinstance(True, float)
False
>>> isinstance(1, str)
False

Note

Remarquez que bool, int, float et str permettent de convertir une valeur mais également de désigner un type. Nous y reviendrons dans un chapitre ultérieur.

Astuce

En Python, une valeur booléenne est à la fois de type bool et de type int. True et False sont donc également considérés comme des nombres en Python ayant pour valeur respective 1 et 0.

>>> isinstance(True, int)
True
>>> isinstance(False, int)
True
>>> 1 + True
2
>>> True + False
1

Exercices

Exercice : comparaison à la moyenne

Écrivez un programme qui demande à l’utilisateur sa taille puis qui indique l’écart en centimètres par rapport à la moyenne. On pourra utiliser comme moyenne 1m75.

Pour réaliser ce programme, vous allez avoir besoin de la fonction input(). Cette fonction accepte en paramètre le message à afficher à l’utilisateur. L’appel à cette fonction bloque le programme et attend que l’utilisateur saisisse une valeur puis tape sur Entrer. La fonction retourne alors la valeur saisie sous la forme d’une chaîne de caractères.

Exemples d’utilisation du programme :

Quelle est votre taille ? 1.70
Vous avez un écart de -5 centimètres par rapport à la moyenne
Quelle est votre taille ? 1.75
Vous avez un écart de 0 centimètres par rapport à la moyenne

Exercice : conversion Fahrenheit / Celsius

Écrivez un programme qui demande à l’utilisateur de saisir une température en degré Fahrenheit et qui affiche le résultat de la conversion en degré Celsius avec un seul chiffre après la virgule.

La formule à appliquer :

d(f) = \frac{f - 32}{1.8}

Exemple d’utilisation du programme :

Température Fahrenheit ? 42
Une température de 42.0°F correspond à 5.5°C

Exercice : QCM en invite de commande

Écrivez un programme qui pose des questions pour lesquelles l’utilisateur doit fournir une réponse. Pour chaque réponse correcte, l’utilisateur marque un point. À la fin, le programme indique le nombre de réponses justes et le nombre de réponses fausses.

Exemple d’utilisation du programme :

Quel est ton nom ?
Sir Robin de Camelot.
Quelle est ta quête ?
Trouver le Saint Graal.
Quelle est la capitale de la Syrie ?
Je sais pas ça !

Réponses correctes : 2
Réponses incorrectes : 1

Astuce

On peut utiliser le fait qu’une valeur booléenne est également un entier en Python avec True qui vaut 1 et False qui vaut 0.

Déclarer une fonction

L’intérêt principal des fonctions est de pouvoir organiser un programme en le décomposant en traitements de granularité plus faible. Ces traitements deviendront des fonctions dont le nom et la documentation amélioreront la lisibilité et la maintenabilité.

Pour déclarer sa propre fonction, on commence par préciser sa signature. Cette signature est délimitée par le mot-clé def et deux-points :. Elle donne le nom de la fonction et la liste des paramètres. Puis vient le corps de la fonction, c’est-à-dire le code à exécuter lorsque cette fonction est appelée. Pour délimiter le corps d’une fonction, Python utilise l’indentation. Chaque ligne de la fonction commence par un certain nombre d’espaces (généralement quatre). Cela donne, à la fois, une indication visuelle au lecteur et à l’interpréteur de code.

Note

Le nom d’une fonction suit la même convention que le nom des variables. Il s’écrit en lettres minuscules et les mots sont séparés par un trait inférieur (underscore) suivant la notation dite du snake case.

def dire_bonjour_a(nom):
    print("Bonjour", nom)

Un paramètre est simplement indiqué par son nom qui peut être ensuite utilisé dans le corps de la fonction. Un paramètre a pour valeur celle qui est donnée à chaque appel de la fonction.

Il est ensuite possible d’appeler la fonction qui a été déclarée :

# affiche Bonjour David
dire_bonjour_a("David")

Note

Le corps d’une fonction Python doit contenir au moins une ligne. Si pour une raison ou une autre, vous voulez déclarer une fonction mais que vous voulez laisser le corps vide (votre fonction ne réalise aucun traitement), alors vous devez utiliser le mot-clé pass :

def ma_fonction_qui_ne_fait_rien():
    pass

Documenter une fonction

Pour écrire la documentation d’une fonction, il suffit d’ajouter une chaîne de caractères directement à la suite de la déclaration de la signature de la fonction. On appelle ce texte la docstring. C’est ce texte qui est affiché lorsqu’on passe le nom de la fonction à la fonction help().

def dire_bonjour_a(nom):
    """Affiche un message qui dit bonjour au nom qui est passé en
       paramètre"""
    print("Bonjour", nom)
>>> help(dire_bonjour_a)

Les valeurs de retour

Pour qu’une fonction retourne une valeur, il faut utiliser le mot-clé return suivi de la valeur à retourner.

def creer_nom(prenom, nom):
    nom_complet = prenom + " " + nom
    return nom_complet

La valeur à retourner peut être le résultat d’une expression. Cela evite souvent d’avoir recours à des variables intermédiaires :

def creer_nom(prenom, nom):
    return prenom + " " + nom

Le mot-clé return interrompt immédiatement le traitement de la fonction et retourne la valeur au programme appelant. Si vous écrivez du code après un return, il ne sera jamais exécuté.

def creer_nom(prenom, nom):
    return prenom + " " + nom
    print("Cette instruction ne sera jamais executée")

Une fonction peut retourner plusieurs valeurs. C’est le cas, par exemple, de la fonction standard divmod() qui retourne à la fois le résultat de la division et le reste de la division. Python permet de récupérer ces valeurs dans deux variables différentes :

resultat, reste = divmod(10, 3)
print("Le resultat de la division de 10 par 3 est", resultat, "et le reste est", reste)
# Le resultat de la division de 10 par 3 est 3 et le reste est 1

Nous pourrions réécrire sans difficulté la fonction divmod() :

def divmod(numerateur, denominateur):
    resultat = numerateur // denominateur
    reste = numerateur % denominateur
    return resultat, reste

Le mot-clé return peut également être employé seul pour signaler la fin d’une procédure. Dans cas, l’exécution de return interrompt immédiatement la procédure sans retourner de valeur.

Les paramètres nommés

Python supporte les paramètres nommés pour une fonction. Cela signifie que vous pouvez, lors de l’appel d’une fonction, préciser le nom et la valeur du paramètre.

def dire_bonjour_a(nom):
    print("Bonjour", nom)

dire_bonjour_a(nom="David")

Cela peut s’avérer utile pour une fonction qui accepte plusieurs paramètres. En effet, il n’est pas toujours facile de se souvenir de l’ordre exact des paramètres ni de leur signification. En nommant les paramètres au moment de l’appel, leur rôle devient plus explicite et nous ne sommes plus obligés de respecter l’ordre de leur déclaration :

def dire_bonjour_a(prenom, nom):
    print("Bonjour", prenom, nom)

dire_bonjour_a(nom="Gayerie", prenom="David")

Note

Vous pouvez appeler un fonction en passant des paramètres et des paramètres nommés. Dans ce cas, les paramètres nommés doivent être placés à la fin de la liste des paramètres.

Valeur par défaut des paramètres

Python autorise une fonction à avoir une valeur par défaut pour un ou plusieurs de ses paramètres. Ainsi le programme qui appelle la fonction peut omettre de donner une valeur pour ces paramètres. Cela permet de rendre certains paramètres optionnels. On précise la valeur d’un paramètre après le signe =.

def dire_bonjour_a(nom, message="Bonjour"):
    print(message, nom)

# affiche Bonjour David
dire_bonjour_a("David")
# affiche Bonsoir David
dire_bonjour_a(message="Bonsoir", nom="David")

Fonction et portée des variables

Une fonction peut accepter des paramètres et une fonction peut déclarer des variables :

def calcul_prix_ttc(prix_ht, taux_tva = 20):
    # déclaration de la variable tva
    tva = prix_ht * taux_tva / 100
    tva = round(tva, 2)
    return prix_ht + tva

Astuce

La fonction round() arrondie un nombre (le premier paramètre) avec une précision après la virgule donnée par le second paramètre.

Dans l’exemple ci-dessus, la fonction calcul_prix_ttc() utilise la variable tva pour stocker le calcul de la TVA et réaliser un arrondi. Cette variable est liée à l’exécution de la fonction calcul_prix_ttc(). Cela signifie qu’elle n’existe pour l’interpréteur qu’au moment de l’exécution de la fonction. Dès que la fonction se termine, la variable et sa valeur ne sont plus accessibles. On dit que la portée de la variable tva est limitée à la fonction calcul_prix_ttc(). Donc cette variable n’existe pas dans le reste du programme.

# Génère une erreur NameError car la variable tva n'existe pas
print(tva)

calcul_prix_ttc(100)

# Génère une erreur NameError car la variable tva n'existe pas
print(tva)

Mais que se passe-t-il si le programme déclare et utilise une variable tva avant et après l’appel à calcul_prix_ttc()

tva = "ceci n'est pas vraiment le montant d'une tva"

calcul_prix_ttc(100)

# affiche: ceci n'est pas vraiment le montant d'une tva
print(tva)

Avec l’exemple précédent, on voit bien que la variable tva n’est pas modifiée par l’appel à la fonction calcul_prix_ttc() car même si elle a un nom identique à la variable utilisée dans cette fonction, il s’agit de variables différentes pour l’interpréteur. On peut déclarer et utiliser des variables qui ont le même nom à condition qu’elles n’appartiennent pas à la même portée.

Exercices

Exercice : comparaison à la moyenne

Reprenez l’exercice qui permet de comparer une taille saisie avec la moyenne.

Créez trois fonctions dans le programme :

demander_taille()

Cette fonction demande sa taille à l’utilisateur et retourne la valeur saisie sous la forme d’un nombre.

comparer_taille()

Cette fonction compare une première taille à une seconde et donne la différence en centimètres. Le second paramètre a une valeur par défaut qui correspond à la moyenne de la taille.

afficher_difference_moyenne()

Cette fonction prend en paramètre un écart de taille en centimètres et affiche l’information à l’utilisateur.

Exercice : fonction de conversion Fahrenheit / Celsius

Écrivez une fonction pour convertir une température en degré Fahrenheit en une température en degré Celsius.

Variable globale et fonction

Une variable qui est déclarée dans le fichier principal est aussi appelée variable globale car elle existe dans la mémoire jusqu’à la fin de l’exécution du programme.

Imaginons le programme suivant :

message="Bonjour"

def dire_bonjour_a(nom):
    print(message, nom)

# Affiche Bonjour David
dire_bonjour_a("David")

La fonction dire_bonjour_a() utilise la paramètre nom mais aussi la variable globale message. Dans les deux cas, la fonction ne fait que lire la valeur du paramètre et de la variable globale. Mais comment faire pour modifier la valeur d’une variable globale dans le corps d’une fonction ?

Nous avons vu à la section précédente qu’il n’est pas possible de modifier directement une variable globale dans une fonction. Nous pouvons simplement créer une nouvelle variable avec le même nom ayant une portée limitée à la fonction. Pour nous en convaincre, essayons le programme suivant :

message = "Un message global"

def traiter_message():
    message = "Un message local"
    print(message)

print(message)
traiter_message()
print(message)

Ce programme produit le résultat suivant :

Un message global
Un message local
Un message global

Cela montre bien que la variable globale message et la variable message initialiser dans la fonction traiter_message() sont bien distinctes.

En Python, il est tout de même possible de modifier une variable globale dans une fonction. Pour cela, il faut préciser explicitement grâce au mot-clé global que la fonction fait référence à la variable globale. Si nous changeons notre implémentation :

message = "Un message global"

def traiter_message():
    global message
    message = "Un message local"
    print(message)

print(message)
traiter_message()
print(message)

Ce programme produit le résultat suivant et modifie bien le contenu de la variable globale :

Un message global
Un message local
Un message local

Prudence

Le recours à des variables globales est souvent le signe d’une mauvaise conception logicielle et est fortement déconseillé. On se limite généralement à utiliser ce type de variables pour représenter des constantes, c’est-à-dire des valeurs qui ne doivent pas changer pendant l’exécution du programme. Il n’existe pas de méthode directe pour déclarer des constantes en Python, on se contente d’écrire le nom des constantes en majuscules pour signaler notre intention aux autres développeurs :

TAUX_TVA = .2

def calculer_prix_ttc(prix_ht):
    tva = round(prix_ht * TAUX_TVA, 2)
    return prix_ht + tva

Notez qu’il n’est pas nécessaire d’utiliser le mot-clé global pour lire et utiliser la valeur d’une variable globale.

Notion de méthode

En plus des fonctions, Python connaît la notion de méthode. Une méthode est une séquence de traitement que l’on effectue sur un type. Une méthode est appelée pour une valeur, une variable ou un paramètre en utilisant l’opérateur .. Par exemple, une chaîne de caractères possède les méthodes upper() et lower() permettant de créer une nouvelle chaîne de caractères en lettres minuscules et respectivement en lettres majuscules :

msg = "Testons les méthodes."
msg_lower = msg.lower()
msg_upper = msg.upper()
print(msg_lower)
print(msg_upper)
msg_upper = "hello".upper()
print(msg_upper)

Une chaîne de caractère possède également la méthode format() qui permet de réaliser un formatage en utilisant cette chaîne comme modèle. Les valeurs à insérer sont désignées dans la chaîne par des accolades avec le numéro de position du paramètre. Si vous voulez appliquer un formatage particulier aux valeurs, reportez-vous à la documentation complète.

>>> "Hello {0}".format("David")
'Hello David'
>>> "{0} pèse {1:06.2f}Kg".format("David", 71.33549)
'David pèse 071.34Kg'

Note

Nous verrons plus en détail la notion de méthode lorsque nous aborderons le paradigme de la programmation orientée objet.