Les fonctions

Les fonctions

Une fonction permet d'éviter d'avoir à écrire plusieurs fois le même code lorsqu'un même traitement doit être mis en oeuvre à plusieurs endroits dans le programme.

Le rôle de découpe en unités logiques

Un rôle important des fonctions est de découper votre programme en "petites unités logiques" faciles à comprendre. L'usage des fonctions, par ce rôle, facilite la conception d'un programme mais aussi sa relecture, sa réutilisation, les corrections.

On va chercher à réécrire le programme proposé dans l' exercice sur la suite de Conway de la feuille d'exercices sur la boucle while.

Pour rendre ce programme plus facile à comprendre, on va le découper en fonctions, chacune des fonctions écrites devra avoir un rôle spécifique dans l'objectif de la résolution de ce problème.

Première fonction.

Notre première fonction devra prendre une chaîne de caractères en paramètre et retourner le nombre de caractères identiques se trouvant en tête de cette chaîne.

Si nous nommons NbCaracIdentiq cette fonction, NbCaracIdentiq('ggjigh') devra être égal à 2, NbCaracIdentiq('555425') devra être égal à 3, NbCaracIdentiq('') devra être égal à 0...


def nbCaracIdentiq(chaine) :
	""" L'entrée chaine est une chaine de caractères.
	La sortie est un entier positif.
	La fonction retourne le nombre de caractères successifs en tête de chaine
	qui sont égaux à chaine[0].
	Par exemple, NbCaracIdentiq('331234') est égal à 2.
	NbCaracIdentiq('bbb12cb34') est égal à 3. 
	L'image de la chaîne vide '' doit être 0.
	"""
	
	if len(chaine)==0 : 
		return 0 # si la chaine est vide, l'image est 0.
	else :
		premier_caractere=chaine[0]
		cpt=0 # compteur pour le nb de caractères 
		    	# identiques en tête de chaine
		j=0  # indice pour parcourir chaine
		while (j<len(chaine)  and chaine[j]==premier_caractere ):
			cpt+=1 # on incrémente le compteur
			       # tant qu'on tombe sur la même lettre ch[0]
			j+=1 # on passe à la lettre suivante
		return cpt 
		
		
## La suite est une utilisation de la fonction ##

print(nbCaracIdentiq('331234'))
print(nbCaracIdentiq('bbb12cb34'))
print(nbCaracIdentiq(''))

On obtient :

2
3
0

