Fonctions et Procédures

Il est possible avec Python de définir une fonction qui ressemble à une fonction mathématique ; la syntaxe est alors la suivante :

\(f:x \rightarrow x^2\)
def f(x):
   return x**2

Mais on peut définir des fonctions beaucoup plus complexes …


Déclaration d’une fonction

Une fonction doit d’abord être déclarée (ou définie).

Voici la forme générale de déclaration d’une fonction :

def ma_fonction([arguments]):
   ...
   instructions
   ...
   [return resultat]
ici les crochets [ ] signalent des paramètres ou lignes facultatifs

(il ne faut pas les saisir !)

La déclaration d’une fonction commence par le mot clé (ou déclaration – statement) def  puis vient le nom de la fonction ma_fonction , puis placé entre parenthèses les éventuels arguments, le tout ponctué de : .

Le contenu de la fonction (séquence d’instructions) se situe intégralement dessous la ligne de déclaration et doit impérativement être indenté d’un cran (une tabulation).

Remarque : dans la plupart des éditeurs dédiés au langage Python, un appui sur la touche « Entrée » après le :  crée automatiquement une indentation.

Si la fonction doit retourner un résultat, cela se fait par l’instruction return , suivie du résultat. Dans le cas contraire, on parle de procédure.

Une propriété remarquable de l’instruction return est qu’elle interrompt systématiquement l’exécution de la fonction : inutile donc de placer des instructions après un return  car ces instructions ne seront jamais lues par l’interpréteur. On parle parfois de code mort pour désigner les lignes qui suivent (à l’intérieur de la définition d’une fonction) l’instruction return .

def power(a,n):
   return a**n
   print("C’est inutile d’écrire ici") # c’est du code mort !

Appel d’une fonction

Une fois déclarée, on peut appeler la fonction :

ma_fonction([arguments])   # s'il s'agit d'une procédure

ou bien

resultat = ma_fonction([arguments])   # s'il s'agit d'une fonction

Dans ce cas, la variable resultat  prend la valeur retournée par ma_fonction() .

Exercices :

  1. Écrire une fonction div_euclid()  qui accepte deux arguments  n  et m , et renvoie le reste et le quotient de la division euclidienne de n  par m .
  2. Écrire une fonction qui accepte un argument  n , et teste si \(2^n -1\) est divisible par 15 (par exemple f(4)  doit renvoyer True  et f(5)  False ).

L’objet fonction

Comme tous les éléments dans Python, une fonction est un objet :

def ma_fonction(arg):
   y = arg*6 + 5
   return y
>>> ma_fonction
<function ma_fonction at 0x036F8EB0>

On trouve entre les crochets :

<nom du type nom de l’objet at adresse de l’objet>

On peut aussi tester :

>>> type(ma_fonction)
<type 'function'>

Et puisque une fonction est un objet, on peut l’utiliser comme une variable, lui donner plusieurs noms :

>>> meme_fonction = ma_fonction
>>> meme_fonction
<function meme_fonction at 0x036F8EB0>

ma_fonction  et meme_fonction  sont deux noms différents pour une seule et même fonction (même adresse).


Les arguments

On peut passer des arguments à une fonction sous deux formes :

  • sans mot clef (ou positionnels) (non-keyword arguments ou positional arguments) : ils sont ordonnés, comme dans une liste
  • avec mot clef (keyword arg) : ils possèdent une clef (un nom), comme dans un dictionnaire, et ne sont pas ordonnés
def ma_fonction(arg1, arg2, karg1 = "e", karg2 = 5):
   print(arg1, arg2, karg1, karg2)

Dans cet exemple, arg1  et arg2  sont des arguments positionnels, sans mot clef : ils sont obligatoires !

Alors que karg1  et karg2  sont des arguments avec mot clef : ils sont facultatifs, possèdent une valeur par défaut, et on peut les faire passer dans le désordre (mais obligatoirement après tous les arguments positionnels !)

Tous ces appels à ma_fonction()  sont valides :

>>> ma_fonction(1, "oui", karg1 = "ISN", karg2 = 0)
1 'oui' 'ISN' 0
>>> ma_fonction(1, "oui", "ISN", 0)
1 'oui' 'ISN' 0
>>> ma_fonction(1, "oui", karg2 = 0, karg1 = "ISN")
1 'oui' 'ISN' 0
>>> ma_fonction(1, "oui", karg1 = "ISN")
1 'oui' 'ISN' 5
>>> ma_fonction(1, "oui")
1 'oui' 'e' 5

