expert:python_objet
no way to compare when less than two revisions
Différences
Ci-dessous, les différences entre deux révisions de la page.
— | expert:python_objet [2018/11/17 12:53] (Version actuelle) – créée - modification externe 127.0.0.1 | ||
---|---|---|---|
Ligne 1: | Ligne 1: | ||
+ | ====== La programmation Orientée objet: Les bases avec python ====== | ||
+ | === NOTES === | ||
+ | Je ne vais pas m' | ||
+ | |||
+ | * [[expert: | ||
+ | |||
+ | == Pourquoi python? == | ||
+ | Ce tuto a pour objectif de vous faire apprendre les bases de la programmation orientée objet. Pour ce faire, il faut bien choisir un langage de programmation. | ||
+ | |||
+ | Python a des qualités qui en font le langage idéal pour commencer l' | ||
+ | * typage dynamique : on peut s' | ||
+ | * full-objet : on peut s' | ||
+ | * syntaxe simple | ||
+ | |||
+ | Enfin, python a beau être un langage didactique, ce n'est pas qu'un gadget scolaire, il est largement utilisé pour coder de vraies applications. | ||
+ | |||
+ | == Version de python pour ce tuto == | ||
+ | |||
+ | Pour le tuto, j' | ||
+ | |||
+ | La raison de ce choix est que c'est la version stable officielle de la debian actuelle. Par conséquent, | ||
+ | |||
+ | J' | ||
+ | |||
+ | ===== Qu' | ||
+ | |||
+ | Je vous propose ici d' | ||
+ | |||
+ | La programmation orientée objet est un paradigme de programmation. C'est un style de programmation qui va conditionner la manière de traiter les problèmes. Le paradigme objet est orienté vers l' | ||
+ | |||
+ | ==== Des classes et des objets ==== | ||
+ | |||
+ | Une classe est une sorte de modèle sur lequel on peut se baser pour construire les objets. | ||
+ | |||
+ | Par exemple, prenons un cercle. Je vais définir une classe cercle avec une variable pour le rayon: R. La classe cercle va me servir pour fabriquer des objets cercles, autant que je veux: | ||
+ | < | ||
+ | class Cercle(): | ||
+ | R = 2 | ||
+ | # ici, je définis la class Cercle | ||
+ | |||
+ | |||
+ | monCercle = Cercle() | ||
+ | # Là, je crée un objet à partir de la classe Cercle | ||
+ | </ | ||
+ | Les lignes qui commencent par # sont des commentaires, | ||
+ | ==== Les méthodes ==== | ||
+ | |||
+ | On peut les appeler indiféramment méthode, procédure ou fonction. En python, cela n'a pas d' | ||
+ | |||
+ | Nous pouvons rajouter dans notre classe " | ||
+ | |||
+ | La procédure est ce qui transforme le contenu de la variable R en variable P. Ici, c'est simple, c'est le calcul: P = 2*3.14*R : | ||
+ | < | ||
+ | # definition de la classe: | ||
+ | class Cercle(): | ||
+ | R = 2 | ||
+ | |||
+ | # ma méthode: | ||
+ | def peri(self): | ||
+ | # variable P interne à la fonction: | ||
+ | P = 2*3.14*self.R | ||
+ | return P | ||
+ | </ | ||
+ | ===== De quoi a-t-on besoin pour ce tuto? ===== | ||
+ | |||
+ | === Python, bien sûr! === | ||
+ | |||
+ | Il vous faut installer python, bien évidemment. Il y a de fortes chance qu'il soit déjà présent sur votre système car de nombreux outils utilisent python. Vous avez besoin de la version 2.6 et c'est tout. | ||
+ | |||
+ | === Un émulateur de terminal bien configuré === | ||
+ | |||
+ | L' | ||
+ | |||
+ | Je ne recommande pas es outils qui incluent trop de choses inutiles. La règle pour un bon émulateur est qu'il se contente d' | ||
+ | |||
+ | Il est également important de le rendre visuellement confortable, | ||
+ | |||
+ | === Un interpréteur avancé: ipython === | ||
+ | |||
+ | Python inclut par défaut deux interpréteurs: | ||
+ | * L' | ||
+ | * L' | ||
+ | |||
+ | Toutefois, il est plus pratique d' | ||
+ | |||
+ | Pour les besoin du tuto, on va commencer en console (pourquoi? parce qu'on est des durs!) et un interpréteur avancé existe: ipython | ||
+ | |||
+ | Une de fonctionnalités intéressantes de ipython est d' | ||
+ | |||
+ | Allez le chercher avec votre gestionnaire de paquet favori et installez-le! | ||
+ | |||
+ | === Un éditeur de texte === | ||
+ | |||
+ | En programmation, | ||
+ | |||
+ | L' | ||
+ | |||
+ | C'est donc le momment de faire un choix: soit vous êtes un vrai dur de dur et vous apprennez à utiliser un éditeur de texte en console: vim, emacs, etc; soit vous choisissez un éditeur graphique: geany, kate, etc. | ||
+ | |||
+ | ===== On se lance? ===== | ||
+ | |||
+ | Assez de bavardage, on va s' | ||
+ | |||
+ | Vous avez besoin d' | ||
+ | |||
+ | < | ||
+ | |||
+ | Et nous voilà enfin au cœur du sujet. Quelques petites choses à savoir sur la syntaxe python: | ||
+ | * Les sauts de ligne font partie du langage | ||
+ | * L' | ||
+ | * On passe une ligne après une méthode | ||
+ | * On passe deux lignes après avoir déclarer une classe | ||
+ | Ipython mettra automatiquement les indentations et se comportera de la manière attendue si vous respectez ces règles. | ||
+ | |||
+ | Pour le quitter, comme pour l' | ||
+ | ===== Jouons avec les classes et les objets ===== | ||
+ | |||
+ | Je vais utliser une notation [[expert: | ||
+ | |||
+ | ==== Une classe ==== | ||
+ | |||
+ | Reprenons notre classe cercle: | ||
+ | < | ||
+ | +------------------+ | ||
+ | | Cercle | ||
+ | +------------------| | ||
+ | | R = 2 | | ||
+ | +------------------| | ||
+ | | | | ||
+ | +------------------+ | ||
+ | </ | ||
+ | La première case représente le nom de la classe. La seconde les variables de la classe. La troisièmes les méthodes de la classe. Pour l' | ||
+ | |||
+ | Le code qui va correspondre à ce modèle: | ||
+ | < | ||
+ | class Cercle(): | ||
+ | R = 2 | ||
+ | </ | ||
+ | La méthode class qu'on utilise ici sert à créer... des classes. On donne ensuite le nom de la classe et on laisse les parenthèses vide, on s'en servira plus tard. Sans oublier les doubles points. | ||
+ | |||
+ | À la ligne, notez l' | ||
+ | |||
+ | N' | ||
+ | |||
+ | === Un peu d' | ||
+ | |||
+ | Une des particularités très appréciée de python est l' | ||
+ | |||
+ | Nous allons donc demander à l' | ||
+ | < | ||
+ | dir(Cercle) | ||
+ | help(Cercle)</ | ||
+ | Touche q pour quiter l' | ||
+ | |||
+ | La directive type() renvoie ce résultat: <type ' | ||
+ | |||
+ | dir() vous renvoie aussi un peu plus d' | ||
+ | |||
+ | ==== Un objet ==== | ||
+ | |||
+ | On dit aussi " | ||
+ | |||
+ | Maintenant que nous avons notre classe, créons un objet à partir de cette classe: | ||
+ | < | ||
+ | Facile, non? Vous pouvez essayer encore les directives type(), dir() et help() | ||
+ | Pour connaitre la valeur d'un élément, vous pouvez entrer simplement: | ||
+ | < | ||
+ | Dans un vrai programme, vous ne ferez pas cela, cela fonctionne en interpreteur par facilité mais à l' | ||
+ | < | ||
+ | |||
+ | === La méthode spéciale __init__() === | ||
+ | Maintenant qu'on sait créer une classe et un objet, on va vouloir créer des cercle de tailles différentes (pas uniquement des cercle de 2). On peut changer la variable R comme ceci: | ||
+ | < | ||
+ | Cependant, il serait sans doute plus malin de déterminer la taille du cercle dès la création de l' | ||
+ | < | ||
+ | class Cercle(): | ||
+ | R = 0 | ||
+ | |||
+ | def __init__(self, | ||
+ | self.R = monRayon | ||
+ | </ | ||
+ | L' | ||
+ | |||
+ | Ensuite, le code de la méthode: nous allons attribuer à la variable R de l' | ||
+ | |||
+ | Créons donc notre nouvel objet: | ||
+ | < | ||
+ | Le tour est joué! | ||
+ | |||
+ | == Note == | ||
+ | Python est un langage très très souple, il permet de récrire les classes, de recréer les objets et de modifier les variables à la volée. | ||
+ | |||
+ | Dans l' | ||
+ | |||
+ | ==== Une méthode ==== | ||
+ | |||
+ | Essayons maintenant de faire notre propre méthode à nous tout seul. Cette méthode va calculer le périmètre du cercle: 2*pi*R | ||
+ | |||
+ | === Importons pi! === | ||
+ | |||
+ | Comme on est des durs, on va pas se contenter de noter 3.14 à chaque fois qu'on a besoin de pi, hein? Il se trouve que pi fait partie d'un module python appelé " | ||
+ | < | ||
+ | Maintenant, essayez: | ||
+ | < | ||
+ | Ceci nous permet de voire comment on importe dans l' | ||
+ | < | ||
+ | À ce moment là, on utilise pi de la manière suivante: | ||
+ | < | ||
+ | |||
+ | === Calculons le périmètre === | ||
+ | |||
+ | Ouïe! une formule... Allez, je vous la donne: 2*pi*R | ||
+ | |||
+ | Ajoutons donc notre méthode à notre code existant: | ||
+ | < | ||
+ | class Cercle(): | ||
+ | R = 0 | ||
+ | |||
+ | def __init__(self, | ||
+ | self.R = monRayon | ||
+ | |||
+ | def peri(self): | ||
+ | P = 2*pi*self.R | ||
+ | return P | ||
+ | </ | ||
+ | Notez qu' | ||
+ | |||
+ | La directive return indique que la méthode doit renvoyer la valeur de P. On aurait aussi pu écrire: | ||
+ | |||
+ | < | ||
+ | |||
+ | Ceci parait plus simple de prime abord mais il vaut mieux toujours prévoire que le code va se compliquer et définir ici une variable permettra par la suite de faire plusieurs opérations avec elle sans avoir à récrire plusieurs fois la formule. Par exemple, nous pourrions stocker P dans l' | ||
+ | < | ||
+ | def peri(self): | ||
+ | P = 2*pi*self.R | ||
+ | self.P = P | ||
+ | return P | ||
+ | </ | ||
+ | |||
+ | Voici à quoi ressemble notre modèle, maintenant: | ||
+ | < | ||
+ | +------------------+ | ||
+ | | Cercle | ||
+ | +------------------| | ||
+ | | R = 2 | | ||
+ | +------------------| | ||
+ | | init(monRayon) | ||
+ | | peri() | ||
+ | +------------------+ | ||
+ | </ | ||
+ | |||
+ | === Utilisons notre nouvelle méthode === | ||
+ | |||
+ | Pour cela, on va commencer par recréer monCercle: | ||
+ | < | ||
+ | print(monCercle.peri())</ | ||
+ | |||
+ | ===== La notion d' | ||
+ | |||
+ | ==== Note: le flux ==== | ||
+ | |||
+ | Je n'ai pas parlé jusqu' | ||
+ | |||
+ | ==== Héritage simple ==== | ||
+ | |||
+ | L' | ||
+ | |||
+ | Nous créons un jeu de rôle. L' | ||
+ | < | ||
+ | from random import randint | ||
+ | |||
+ | class Rerso(): | ||
+ | force = 0 | ||
+ | endur = 0 | ||
+ | |||
+ | def __init__(self): | ||
+ | self.force = randint(1, | ||
+ | self.endur = randint(1, | ||
+ | </ | ||
+ | Le code devrait vous paraître simple. Petite spécificité, | ||
+ | |||
+ | Notre jeu inclue deux races: les nains et les elfes. Les nains et les elfes sont des personnages, | ||
+ | < | ||
+ | from random import randint | ||
+ | |||
+ | class Perso(): | ||
+ | force = 0 | ||
+ | endur = 0 | ||
+ | |||
+ | |||
+ | class Nain(Perso): | ||
+ | barbe = 0 | ||
+ | |||
+ | def __init__(self): | ||
+ | self.barbe = randint (50,100) | ||
+ | self.force = randint(3, | ||
+ | self.endur = randint(4, | ||
+ | |||
+ | |||
+ | class Elf(Perso): | ||
+ | cheveux = 0 | ||
+ | |||
+ | def __init__(self): | ||
+ | self.cheveux = randint (50,100) | ||
+ | self.force = randint(2, | ||
+ | self.endur = randint(4, | ||
+ | </ | ||
+ | |||
+ | Comme la classe perso ne va plus nous servir à créer directement des personnage, on lui enlève son constructeur qui ne sert plus à rien. En revanche, on va pouvoir personaliser les constructeurs des classes filles. | ||
+ | |||
+ | Pour l' | ||
+ | |||
+ | Le modèle simplifié ressemble à ceci: | ||
+ | < | ||
+ | | ||
+ | +---------+ | ||
+ | | Perso |< | ||
+ | +---------+ | ||
+ | | +--------+ | ||
+ | +--------| | ||
+ | | ||
+ | </ | ||
+ | Maintenant, créez des instances des classe nain et elf et utilisez l' | ||
+ | < | ||
+ | gimli=Nain() | ||
+ | tafiole=Elf() | ||
+ | dir(gimli) | ||
+ | [' | ||
+ | </ | ||
+ | Vous voyez ici que l' | ||
+ | |||
+ | Vous pouvez maintenant vous amuser à pousser un peu le concept, rajouter des nouveaux attributs à ces classes, créer des nouvelles races, etc. | ||
+ | ==== Héritage multiple ==== | ||
+ | |||
+ | Python permet l' | ||
+ | |||
+ | < | ||
+ | class Papa(): | ||
+ | SEXE = " | ||
+ | |||
+ | |||
+ | class Maman(): | ||
+ | SEXE = " | ||
+ | |||
+ | |||
+ | class Enfant(Papa, | ||
+ | pass | ||
+ | </ | ||
+ | |||
+ | Ici, on illustre bien le problème que cela pose. Les deux classes ont une variable constante qui porte le même nom: de laquelle va hériter l' | ||
+ | |||
+ | Pour résoudre ce problème, on peut: | ||
+ | * Créer une méthode pour fusionner les eléments complexes (les fonctions, par exemple) | ||
+ | * Utiliser la surcharge | ||
+ | ==== La surcharge d' | ||
+ | |||
+ | La surcharge consiste à redéfinir un élement. Quand une classe hérite d'une autre, vous pouvez vouloir modifier une une variable ou une fonction. On le fait simpement en redéclarant celle-ci dans la classe fille: | ||
+ | |||
+ | < | ||
+ | Classe Papa(): | ||
+ | def dit(): | ||
+ | print(" | ||
+ | |||
+ | |||
+ | Classe enfant(Papa): | ||
+ | def dit(): | ||
+ | print(" | ||
+ | </ | ||
+ | |||
+ | |||
+ | ====== Aller plus loin avec python ====== | ||
+ | |||
+ | Pour aller plus loin, nous allons utiliser notre éditeur de texte pour écrire les programmes. Nous continuerons tout de méme à employer l' | ||
+ | |||
+ | ===== Quelques recommandations ===== | ||
+ | |||
+ | ==== Les bonnes pratiques ==== | ||
+ | |||
+ | === KISS === | ||
+ | |||
+ | Keep It Simple, Stupid! (Laisse ça simple, imbécile!) | ||
+ | |||
+ | Souvenez-vous du rasoir d' | ||
+ | |||
+ | === Syntaxe === | ||
+ | |||
+ | En python, l' | ||
+ | |||
+ | < | ||
+ | # ou encore | ||
+ | class Perso | ||
+ | { | ||
+ | int $force;int $endu; | ||
+ | } | ||
+ | </ | ||
+ | |||
+ | Seulement, on n'est que rarement seul à travailler sur un projet. Quand le code commence à devenir vraiment compliqué (imaginez la tailles des classe si vous transcrivez la totalité des règle de AD&D), si chacun utilise son propre style, cela devient vite invivable. Croyez-moi, il n'y a rien de plus agaçant que de devoir reprendre du code en vrac! | ||
+ | |||
+ | Dans les logiciels libres, c'est encore plus flagrant, l' | ||
+ | |||
+ | De plus, vous vous rendrez vite compte qu'on a nous aussi une capacité de mémorisation limitée. Quand on a le nez dans son programme, on sait bien évidemment à quoi correspond quoi. Mais on développe toujours plusieurs choses, on passe d'un projet à l' | ||
+ | |||
+ | C'est en tenant compte de ces habitudes que python a été créé. Le code python est ainsi toujours très lisible. En apprenant la programmation orientée objet avec python, vous prennez des bonnes habitudes. | ||
+ | |||
+ | Un certain nombre de conventions, | ||
+ | |||
+ | * Laisser deux lignes vides après une classe | ||
+ | * Un espace après une virgule | ||
+ | * Un espace de chaque côté des opérateurs logiques ( = != | & ) | ||
+ | * Utiliser quatre espaces au lieu d'une tabulation pour les indentations | ||
+ | * Pas d' | ||
+ | * Des lignes de 79 caractères (originellement, | ||
+ | |||
+ | === Conventions de nommage === | ||
+ | |||
+ | * Les classes : première lettre en majuscule, le reste en minuscule | ||
+ | * Les variables de préférence en minuscule sauf si cela vous permet de mieux l' | ||
+ | * Modules et packages en minuscule. | ||
+ | |||
+ | D'une manière générale, assurez-vous qu'il y ait une certaine cohérence dans les noms, que ceux-ci soient significatifs. Évitez d' | ||
+ | |||
+ | === Encapsulation des données === | ||
+ | |||
+ | L' | ||
+ | |||
+ | Si cela s' | ||
+ | |||
+ | Ces méthodes s' | ||
+ | |||
+ | Pour vous expliquer l' | ||
+ | < | ||
+ | classe Compteur(): | ||
+ | nb = 0 | ||
+ | |||
+ | def getNb(self): | ||
+ | nb = nb +1 | ||
+ | return nb | ||
+ | |||
+ | |||
+ | zigzag = compteur() | ||
+ | zigzag.getNb() | ||
+ | >1 | ||
+ | zigzag.getNb() | ||
+ | >2 | ||
+ | zigzag.getNb() | ||
+ | >3 | ||
+ | zigzag.nb | ||
+ | >3 | ||
+ | zigzag.nb | ||
+ | >3 | ||
+ | </ | ||
+ | Ici, c'est simple, on veut compter le nombre de fois que le programme accède à une variable. Si le programme accède directement à la variable, ça ne fonctionne pas. | ||
+ | |||
+ | === Importation === | ||
+ | |||
+ | Il existe différentes manières d' | ||
+ | < | ||
+ | Ici on importe uniquement la variable pi du module math | ||
+ | < | ||
+ | Ici, on importe le module math. Pour acceder à pi, il faudra procéder comme suit: | ||
+ | < | ||
+ | Ce n'est pas recommandé, | ||
+ | |||
+ | De la même façon: | ||
+ | < | ||
+ | Là, on peut toujour appeller tous les élements du module directement mais en plus de charger la mémoire, si vous faites ça sur plusieurs module, il est possible que les noms des éléments rentrent en conflit. Dans ce cas, c'est le dernier chargé qui écrase les autre mais je vous laisse imaginer le bazar. | ||
+ | |||
+ | D' | ||
+ | < | ||
+ | Il faudra par la suite utiliser le nom " | ||
+ | |||
+ | === Commentez! === | ||
+ | |||
+ | Les commentaires sont des éléments importants. Il ne font rien en eux-même mais permettent de s'y retrouver dans le code et donnent des informations utiles pour les autres programmeurs et pour vous-même. Un commentaire est une ligne qui commance par # | ||
+ | |||
+ | Il ne faut pas hésiter à en mettre à chaque fois que cela vous parait pertinent. | ||
+ | |||
+ | === Documentez! === | ||
+ | |||
+ | Vous avez découvert l' | ||
+ | |||
+ | Hé bien, une chose qui rend l' | ||
+ | |||
+ | Voici comment rajouter un element à la pydoc: | ||
+ | < | ||
+ | """ | ||
+ | Ici, je documente une fonction ou une classe | ||
+ | """ | ||
+ | </ | ||
+ | |||
+ | Inspirez-vous de la pydoc existante et que vous utilisez avec la commande help() | ||
+ | |||
+ | Tâchez de vous exprimer en anglais et de vérifier que votre anglais technique est correct. En anglais, c'est une convention. On va pas troller à propos de l' | ||
+ | |||
+ | ===== Créer vos propres modules et bibliothèques ===== | ||
+ | |||
+ | Une bibliothèque est un ensemble d' | ||
+ | |||
+ | Un module en revanche, est un composant actif qui vient se grefer au programme. | ||
+ | |||
+ | La différence entre module et bibliothèque python est presque philosophique. On peut dire encore package (correspond à la dénomination UML). Il n'y a pas de bibliothèque à proprement parler en python. | ||
+ | |||
+ | Tout fichier python est en lui-même un module, vous pouvez l' | ||
+ | |||
+ | Pour créer un module plus important, on peut stocker plusieurs fichier python dans un répertoire. On rajoute alors un fichier __init__.py au même niveau. Ce fichier peut rester vide. Si besoin est, il contiendra les méthodes supplémentaire propres à l' | ||
+ | |||
+ | ==== Un petit TP, ça vous dit? ==== | ||
+ | |||
+ | Créez donc un nouveau répertoire Quelque part dans votre arborescence. Placez-y les fichiers adéquat, par exemple comme ceci: | ||
+ | |||
+ | < | ||
+ | / +-- home/ | ||
+ | +-- tux/ | ||
+ | +-- tuto_python/ | ||
+ | +-- figures/ | ||
+ | +-- __init__.py | ||
+ | +-- cerles.py | ||
+ | </ | ||
+ | |||
+ | Le contenu du fichier cercles.py: | ||
+ | |||
+ | < | ||
+ | # | ||
+ | # -*- coding: utf8 -*- | ||
+ | |||
+ | |||
+ | class Cercle(): | ||
+ | """ | ||
+ | Définit un cercle de rayon R | ||
+ | |||
+ | EXEMPLE | ||
+ | monCercle = Cercle(2) | ||
+ | """ | ||
+ | R = 0 | ||
+ | |||
+ | def __init__(self, | ||
+ | self.R = monRayon | ||
+ | |||
+ | def peri(self): | ||
+ | """ | ||
+ | Permet de calculer le périmètre | ||
+ | """ | ||
+ | P = 2*pi*self.R | ||
+ | return P | ||
+ | </ | ||
+ | |||
+ | Le contenu du fichier __init__.py : | ||
+ | |||
+ | < | ||
+ | import cercles | ||
+ | </ | ||
+ | |||
+ | N' | ||
+ | |||
+ | Avec votre émulateur de terminal favori, placez-vous dans le répertoire tuto_python/ | ||
+ | |||
+ | < | ||
+ | import figures | ||
+ | |||
+ | dir(figures) | ||
+ | help(figures) | ||
+ | type(figures) | ||
+ | </ | ||
+ | |||
+ | À cette étape, la class Cercle n'est pas directement accessible. Vous pouvez l' | ||
+ | |||
+ | < | ||
+ | monCercle = figures.cercles.Cercle(2) | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | from figures import cercles | ||
+ | |||
+ | dir(cercles) | ||
+ | help(cercles) | ||
+ | type(cercles) | ||
+ | </ | ||
+ | |||
+ | Pour utiliser la classe Cercle: | ||
+ | |||
+ | < | ||
+ | monCercle = cercles.Cercle(2) | ||
+ | </ | ||
+ | |||
+ | < | ||
+ | from figures.cercles import Cercle | ||
+ | |||
+ | dir(Cercle) | ||
+ | help(Cercle) | ||
+ | type(Cercle) | ||
+ | </ | ||
+ | |||
+ | Là, nous avons importé la classe Cercle, nous pouvons donc l' | ||
+ | |||
+ | < | ||
+ | monCercle = Cercle(2) | ||
+ | </ | ||
+ | |||
+ | Vous pouvez maintenant vous amuser à créer d' | ||
+ | |||
+ | ===== Passer à la vitesse supérieure ===== | ||
+ | |||
+ | * [[expert: | ||
+ | * Bases de programmation avec python: | ||
+ | * [[expert: | ||
+ | * [[expert: | ||
+ | * [[expert: | ||
+ | * [[expert: | ||
+ | * [[expert: | ||
+ | * [[expert: | ||
+ | * [[expert: | ||
+ | * [[expert: |
expert/python_objet.txt · Dernière modification : 2018/11/17 12:53 de 127.0.0.1