1.7. Fonctions

# Afficher la table des matières

from jyquickhelper import add_notebook_menu
add_notebook_menu()
run previous cell, wait for 2 seconds

Une fonction en Python est définie à l’aide du mot-clé def, suivi d’un nom de fonction, d’un ensemble d’arguments en entrée (ou pas) entre parenthèses () et de deux points :. Le code suivant, avec un niveau d’indentation représente le corps de la fonction.

def droite (x):
    print(2*x+1)
droite (2)
5

Optionnel, mais fortement recommandé, vous pouvez définir un “docstring”, qui est une description des fonctions. Le docstring doit figurer directement après la définition de la fonction, avant le code correspondant au corps de la fonction.

def droite (x):
    """ Ecrit le res. 2x+1 """
    print(2*x+1)        
help(droite)
Help on function droite in module __main__:

droite(x)
    Ecrit le res. 2x+1
droite.__doc__
' Ecrit le res. 2x+1 '

Les fonctions qui renvoient une valeur utilisent le mot-clé return

def droite (x):
    """ Renvoie le res . 2x+1 """
    return 2*x+1
droite(4)
9

On peut retourner plusieurs valeurs en utilisant des virgules (un tuple est renvoyé)

def puissance(x):
    """
    Retourne certaines puissance de x
    """
    return x ** 2, x ** 3, x ** 4
puissance(2)
(4, 8, 16)
x2, x3, x4 = puissance(2)

print(x4)
16

1.7.1. Les arguments par défaut et mots clés

On peut donner des valeurs par défaut aux arguments que la fonction prend en entrée :

def mafonction(x, p=2, debug=False):
    if debug:
        print("Evaluer mafonction pour x = " + str(x) + " en utilisant un exposant p = " + str(p))
    return x**p

Si nous ne fournissons pas une valeur de l’argument debug lors de l’appel de la fonction myfunc, elle prend par défaut la valeur fournie dans la définition de fonction :

mafonction(4)
16
mafonction(4, debug=True)
Evaluer mafonction pour x = 4 en utilisant un exposant p = 2
16

Si vous énumérez explicitement le nom des arguments dans les appels de fonction, ils n’ont pas besoin d’être dans le même ordre que dans la définition de la fonction. C’est ce qu’on appelle les arguments mot-clé, et est souvent très utile dans les fonctions qui nécessitent beaucoup d’arguments facultatifs.

mafonction(p=2, debug=True, x=14)
Evaluer mafonction pour x = 14 en utilisant un exposant p = 2
196

1.7.2. Fonctions de manipulation de séquences

1.7.2.1. Fonction : filter

Applique la fonction passée en premier argument sur chacun des éléments de la séquence passée en second argument et retourne une nouvelle liste qui contient tous les éléments de la séquence pour lesquels la fonction a retourné une valeur vrai.

def funct1 (val ):
    return val > 0
list(filter( funct1 , [1, -2, 3, -4, 5]))
[1, 3, 5]

1.7.2.2. Fonction : map

applique la fonction passée en premier argument sur chacun des éléments de la ou des séquences passées en paramètre

def somme (x,y):
    return x+y
L4= map(somme ,[1 , 2, 3], [4, 5, 6])
list(L4)
[5, 7, 9]

Remarque : map peut être beaucoup plus rapide qu’une boucle for

1.7.2.3. Fonction : zip

permet de parcourir plusieurs séquences en parallèle

for (x, y) in zip ([1 , 2, 3] ,[4 , 5, 6]) :
    print(x, '+', y, '=', x + y)
1 + 4 = 5
2 + 5 = 7
3 + 6 = 9

La fonction zip est très utile pour créer un dictionnaire. En effet, cela permet de raccourcir le code pour créer un dictionnaire à partir de clés et de valeurs séparés. Ca paraît bien plus long de créer les listes des clés et des valeurs. Et pourtant le code suivant peut être considérablement raccourci :

hist = {'a': 1, 'b': 2, 'er': 1, 'gh': 2}
cles = []
vals = []
for k, v in hist.items():
    cles.append(k)
    vals.append(v)
cles, vals
(['a', 'b', 'er', 'gh'], [1, 2, 1, 2])

Cela devient :

hist = {'a': 1, 'b': 2, 'er': 1, 'gh': 2}
cles, vals = zip(*hist.items())
cles, vals
(('a', 'b', 'er', 'gh'), (1, 2, 1, 2))

Petite différence, cles, vals sont sous forme de tuple mais cela reste très élégant.

1.7.2.4. Fonction : reduce

Réduit une séquence par l’application récursive d’une fonction sur chacun de ses éléments. - La fonction passée comme premier paramètre doit prendre deux arguments - La fonction reduce prend un troisième paramètre optionnel qui est la valeur initiale du calcul - Importer la fonction reduce à partir du module functools : from functools import reduce

from functools import reduce
reduce(somme , [1, 2, 3, 4, 5])
15

1.7.2.5. Fonctions sans nom (mot-clé lambda)

Sous Python, vous pouvez également créer des fonctions sans nom, en utilisant le mot-clé lambda :

f1 = lambda x: x**2
    
# est équivalent à 

def f2(x):
    return x**2
f1(2), f2(2)
(4, 4)

Les lambda expressions permettent une syntaxe plus légère pour déclarer une fonction simple

Cette technique est utile par exemple lorsque nous voulons passer une fonction simple comme argument à une autre fonction, comme ceci :

# map est une fonction intégrée de python
map(lambda x: x**2, range(-3,4))
<map at 0x10e8f0af0>
# Dans python 3 nous pouvons utiliser `list (...)` pour convertir l'itérateur en une liste explicite
list(map(lambda x: x**2, range(-3,4)))
[9, 4, 1, 0, 1, 4, 9]

1.7.3. Bon à connaître

1.7.3.1. **kwargs : Passer plusieurs arguments à une fonction en Python

Il peut arriver que vous ne connaissiez pas les arguments que vous passerez à une fonction. Dans ce cas, utilisez **kwargs.

Les **kwargs vous permettent de passer plusieurs arguments à une fonction en utilisant un dictionnaire. Dans l’exemple ci-dessous, passer **{'a':1, 'b':2} à la fonction revient à passer a=1, b=1 à la fonction.

Une fois l’argument **kwargs passé, vous pouvez le traiter comme un dictionnaire Python.

parameters = {'a': 1, 'b': 2}

def example(c, **kwargs):
    print(kwargs)
    for val in kwargs.values():
        print(c + val)

example(3, **parameters)
{'a': 1, 'b': 2}
4
5

1.7.3.2. Décorateur en Python

Si vous voulez ajouter le même bloc de code à différentes fonctions en Python, le mieux c’est d’utiliser le décorateur.

Dans le code ci-dessous, on crée un décorateur pour suivre le temps de la fonction Salut.

import time 

def time_func(func):
    def wrapper():
        print("Cela se passe avant que la fonction soit appelée.")
        start = time.time()
        func()
        print('Cela se produit après que la fonction soit appelée.')
        end = time.time()
        print('La durée est de', end - start, 's')

    return wrapper

Maintenant, tout ce qu’il reste à faire est d’ajouter @time_func avant la fonction Salut.

@time_func
def Salut():
    print("hello")

Salut()
Cela se passe avant que la fonction soit appelée.
hello
Cela se produit après que la fonction soit appelée.
La durée est de 3.910064697265625e-05 s

Le décorateur rend le code propre et raccourcit le code répétitif. Si on veux regarder le temps d’une autre fonction, par exemple, func2(), on peut simplement utiliser :

@time_func
def func2():
    pass
func2()
Cela se passe avant que la fonction soit appelée.
Cela se produit après que la fonction soit appelée.
La durée est de 0.00013303756713867188 s