En revanche ces appels provoquent une erreur :

>>> ma_fonction(1, karg1 = "ISN", "oui",  karg2 = 0)
SyntaxError: non-keyword arg after keyword arg
>>> ma_fonction(1, karg1 = "ISN", karg2 = 0)
Traceback (most recent call last):
 File "<pyshell#20>", line 1, in <module>
 ma_fonction(1, karg1 = "ISN", karg2 = 0)
TypeError: ma_fonction() missing 1 required positional argument: 'arg2'

# avant python 3.4 :
TypeError: ma_fonction() takes at least 2 arguments (3 given)
>>> ma_fonction(1, "oui", karg1 = "ISN", karg3 = 0)
Traceback (most recent call last):
 File "<pyshell#21>", line 1, in <module>
 ma_fonction(1, "oui", karg1 = "ISN", karg3 = 0)
TypeError: ma_fonction() got an unexpected keyword argument 'karg3'

Exercice :

  • Traduire en Français ces messages d’erreur et expliquer ce qui ne va pas.

Variable locale, variable globale

Exercice :

  • Tester la suite d’instructions suivantes :
x = 0
def f(y):
   x = 1
   return y

f(2)
print(x)
  • Simuler le comportement à l’aide de PythonTutor :
Quelle(s) conclusion(s) peut on en tirer ?

Toute variable définie à l’intérieur du corps d’une fonction, n’est accessible qu’à la fonction elle-même. On la qualifie de variable locale à la fonction.

Une variable définie à l’extérieur de toute fonction sera quant à elle appelée variable globale.

Si une variable locale porte le même nom qu’une variable globale, cette dernière sera ignorée pendant l’exécution de la fonction.

Une variable globale (si aucune autre variable locale ne porte le même nom) peut être lue à l’intérieur d’une fonction.

Mais pour qu’elle puisse y être modifiée, il faut utiliser la déclaration global  en début de définition de la fonction.

x = 0
def f(y):
   global x
   x = 1
   return y

f(2)
print(x)

A la fin de l’exécution de la fonction, les variables locales sont détruites (ramasse-miettes).

def f(y):
   var_locale = 1
   return y

f(2)
print(var_locale)

Fonctions lambda

Une écriture parfois intéressante quand le corps d’une fonction est court :

def f(x):
   return x*2

peut s’écrire avec une fonction lambda :

f = lambda x: x*2

Exercice :

  • Écrire sous forme « lambda » la fonction div_euclid()  réalisée plus haut.

Aide d’une fonction

On a vu dans l’introduction à python qu’une fonction pouvait avoir une aide, indiquant ce que fait et comment utiliser une fonction.

>>> import random
>>> help(random.random)
Help on built-in function random:

random(...)
    random() -> x in the interval [0, 1).

Les fonctions définies par l’utilisateur peuvent aussi en avoir une :

def ma_fonction(x, y):
   """ Fonction qui calcule x**y
   """
   return x**y
help(ma_fonction)
Help on function ma_fonction in module __main__:

ma_fonction(x, y)
    Fonction qui calcule x**y

Fonctions récursives

Une fonction est qualifiée de récursive si elle s’appelle elle-même.

Par exemple, cette fonction qui permet de calculer \(x^y\) (\(y\) étant supposé > 0) :

def puissance(x, y):
   if y > 0 :                        # Si y > 0 alors …
      return x * puissance(x, y-1)   # auto appel de la fonction
   else :                            # Sinon …
      return 1                       # Arrêt de la récursion

print(puissance(3,8))

ATTENTION : une fonction récursive sans condition d’arrêt ne s’arrête jamais. En pratique Python prévoit une profondeur de récursion maximum (par défaut 1000, mais modifiable), mais l’atteindre provoque une erreur, et surtout témoigne d’une faute de programmation.

Il existe toujours une façon non récursive de réaliser une fonction donnée.

Écrire une fonction sous forme récursive est souvent plus naturel. En revanche, les grandes profondeurs de récursion peuvent solliciter fortement la mémoire et rendre son exécution plus lente.

Exercice :

  • Écrire sous forme récursive la fonction : \(factorielle:x \rightarrow x!\)

 


 

Dépôt de fichier réponse

Vous aimerez aussi...

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *