{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Fonctions" ] }, { "cell_type": "code", "execution_count": 28, "metadata": {}, "outputs": [ { "data": { "text/html": [ "
run previous cell, wait for 2 seconds
\n", "" ], "text/plain": [ "" ] }, "execution_count": 28, "metadata": {}, "output_type": "execute_result" } ], "source": [ "\n", "# Afficher la table des matières\n", "\n", "from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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 `:`.\n", "Le code suivant, avec un niveau d'indentation représente le corps de la fonction." ] }, { "cell_type": "code", "execution_count": 29, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def droite (x):\n", " print(2*x+1)" ] }, { "cell_type": "code", "execution_count": 30, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "5\n" ] } ], "source": [ "droite (2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 31, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def droite (x):\n", " \"\"\" Ecrit le res. 2x+1 \"\"\"\n", " print(2*x+1) " ] }, { "cell_type": "code", "execution_count": 32, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Help on function droite in module __main__:\n", "\n", "droite(x)\n", " Ecrit le res. 2x+1\n", "\n" ] } ], "source": [ "help(droite)" ] }, { "cell_type": "code", "execution_count": 33, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "' Ecrit le res. 2x+1 '" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" } ], "source": [ "droite.__doc__" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Les fonctions qui renvoient une valeur utilisent le mot-clé `return`" ] }, { "cell_type": "code", "execution_count": 34, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def droite (x):\n", " \"\"\" Renvoie le res . 2x+1 \"\"\"\n", " return 2*x+1" ] }, { "cell_type": "code", "execution_count": 35, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "9" ] }, "execution_count": 35, "metadata": {}, "output_type": "execute_result" } ], "source": [ "droite(4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On peut retourner plusieurs valeurs en utilisant des virgules (un tuple\n", "est renvoyé)" ] }, { "cell_type": "code", "execution_count": 36, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def puissance(x):\n", " \"\"\"\n", " Retourne certaines puissance de x\n", " \"\"\"\n", " return x ** 2, x ** 3, x ** 4" ] }, { "cell_type": "code", "execution_count": 37, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(4, 8, 16)" ] }, "execution_count": 37, "metadata": {}, "output_type": "execute_result" } ], "source": [ "puissance(2)" ] }, { "cell_type": "code", "execution_count": 38, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "16\n" ] } ], "source": [ "x2, x3, x4 = puissance(2)\n", "\n", "print(x4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Les arguments par défaut et mots clés" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "On peut donner des valeurs par défaut aux arguments que la fonction prend en entrée :" ] }, { "cell_type": "code", "execution_count": 39, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def mafonction(x, p=2, debug=False):\n", " if debug:\n", " print(\"Evaluer mafonction pour x = \" + str(x) + \" en utilisant un exposant p = \" + str(p))\n", " return x**p" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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 :" ] }, { "cell_type": "code", "execution_count": 40, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "16" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mafonction(4)" ] }, { "cell_type": "code", "execution_count": 41, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Evaluer mafonction pour x = 4 en utilisant un exposant p = 2\n" ] }, { "data": { "text/plain": [ "16" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mafonction(4, debug=True)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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." ] }, { "cell_type": "code", "execution_count": 42, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Evaluer mafonction pour x = 14 en utilisant un exposant p = 2\n" ] }, { "data": { "text/plain": [ "196" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mafonction(p=2, debug=True, x=14)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Fonctions de manipulation de séquences\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " #### Fonction : filter" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Applique la fonction passée en premier argument sur chacun des\n", "éléments de la séquence passée en second argument et retourne une\n", "nouvelle liste qui contient tous les éléments de la séquence pour\n", "lesquels la fonction a retourné une valeur vrai." ] }, { "cell_type": "code", "execution_count": 43, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[1, 3, 5]" ] }, "execution_count": 43, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def funct1 (val ):\n", " return val > 0\n", "list(filter( funct1 , [1, -2, 3, -4, 5]))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " #### Fonction : map" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "applique la fonction passée en premier argument sur chacun des\n", "éléments de la ou des séquences passées en paramètre" ] }, { "cell_type": "code", "execution_count": 44, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[5, 7, 9]" ] }, "execution_count": 44, "metadata": {}, "output_type": "execute_result" } ], "source": [ "def somme (x,y):\n", " return x+y\n", "L4= map(somme ,[1 , 2, 3], [4, 5, 6])\n", "list(L4)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "**Remarque :** map peut être beaucoup plus rapide qu’une boucle for" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " #### Fonction : [zip](https://docs.python.org/3/library/functions.html#zip)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "permet de parcourir plusieurs séquences en parallèle" ] }, { "cell_type": "code", "execution_count": 45, "metadata": { "collapsed": false }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "1 + 4 = 5\n", "2 + 5 = 7\n", "3 + 6 = 9\n" ] } ], "source": [ "for (x, y) in zip ([1 , 2, 3] ,[4 , 5, 6]) :\n", " print(x, '+', y, '=', x + y)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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 :" ] }, { "cell_type": "code", "execution_count": 46, "metadata": { "collapsed": false, "scrolled": true }, "outputs": [ { "data": { "text/plain": [ "(['a', 'b', 'er', 'gh'], [1, 2, 1, 2])" ] }, "execution_count": 46, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hist = {'a': 1, 'b': 2, 'er': 1, 'gh': 2}\n", "cles = []\n", "vals = []\n", "for k, v in hist.items():\n", " cles.append(k)\n", " vals.append(v)\n", "cles, vals" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cela devient :" ] }, { "cell_type": "code", "execution_count": 47, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(('a', 'b', 'er', 'gh'), (1, 2, 1, 2))" ] }, "execution_count": 47, "metadata": {}, "output_type": "execute_result" } ], "source": [ "hist = {'a': 1, 'b': 2, 'er': 1, 'gh': 2}\n", "cles, vals = zip(*hist.items())\n", "cles, vals" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Petite différence, `cles`, `vals` sont sous forme de [tuple](https://docs.python.org/3.5/library/stdtypes.html?highlight=tuple#tuple) mais cela reste très élégant." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ " #### Fonction : reduce" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Réduit une séquence par l’application récursive d’une fonction sur chacun de ses éléments.\n", " - La fonction passée comme premier paramètre doit prendre deux arguments\n", " - La fonction reduce prend un troisième paramètre optionnel qui est la valeur initiale du calcul\n", " - Importer la fonction reduce à partir du module functools : from functools import reduce" ] }, { "cell_type": "code", "execution_count": 48, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "15" ] }, "execution_count": 48, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from functools import reduce\n", "reduce(somme , [1, 2, 3, 4, 5])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Fonctions sans nom (mot-clé lambda)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Sous Python, vous pouvez également créer des fonctions sans nom, en utilisant le mot-clé `lambda` :" ] }, { "cell_type": "code", "execution_count": 49, "metadata": { "collapsed": true }, "outputs": [], "source": [ "f1 = lambda x: x**2\n", " \n", "# est équivalent à \n", "\n", "def f2(x):\n", " return x**2" ] }, { "cell_type": "code", "execution_count": 50, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "(4, 4)" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "f1(2), f2(2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Les lambda expressions permettent une syntaxe plus légère pour déclarer une fonction simple" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Cette technique est utile par exemple lorsque nous voulons passer une fonction simple comme argument à une autre fonction, comme ceci :" ] }, { "cell_type": "code", "execution_count": 51, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 51, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# map est une fonction intégrée de python\n", "map(lambda x: x**2, range(-3,4))" ] }, { "cell_type": "code", "execution_count": 52, "metadata": { "collapsed": false }, "outputs": [ { "data": { "text/plain": [ "[9, 4, 1, 0, 1, 4, 9]" ] }, "execution_count": 52, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Dans python 3 nous pouvons utiliser `list (...)` pour convertir l'itérateur en une liste explicite\n", "list(map(lambda x: x**2, range(-3,4)))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Bon à connaître" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### **kwargs : Passer plusieurs arguments à une fonction en Python\n", "\n", "Il peut arriver que vous ne connaissiez pas les arguments que vous passerez à une fonction. Dans ce cas, utilisez `**kwargs`.\n", "\n", "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.\n", "\n", "Une fois l'argument `**kwargs` passé, vous pouvez le traiter comme un dictionnaire Python.\n" ] }, { "cell_type": "code", "execution_count": 54, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'a': 1, 'b': 2}\n", "4\n", "5\n" ] } ], "source": [ "parameters = {'a': 1, 'b': 2}\n", "\n", "def example(c, **kwargs):\n", " print(kwargs)\n", " for val in kwargs.values():\n", " print(c + val)\n", "\n", "example(3, **parameters)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "#### Décorateur en Python\n", "\n", "Si vous voulez ajouter le même bloc de code à différentes fonctions en Python, le mieux c'est d'utiliser le décorateur.\n", "\n", "Dans le code ci-dessous, on crée un décorateur pour suivre le temps de la fonction `Salut`." ] }, { "cell_type": "code", "execution_count": 55, "metadata": {}, "outputs": [], "source": [ "import time \n", "\n", "def time_func(func):\n", " def wrapper():\n", " print(\"Cela se passe avant que la fonction soit appelée.\")\n", " start = time.time()\n", " func()\n", " print('Cela se produit après que la fonction soit appelée.')\n", " end = time.time()\n", " print('La durée est de', end - start, 's')\n", "\n", " return wrapper" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Maintenant, tout ce qu'il reste à faire est d'ajouter `@time_func` avant la fonction `Salut`." ] }, { "cell_type": "code", "execution_count": 56, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cela se passe avant que la fonction soit appelée.\n", "hello\n", "Cela se produit après que la fonction soit appelée.\n", "La durée est de 7.891654968261719e-05 s\n" ] } ], "source": [ "@time_func\n", "def Salut():\n", " print(\"hello\")\n", "\n", "Salut()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "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 :" ] }, { "cell_type": "code", "execution_count": 57, "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Cela se passe avant que la fonction soit appelée.\n", "Cela se produit après que la fonction soit appelée.\n", "La durée est de 0.00021314620971679688 s\n" ] } ], "source": [ "@time_func\n", "def func2():\n", " pass\n", "func2()" ] } ], "metadata": { "anaconda-cloud": {}, "interpreter": { "hash": "40d3a090f54c6569ab1632332b64b2c03c39dcf918b08424e98f38b5ae0af88f" }, "kernelspec": { "display_name": "Python [Root]", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.8.8" } }, "nbformat": 4, "nbformat_minor": 0 }