{"cells": [{"cell_type": "markdown", "metadata": {}, "source": ["# 1A.2 - Classes, h\u00e9ritage\n", "\n", "L'h\u00e9ritage permet de r\u00e9\u00e9crire certaines parties du code sans pour autant enlever les anciennes versions toujours utilis\u00e9es."]}, {"cell_type": "code", "execution_count": 1, "metadata": {}, "outputs": [{"data": {"text/html": ["
run previous cell, wait for 2 seconds
\n", ""], "text/plain": [""]}, "execution_count": 2, "metadata": {}, "output_type": "execute_result"}], "source": ["from jyquickhelper import add_notebook_menu\n", "add_notebook_menu()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Qu'est-ce que l'h\u00e9ritage ?\n", "\n", "La s\u00e9ance pr\u00e9c\u00e9dente a montr\u00e9 comment fonctionnait une classe, comment elle s'\u00e9crivait. Cette s\u00e9ance est \u00e0 propos de l'_h\u00e9ritage_ qui est une propri\u00e9t\u00e9 des langages objets. Elle est utile par exemple lorsqu'on doit \u00e9crire plusieurs versions d'un m\u00eame algorithme et qu'une petite partie seulement change d'une version \u00e0 l'autre.\n", "\n", "Supposons que vous ayez un algorithme constitu\u00e9 de trois fonctions plus une derni\u00e8re qui appelle les trois autres dans le bon ordre. On d\u00e9sire cr\u00e9er une version pour laquelle une des trois fonctions seulement est modifi\u00e9e."]}, {"cell_type": "code", "execution_count": 2, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Version1.fonction1 0\n", "Version1.fonction2 0\n", "Version1.fonction3 0\n"]}], "source": ["class Version1:\n", " def __init__(self, p):\n", " self.p = p\n", " def fonction1(self):\n", " print(\"Version1.fonction1\", self.p)\n", " def fonction2(self):\n", " print(\"Version1.fonction2\", self.p)\n", " def fonction3(self):\n", " print(\"Version1.fonction3\", self.p)\n", " def fonction_finale(self):\n", " self.fonction1()\n", " self.fonction2()\n", " self.fonction3()\n", " \n", "v = Version1(0)\n", "v.fonction_finale()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["On souhaite changer la fonction ``fonction2`` sans modifier la classe ``Version1`` et en \u00e9crivant le moins possible de code."]}, {"cell_type": "code", "execution_count": 3, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["Version1.fonction1 0\n", "Version2.fonction2 1\n", "Version1.fonction3 0\n"]}], "source": ["class Version2(Version1):\n", " def fonction2(self):\n", " print(\"Version2.fonction2\", self.p+1)\n", "\n", "v = Version2(0)\n", "v.fonction_finale()"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Le langage a compris qu'on avait chang\u00e9 une fonction et il s'en sert dans la seconde classe. Pour que cela fonctionne, il faut n\u00e9anmoins respecter une contrainte essentielle : la fonction remplac\u00e9e (ou surcharg\u00e9e) doit accepter les m\u00eames param\u00e8tres et retourner le m\u00eame type de r\u00e9sultat. Cette contrainte n'est pas obligatoire en Python mais elle l'est dans la plupart des langages. Il est conseill\u00e9 de la respecter."]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Exercice 1 : pi\u00e8ce normale\n", "\n", "On cr\u00e9er une classe ``Piece`` qui contient deux m\u00e9thodes : une m\u00e9thode ``tirage_aleatoire`` et une m\u00e9thode qui appelle la pr\u00e9c\u00e9dente pour faire une moyenne sur $n$ tirages."]}, {"cell_type": "code", "execution_count": 4, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["0\n"]}], "source": ["import random\n", "\n", "class Piece:\n", " def tirage_aleatoire(self, precedent):\n", " return random.randint(0,1)\n", " def moyenne_tirage(self, n):\n", " # ....\n", " return 0 # \u00e0 remplacer\n", "\n", "p = Piece()\n", "print(p.moyenne_tirage(100))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Exercice 2 : pi\u00e8ce truqu\u00e9e\n", "\n", "Le param\u00e8tre ``precedent`` est inutile dans cette premi\u00e8re version mais on suppose maintenant que le joueur qui joue est un tricheur. Lorsqu'il perd, il joue une pi\u00e8ce truqu\u00e9e le coup d'apr\u00e8s pour laquelle la probabilit\u00e9 d'avoir 1 est de 0,7. On veut impl\u00e9menter cela avec une classe ``PieceTruquee``."]}, {"cell_type": "code", "execution_count": 5, "metadata": {"collapsed": true}, "outputs": [], "source": ["import random\n", "\n", "class PieceTruquee(Piece):\n", " # ......\n", " pass"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Pour choisir de faire telle ou telle avec une probabilit\u00e9 de 0,7, on peut \u00e9crire :"]}, {"cell_type": "code", "execution_count": 6, "metadata": {"collapsed": true}, "outputs": [], "source": ["if random.random() <= 0.7 :\n", " # ... faire une chose avec la probabilit\u00e9 0.7\n", " pass\n", "else :\n", " # ... faire une autre chose avec la probabilit\u00e9 0.3\n", " pass"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Utiliser des m\u00e9thodes de la classe m\u00e8re"]}, {"cell_type": "markdown", "metadata": {}, "source": ["Lorsqu'on change une fonction, on a parfois juste d'un petit changement par rapport \u00e0 la m\u00e9thode pr\u00e9c\u00e9dente qu'il faut pouvoir appeler. Si on reprend l'exemple pr\u00e9c\u00e9dent, on modifie la m\u00e9thode ``tirage_aleatoire`` pour retourner l'autre valeur :"]}, {"cell_type": "code", "execution_count": 7, "metadata": {}, "outputs": [{"data": {"text/plain": ["1"]}, "execution_count": 8, "metadata": {}, "output_type": "execute_result"}], "source": ["class PieceTruquee(Piece):\n", " def tirage_aleatoire(self, precedent):\n", " return 1 - Piece.tirage_aleatoire(self, precedent)\n", "p = PieceTruquee()\n", "p.tirage_aleatoire(0) "]}, {"cell_type": "markdown", "metadata": {}, "source": ["Une autre \u00e9criture possible est la suivante avec le mot-cl\u00e9 [super](https://docs.python.org/3.4/library/functions.html#super) :"]}, {"cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [{"data": {"text/plain": ["0"]}, "execution_count": 9, "metadata": {}, "output_type": "execute_result"}], "source": ["class PieceTruquee(Piece):\n", " def tirage_aleatoire(self, precedent):\n", " return 1 - super().tirage_aleatoire(precedent)\n", "p = PieceTruquee()\n", "p.tirage_aleatoire(0)"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Exercice 3 : Pi\u00e8ce mixte\n", "\n", "Ecrire une classe ``PieceTruqueeMix`` qui appelle al\u00e9atoiremnt soit ``Piece.tirage_aleatoire`` soit ``PieceTruquee.tirage_aleatoire``."]}, {"cell_type": "code", "execution_count": 9, "metadata": {"collapsed": true}, "outputs": [], "source": []}, {"cell_type": "markdown", "metadata": {}, "source": ["### Autre construction avec des fonctions\n", "\n", "La cr\u00e9ation de classe peut sembler fastidieuse. Une autre solution est l'utilisation de fonction comme param\u00e8tre d'une autre fonction :"]}, {"cell_type": "code", "execution_count": 10, "metadata": {}, "outputs": [{"name": "stdout", "output_type": "stream", "text": ["0.49\n", "0.59\n"]}], "source": ["def moyenne_tirage(n, fonction):\n", " \"\"\"\n", " cette fonction fait la moyenne des r\u00e9sultats produits par la fonction pass\u00e9e en argument\n", " ce texte appara\u00eet d\u00e8s qu'on \u00e9crit help(moyenne_tirage) (ou moyenne_tirage? dans un notebook)\n", " \"\"\"\n", " tirage = [ ]\n", " for i in range (n) :\n", " precedent = tirage[-1] if i > 0 else None\n", " tirage.append( fonction (precedent) )\n", " s = sum(tirage)\n", " return s * 1.0 / len(tirage)\n", " \n", "print (moyenne_tirage(100, lambda v : random.randint(0,1) ))\n", " \n", "def truquee (precedent) :\n", " if precedent == None or precedent == 1 :\n", " return random.randint(0,1)\n", " else :\n", " return 1 if random.randint(0,9) >= 3 else 0\n", " \n", "print(moyenne_tirage(100, truquee ))"]}, {"cell_type": "markdown", "metadata": {}, "source": ["### Exercice 4 : pi\u00e8ce mixte avec des fonctions\n", "\n", "Comment utiliser les fonctions dans le cas de la pi\u00e8ce ``PieceTruqueeMix`` ?"]}, {"cell_type": "code", "execution_count": 11, "metadata": {"collapsed": true}, "outputs": [], "source": []}], "metadata": {"kernelspec": {"display_name": "Python 3", "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.6.1"}}, "nbformat": 4, "nbformat_minor": 2}