Quelques remarques.

  • La fonction est auto-documentée par un texte entre """ et """ (c'est ce que l'on appelle le docstring de la fonction). Toutes vos fonctions devront commencer ainsi par un docstring. Ce docstring doit donner :
    1. la nature (le type) des entrées (ici une chaîne de caractères).
    2. la nature (type ) de la sortie (ici un entier).
    3. le lien entre les entrées et la sortie (en d'autres termes, le rôle de la fonction)
    4. des exemples pour clarifier ce rôle, qui seront choisis pour être également de bons tests de la fonction.
  • La fonction se termine avec une instruction return. Ce qui suit le return est l'image des entrées par la fonction. Dès que la fonction rencontre un return, elle retourne ce qui suit le return et stoppe son exécution.

A propos de la remarque qui vient d'être faite (Dès que la fonction rencontre un return, elle retourne ce qui suit le return et stoppe son exécution.), une conséquence est que le else dans le code précédent est inutile.
Le code ci-dessous (on a enlevé else) définit exactement la même fonction :


def nbCaracIdentiq(chaine) :
	""" L'entrée chaine est une chaine de caractères.
	La sortie est un entier positif.
	La fonction retourne le nombre de caractères successifs en tête de chaine
	qui sont égaux à chaine[0].
	Par exemple, NbCaracIdentiq('331234') est égal à 2.
	NbCaracIdentiq('bbb12cb34') est égal à 3. 
	L'image de la chaîne vide '' doit être 0.
	"""
	
	if len(chaine)==0 : 
		return 0 # si la chaine est vide, l'image est 0.
	 
	premier_caractere=chaine[0]
	cpt=0 # compteur pour le nb de caractères 
	       # identiques en tête de chaine
	j=0  # indice pour parcourir chaine
	while (j<len(chaine)  and chaine[j]==premier_caractere ):
		cpt+=1 # on incrémente le compteur
		       # tant qu'on tombe sur la même lettre ch[0]
		j+=1 # on passe à la lettre suivante
	return cpt 
		
		
## La suite est une utilisation de la fonction ##

print(nbCaracIdentiq('331234'))
print(nbCaracIdentiq('bbb12cb34'))
print(nbCaracIdentiq(''))

en effet, lorsque la chaîne donnée en paramètre est la chaîne vide, l'exécution passe par l'instruction return 0 qui a pour effet de stopper la fonction, ce qui suit n'est donc pas lu. Par contre, lorsque la chaîne n'est pas vide, c'est l'instruction return 0 qui n'est pas "vu" et la suite du corps de la fonction est exécutée.

Seconde fonction.

Notre second programme aura pour objectif de couper les caractères identiques en tête d'une chaîne de caractères.


def coupeRepetTete(ch):
	""" L'entrée ch est une chaîne de caractères.
	La sortie sera une chaîne de caractères chsortie.
	chsortie est ch privée du premier caractère ch[0]
	ainsi que des caractères qui suivent égaux à ch[0].
	Si par exemple ch='rrtzra', 
	alors coupeRepetTete(ch)='tzra'. """
	m=nbCaracIdentiq(ch) # m est le nombre de caractères
					     # identiques en tête de chaîne
	return ch[m:] # on retourne la chaîne
	               # privée des m premiers caractères
	               
	
	
## utilisation de la fonction ##               
print(coupeRepetTete('331234'))
print(coupeRepetTete('bbb12cb34'))
print(coupeRepetTete(''))	
  1. Dans cette fonction, on fait appel à la première fonction écrite. Elles doivent être dans un même fichier (il existe toutefois des techniques, avec import, permettant d'écrire ces fonctions dans des fichiers séparés.)
  2. On commence à voir ici l'intérêt du découpage en fonctions : si l'on accepte que la première fonction fait bien ce que son docstring affirme, cette deuxième fonction est facile à écrire, facile à comprendre. Les fonctions permettent ainsi de "découper" les difficultés en plus petits problèmes plus faciles à résoudre.
  3. Ce découpage, nous l'avons signalé, facilite la maintenance d'un programme. Si nous nous apercevons par exemple que notre première fonction contient un bug, nous pouvons la réécrire, la corriger. Mais si nous respectons la nature des entrées et des sorties, cette réécriture de la première fonction n'entraînera aucune modification de la seconde fonction. Vous pouvez facilement imaginer l'intérêt de cela sur un programme comportant plusieurs dizaines de fonctions.

Vous pourrez par exemple vérifier que si l'on modifie la première fonction de l'une des façons ci-dessous, la seconde fonction fonctionnera en apparence exactement de la même façon.


def nbCaracIdentiq(chaine) :
	""" L'entrée chaine est une chaine de caractères.
	La sortie est un entier positif.
	La fonction retourne le nombre de caractères successifs en tête de chaine
	qui sont égaux à chaine[0].
	Par exemple, NbCaracIdentiq('331234') est égal à 2.
	NbCaracIdentiq('bbb12cb34') est égal à 3. 
	L'image de la chaîne vide '' doit être 0.
	"""
	
	if len(chaine)==0 : 
		return 0 # si la chaine est vide, l'image est 0.
	 
	premier_caractere=chaine[0]
	cpt=0 # compteur pour le nb de caractères 
	       # identiques en tête de chaine
	 
	for x in chaine :
		if x==premier_caractere : cpt+=1
		else : break
	return cpt 

Rappel pour l'instruction break sur cette page.

Autre écriture de la fonction 1 :

def nbCaracIdentiq(chaine) :
	""" L'entrée chaine est une chaine de caractères.
	La sortie est un entier positif.
	La fonction retourne le nombre de caractères successifs en tête de chaine
	qui sont égaux à chaine[0].
	Par exemple, NbCaracIdentiq('331234') est égal à 2.
	NbCaracIdentiq('bbb12cb34') est égal à 3. 
	L'image de la chaîne vide '' doit être 0.
	"""
	
	if len(chaine)==0 : 
		return 0 # si la chaine est vide, l'image est 0.
	 
	premier_caractere=chaine[0]
	cpt=0 # compteur pour le nb de caractères 
	       # identiques en tête de chaine
	while ( chaine and chaine[0]==premier_caractere ) :
		cpt+=1
		chaine=chaine[1:] # on supprime le premier caractère 
	return cpt 
		
		
## La suite est une utilisation de la fonction ##

print(nbCaracIdentiq('331234'))
print(nbCaracIdentiq('bbb12cb34'))
print(nbCaracIdentiq(''))
print(nbCaracIdentiq('aa'))

Troisième fonction

Notre troisième fonction prendra en paramètre une chaîne de caractères ch et renverra une chaîne de caractères suivant le principe exposé dans l'exercice sur la suite de Conway dans la feuille d'exercices sur while.

Si par exemple ch='aabcddd', la chaîne en sortie sera '2a1b1c3d'.


def ligneSuivante(ch):
	""" L'entrée ch est une chaîne de caractères.
	La sortie sera une chaîne de caractères.
	Le principe de construction de la chaîne de sortie 
	à partir de la chaîne d'entrée est le principe
	de la suite de Conway  
	http://fr.wikipedia.org/wiki/Suite_de_Conway. """
	
	ligne=''
	while ch!='':
		ligne+=str(nbCaracIdentiq(ch))+ch[0]
		ch=coupeRepetTete(ch)
	return ligne
	
	
	
## utilisation de la fonction ##               
print(ligneSuivante('331234'))
print(ligneSuivante('bbb12cb34'))
print(ligneSuivante('4445506666'))	

Quatrième fonction

Notre quatrième fonction construira le triangle de l'exercice "Suite de Conway" de la feuille d'exercices sur while à partir d'une première chaîne de caractères ch (par exemple ch='1' si l'on reprend l'exemple de l'exercice cité).

Cette quatrième fonction est maintenant facile à écrire. Nous vous laissons ce travail en exercice ( exercice 1 de la fiche d'exercices de ce chapitre 'fonctions').

Vous pouvez, après réalisation et test de cette dernière fonction, comparer les deux programmes obtenus pour la réalisation de la suite de Conway . Celui que nous avons écrit ici est beaucoup plus long, mais il est également beaucoup plus aisé à relire. Pour le comprendre, on peut se concentrer sur une seule difficulté à la fois. Ce travail de décomposition en petites tâches vous incombera lors de la réalisation de mini-projets et surtout lors de la réalisation de votre projet pour l'évaluation finale.