Un peu de zik, puisque c’est ce qu’on fait maintenant :
Prérequis :
- Avoir lu (et compris) la partie 3
Aujourd’hui nous allons voir ce qui fait toute la puissance de la programmation orientée objet : l’héritage.
Héritage simple
L’héritage est un moyen de factoriser du code, c’est à dire que si on a le même code à deux endroits, l’héritage permet de centraliser ce code à un seul endroit. Ce n’est pas le seul moyen de faire ça. On peut très bien factoriser du code uniquement avec des fonctions. Néanmoins l’héritage a des caractéristiques qui rendent la factorisation très efficace.
Supposons que vous fassiez un jeu vidéo pour apprendre les prières chrétiennes, et que vous ayez une classe par prière :
class AveMaria: texte = ("Je vous salue, Marie pleine de grâce ;", "Le Seigneur est avec vous.", "Vous êtes bénie entre toutes les femmes", "Et Jésus, le fruit de vos entrailles, est béni.", "Sainte Marie, Mère de Dieu,", "Priez pour nous, pauvres pécheurs,", "Maintenant, et à l'heure de notre mort.", "Amen.") def prier(self, nombre_de_fois=1): for x in xrange(nombre_de_fois): for ligne in self.texte: print ligne class PaterNoster: texte = ("Notre Père qui es aux cieux", "que ton nom soit sanctifié", "que ton règne vienne,", "que ta volonté soit faite", "sur la terre comme au ciel.", "Donne-nous aujourd’hui", "notre pain de ce jour,", "pardonne-nous nos offenses", "comme nous pardonnons aussi", "à ceux qui nous ont offensés", "et ne nous soumets pas à la tentation", "mais délivre-nous du mal.", "Amen") def prier(self, nombre_de_fois=1): for x in xrange(nombre_de_fois): for ligne in self.texte: print ligne >>> piere = AveMaria() >>> piere.prier() Je vous salue, Marie pleine de grâce ; Le Seigneur est avec vous. Vous êtes bénie entre toutes les femmes Et Jésus, le fruit de vos entrailles, est béni. Sainte Marie, Mère de Dieu, Priez pour nous, pauvres pécheurs, Maintenant, et à l'heure de notre mort. Amen. |
Ici la méthode prier()
est dupliquée. Or, c’est exactement la même. Il n’y a pas de raison de l’écrire deux fois. Nous allons utiliser l’héritage pour centraliser ce code en créant une classe Priere
qui contiendra le code commun à toutes les prières :
class Priere: def prier(self, nombre_de_fois=1): for x in xrange(nombre_de_fois): for ligne in self.texte: print ligne |
Ensuite, nous allons demander à toutes les classes prières d’hériter de cette classe commune :
class AveMaria(Priere): # <---- cette syntaxe veut dire 'hérite de Priere' texte = ("Je vous salue, Marie pleine de grâce ;", "Le Seigneur est avec vous.", "Vous êtes bénie entre toutes les femmes", "Et Jésus, le fruit de vos entrailles, est béni.", "Sainte Marie, Mère de Dieu,", "Priez pour nous, pauvres pécheurs,", "Maintenant, et à l'heure de notre mort.", "Amen.") class PaterNoster(Priere): texte = ("Notre Père qui es aux cieux", "que ton nom soit sanctifié", "que ton règne vienne,", "que ta volonté soit faite", "sur la terre comme au ciel.", "Donne-nous aujourd’hui", "notre pain de ce jour,", "pardonne-nous nos offenses", "comme nous pardonnons aussi", "à ceux qui nous ont offensés", "et ne nous soumets pas à la tentation", "mais délivre-nous du mal.", "Amen") |
Ici, les classes AveMaria
et PaterNoster
héritent de la classe Priere
. On dit qu’elles sont les enfants (ou filles) de Priere
. Ou que Priere
est la classe parente de AveMaria
et PaterNoster
Notez qu’on a retiré la méthode prier()
de PaterNoster
et AveMaria
. Malgré cela, ça marche :
>>> PaterNoster().prier() Notre Père qui es aux cieux que ton nom soit sanctifié que ton règne vienne, que ta volonté soit faite sur la terre comme au ciel. Donne-nous aujourd'hui notre pain de ce jour, pardonne-nous nos offenses comme nous pardonnons aussi à ceux qui nous ont offensés et ne nous soumets pas à la tentation mais délivre-nous du mal. Amen |
Cela marche car quand on hérite d’une classe, le code de cette classe est copié de la classe parente vers la classe enfant. Ainsi, prier()
est automatiquement copiée de Priere
vers AveMaria
et PaterNostre
.
Cela marche pour toutes les méthodes, même celles appelées automatiquement. C’est particulièrement utile avec la méthode __init__
:
class Priere: def __init__(self, expiation=False): self.expiation = expiation def prier(self, nombre_de_fois=1): for x in xrange(nombre_de_fois): for ligne in self.texte: if self.expiation: print ligne.upper() else: print ligne |
On rajoute ici un attribut, et il se retrouve dans la classe enfant (si vous êtes dans un shell, n’oubliez pas de réécrire aussi la classe AveMaria
à chaque fois, même si elle ne change pas):
>>> priere = AveMaria(expiation=True) >>> priere.expiation True >>> priere.prier() JE VOUS SALUE, MARIE PLEINE DE GRâCE ; LE SEIGNEUR EST AVEC VOUS. VOUS êTES BéNIE ENTRE TOUTES LES FEMMES ET JéSUS, LE FRUIT DE VOS ENTRAILLES, EST BéNI. SAINTE MARIE, MèRE DE DIEU, PRIEZ POUR NOUS, PAUVRES PéCHEURS, MAINTENANT, ET à L'HEURE DE NOTRE MORT. AMEN. |
L’héritage, c’est juste cela. Pas la peine de chercher un truc compliqué : le code du parent se retrouve dans celui de l’enfant. Cela marche pour les méthodes et les attributs.
Petit apparté sur object
Dans la partie précédente et dans de nombreux codes, vous avez dû voir des classes comme cela :
class MaClass(object): # wtf is this object stuff ? # code |
Il s’agit bel et bien d’héritage, object
étant un type buil-in en Python au même titre que les string ou les int :
>>> object <type 'object'> |
La raison de cet héritage bizarre est qu’à partir de Python 2.2, une nouvelle architecture des classes a été introduite qui corrige les problèmes de l’ancienne. Mais pour garder le code compatible, ces nouvelles classes n’ont pas été activées par défaut.
Ainsi, même si vous êtes en Python 2.7, quand vous faites :
class MaClass: # code |
Vous utilisez l’ancien type de classe (old-style class). Pour dire à Python que vous voulez utiliser le nouveau type de classe (new-style class), il faut hériter d’object
:
class MaClass(object): # code |
Il n’y a AUCUN intérêt à utiliser les old-style classes. Je l’ai fais en ce début de cours pour éviter d’introduire la notion d’héritage trop tôt.
A partir de maintenant, quand vous créez une nouvelle classe qui n’a pas de parent, faites la TOUJOURS hériter de object
.
Des tas de fonctions (par exemple les properties) fonctionnent beaucoup mieux avec les new-style classes. (D’ailleurs à partir de Python 3, elles sont activées par défaut)
Ainsi, notre classe Priere doit ressembler à ça maintenant :
class Priere(object): def __init__(self, expiation=False): self.expiation = expiation def prier(self, nombre_de_fois=1): for x in xrange(nombre_de_fois): for ligne in self.texte: if self.expiation: print ligne.upper() else: print ligne |
Overriding
Parfois on veut tout le code du parent dans l’enfant. Parfois juste une partie. L’héritage vous permet de réécrire certaines méthodes du parent dans l’enfant, c’est ce qu’on appelle l’overriding.
Quand vous faites :
class Parent(object): def truc(self): print 'foo' class Enfant(Parent): pass |
En fait vous faites en quelque sorte :
class Enfant(object): def truc(self): print 'foo' |
Si vous faites :
class Enfant(object): def truc(self): print 'foo' def truc(self): print 'bar' |
Vous allez écraser la première méthode avec la deuxième, car elles portent toutes les deux le même nom :
>>> Enfant().truc() bar |
“Ecraser” en anglais, se dit “to override”. Félicitation, vous venez d’apprendre l’overriding ! Ce qu’on vient de voir plus haut s’écrit comme ça dans le cadre de l’héritage :
class Parent(object): def truc(self): print 'foo' class Enfant1(Parent): pass # pas d'overriding class Enfant2(Parent): def truc(self): print 'bar' # overriding ! >>> Enfant1().truc() foo >>> Enfant2().truc() bar |
Enfant1
a tout le code du parent qui est copié. Enfant2
aussi, mais il réécrit la méthode, donc sa version de la méthode écrase celle du parent.
Voyons ce que ça donne sur un cas plus concret dans la vie de tous les jours comme les prières chrétiennes (promis je fais les sourates du Coran si je fais un tuto Haskell) :
class Priere(object): def __init__(self, expiation=False): self.expiation = expiation def prier(self, nombre_de_fois=1): for x in xrange(nombre_de_fois): for ligne in self.texte: if self.expiation: print ligne.upper() else: print ligne class PaterNoster(Priere): texte = ("Notre Père qui es aux cieux", "que ton nom soit sanctifié", "que ton règne vienne,", "que ta volonté soit faite", "sur la terre comme au ciel.", "Donne-nous aujourd’hui", "notre pain de ce jour,", "pardonne-nous nos offenses", "comme nous pardonnons aussi", "à ceux qui nous ont offensés", "et ne nous soumets pas à la tentation", "mais délivre-nous du mal.", "Amen") # sur avemaria, on veut mettre en avant la version en araméen # car l'araméen c'est trop cool (ça ressemble au langage des furlings # dans stargate) class AveMaria(Priere): vf = ("Je vous salue, Marie pleine de grâce ;", "Le Seigneur est avec vous.", "Vous êtes bénie entre toutes les femmes", "Et Jésus, le fruit de vos entrailles, est béni.", "Sainte Marie, Mère de Dieu,", "Priez pour nous, pauvres pécheurs,", "Maintenant, et à l'heure de notre mort.", "Amen.") vo = ("ܡܠܝܬ ܛܝܒܘܬܐ", "ܡܪܢ ܥܡܟܝ", "ܡܒܪܟܬܐ ܐܢܬܝ ܒܢܫ̈ܐ", "ܘܡܒܪܟ ܗܘ ܦܐܪܐ ܕܒܟܪܣܟܝ ܡܪܢ ܝܫܘܥ", "ܐܘ ܩܕܝܫܬܐ ܡܪܝܡ ܝܠܕܬ ܐܠܗܐ", "ܨܠܝ ܚܠܦܝܢ ܚܛܝ̈ܐ", "ܗܫܐ ܘܒܫܥܬ ܘܡܘܬܢ", "ܐܡܝܢ܀") def prier(self, nombre_de_fois=1, version='vo'): for x in xrange(nombre_de_fois): for ligne in getattr(self, version, 'vo'): if self.expiation: print ligne.upper() else: print ligne >>> AveMaria().prier() ܡܠܝܬ ܛܝܒܘܬܐ ܡܪܢ ܥܡܟܝ ܡܒܪܟܬܐ ܐܢܬܝ ܒܢܫ̈ܐ ܘܡܒܪܟ ܗܘ ܦܐܪܐ ܕܒܟܪܣܟܝ ܡܪܢ ܝܫܘܥ ܐܘ ܩܕܝܫܬܐ ܡܪܝܡ ܝܠܕܬ ܐܠܗܐ ܨܠܝ ܚܠܦܝܢ ܚܛܝ̈ܐ ܗܫܐ ܘܒܫܥܬ ܘܡܘܬܢ ܐܡܝܢ܀ >>> AveMaria().prier(2, 'vf') Je vous salue, Marie pleine de grâce ; Le Seigneur est avec vous. Vous êtes bénie entre toutes les femmes Et Jésus, le fruit de vos entrailles, est béni. Sainte Marie, Mère de Dieu, Priez pour nous, pauvres pécheurs, Maintenant, et à l'heure de notre mort. Amen. Je vous salue, Marie pleine de grâce ; Le Seigneur est avec vous. Vous êtes bénie entre toutes les femmes Et Jésus, le fruit de vos entrailles, est béni. Sainte Marie, Mère de Dieu, Priez pour nous, pauvres pécheurs, Maintenant, et à l'heure de notre mort. Amen. |
Ici la classe AveMaria
hérite de la classe Priere
. Deux méthodes sont copiées de Priere
vers AveMaria
: __init__
et prier()
.
__init__
ne change pas. Donc AveMaria
a toujours le __init__
de Priere
. Par contre, on a overridé prier()
dans AveMaria
, qui est maintenant un code personnalisé.
Ceci nous permet donc de bénéficier d’une partie du code en commun (__init__
), et de choisir un comportement différent pour d’autres bout du code (prier()
).
La classe PaterNoster
, elle, n’est pas affectée. Elle n’override rien, et sa méthode prier()
est la même que celle de Priere
.
Peut-être voulez-vous une exemple plus terre à terre (et moins dans les cieux) :
Prenez la bibliothèque path.py, par exemple. Normalement quand on additionne deux strings, ça les concatène. Mais quand on les divise, le comportement par défaut est de lever une erreur.
>>> '/home/sam' + '/blog' '/home/sam/blog' >>> '/home/sam' / '/blog' Traceback (most recent call last): File "<ipython-input-58-8701a4e82b4b>", line 1, in <module> '/home/sam' / '/blog' TypeError: unsupported operand type(s) for /: 'str' and 'str' |
Path.py override ce comportement :
import os class path(str): # hé oui, on peut hériter des types de base def __div__(self, other): # override le comportement face à l'opérateur '/' return path(os.path.join(self, other)) ... p = path('/home/sam') ... print p / 'blog' /home/sam/blog |
Ca nous donne une très jolie interface pour la manipulation des chemins d’accès.
Polymorphisme et autres diableries
Comme d’hab en prog, on adore les mots qui font super hype de la vibes du flex.
Le polymorphisme fait partie de ces termes compliqués qui cachent une notion simple : avoir une API commune qui fait des choses différentes.
Voyez-vous, nos deux classes AveMaria
et PaterNoster
, sont toutes les deux filles de la même classe parente. Elles se ressemblent donc beaucoup : elles ont des attributs et des méthodes en commun :
>>> p1 = AveMaria() >>> p2 = PaterNoster() >>> p1.expiation False >>> p2.expiation False >>> p1.prier <bound method AveMaria.prier of <__main__.AveMaria object at 0x20618d0>> >>> p2.prier <bound method PaterNoster.prier of <__main__.PaterNoster object at 0x2061c90>> >>> p1.__init__ <bound method AveMaria.__init__ of <__main__.AveMaria object at 0x20618d0>> >>> p2.__init__ <bound method PaterNoster.__init__ of <__main__.PaterNoster object at 0x2061c90>> |
Ce sont pourtant des classes différentes (et prier()
ne fait pas du tout le même chose), mais elles partagent ce qu’on appelle une API (une interface), c’est à dire une manière de les utiliser.
Cette capacité à être utilisé pareil, mais produire un résultat diffférent est ce qu’on appelle le polymorphisme (et c’est la base du duck typing). Concrètement ça veut dire que vous pouvez utiliser les deux classes dans le même contexte, sans vous soucier de si c’est l’une ou l’autre :
>>> prieres = [AveMaria(), AveMaria(), PaterNoster(), AveMaria(), PaterNoster()] >>> prieres [<__main__.AveMaria object at 0x2061d50>, <__main__.AveMaria object at 0x2061d90>, <__main__.PaterNoster object at 0x2061f50>, <__main__.AveMaria object at 0x2061f90>, <__main__.PaterNoster object at 0x2061fd0>] >>> for priere in prieres: ... priere.prier() # prier une prière, ça se fait pareil ܡܠܝܬ ܛܝܒܘܬܐ ܡܪܢ ܥܡܟܝ ܡܒܪܟܬܐ ܐܢܬܝ ܒܢܫ̈ܐ ܘܡܒܪܟ ܗܘ ܦܐܪܐ ܕܒܟܪܣܟܝ ܡܪܢ ܝܫܘܥ ܐܘ ܩܕܝܫܬܐ ܡܪܝܡ ܝܠܕܬ ܐܠܗܐ ܨܠܝ ܚܠܦܝܢ ܚܛܝ̈ܐ ܗܫܐ ܘܒܫܥܬ ܘܡܘܬܢ ܐܡܝܢ܀ ܡܠܝܬ ܛܝܒܘܬܐ ܡܪܢ ܥܡܟܝ ܡܒܪܟܬܐ ܐܢܬܝ ܒܢܫ̈ܐ ܘܡܒܪܟ ܗܘ ܦܐܪܐ ܕܒܟܪܣܟܝ ܡܪܢ ܝܫܘܥ ܐܘ ܩܕܝܫܬܐ ܡܪܝܡ ܝܠܕܬ ܐܠܗܐ ܨܠܝ ܚܠܦܝܢ ܚܛܝ̈ܐ ܗܫܐ ܘܒܫܥܬ ܘܡܘܬܢ ܐܡܝܢ܀ Notre Père qui es aux cieux que ton nom soit sanctifié que ton règne vienne, que ta volonté soit faite sur la terre comme au ciel. Donne-nous aujourd’hui notre pain de ce jour, pardonne-nous nos offenses comme nous pardonnons aussi à ceux qui nous ont offensés et ne nous soumets pas à la tentation mais délivre-nous du mal. Amen ܡܠܝܬ ܛܝܒܘܬܐ ܡܪܢ ܥܡܟܝ ܡܒܪܟܬܐ ܐܢܬܝ ܒܢܫ̈ܐ ܘܡܒܪܟ ܗܘ ܦܐܪܐ ܕܒܟܪܣܟܝ ܡܪܢ ܝܫܘܥ ܐܘ ܩܕܝܫܬܐ ܡܪܝܡ ܝܠܕܬ ܐܠܗܐ ܨܠܝ ܚܠܦܝܢ ܚܛܝ̈ܐ ܗܫܐ ܘܒܫܥܬ ܘܡܘܬܢ ܐܡܝܢ܀ Notre Père qui es aux cieux que ton nom soit sanctifié que ton règne vienne, que ta volonté soit faite sur la terre comme au ciel. Donne-nous aujourd’hui notre pain de ce jour, pardonne-nous nos offenses comme nous pardonnons aussi à ceux qui nous ont offensés et ne nous soumets pas à la tentation mais délivre-nous du mal. Amen |
Le polymorphisme, c’est donc l’utilisation de l’héritage pour faire des choses différentes, mais en proposant la même interface (ensemble de méthodes et d’attributs) pour le faire. Le polymorphisme s’étend aussi à la réaction aux opérateurs (+, -, /, or, and, etc), d’autant qu’en Python, c’est implémenté avec les méthodes nommées avec __
.
Un dernier point pour les gens qui se demandent ce que veut dire overloader. L’overload est lié à l’override et au polymorphisme, mais ce n’est pas la même chose : elle consiste à overrider plusieurs fois une même méthode avec une signature différente. Il n’y a pas d’overload en Python, la notion ne nous concerne donc pas. Si vous voulez en apprendre plus, chopez un tuto Java ou C++.
Qui est qui
Avec l’héritage vient la notion de type. Quand vous créez une classe, vous créez un nouveau type. Quand vous sous-classez, vous créez un sous-type.
C’est intéressant, car une classe fille, est de son propre type ET du type de son parent (mais l’inverse n’est pas vrai).
Avec Python, on vérifie cela avec isinstance()
:
>>> isinstance(Priere(), Priere) # instance de sa propre classe True >>> isinstance(Priere(), str) # pas l'instance d'une classe quelconque False >>> isinstance(Priere(), AveMaria) # pas l'instance d'un enfant False >>> isinstance(AveMaria(), AveMaria) # instance de sa propre classe True >>> isinstance(AveMaria(), Priere) # instance de sa classe parente True |
C’est utile, car certains comportements sont basés sur le type. Le plus important étant le mécanisme des exceptions. Un try
/ except
arrêtera l’exception demandée, ou du même type.
class MonExceptionPerso(Exception): pass class FillesDeMonExceptionPerso(MonExceptionPerso): pass try: raise MonExceptionPerso('Alerte ! Alerte !') except MonExceptionPerso: print 'Exception arrêtée' try: raise FillesDeMonExceptionPerso('Alerte ! Alerte !') except FillesDeMonExceptionPerso: print 'Exception arrêtée' try: raise FillesDeMonExceptionPerso('Alerte ! Alerte !') except MonExceptionPerso: print 'Exception arrêtée' try: raise MonExceptionPerso('Alerte ! Alerte !') except FillesDeMonExceptionPerso: print 'Exception arrêtée' Exception arrêtée Exception arrêtée Exception arrêtée Traceback (most recent call last): File "<ipython-input-67-7e7aec1e78c9>", line 21, in <module> raise MonExceptionPerso('Alerte ! Alerte !') MonExceptionPerso: Alerte ! Alerte ! |
MonExceptionPerso
est de type MonExceptionPerso
, donc l’exception est arrêtée. FillesDeMonExceptionPerso
est de type FillesDeMonExceptionPerso
, donc l’exception est arrêtée. FillesDeMonExceptionPerso
, qui hérite de MonExceptionPerso
, et donc de type MonExceptionPerso
est arrêtée.
En revanche, MonExceptionPerso
n’est PAS de type FillesDeMonExceptionPerso
. Donc elle n’est pas arrêtée.
Je le signale car il est très courant de faire des enfants de ValueError
, IOError
, IndexError
, KeyError
, etc. et de le lever dans son propre programme. Cela permet à l’utilisateur de son code de pouvoir attraper soit toutes les erreurs de son code en faisant un except
sur l’enfant, soit attraper toutes les erreurs de type ValueError
, IOError
, IndexError
, KeyError
en faisant le except
sur le parent. On laisse ainsi une marge de manoeuvre dans la gestion des erreurs.
Appeler la méthode de la classe parent
Bon, vous avez overridé une méthode du parent. Mais c’est une groooooooooooooossse méthode. Vous allez pas la réécrire en entier, si ?
class Escorte(object): def calculer_prix(self, heures, tarif): return heures * tarif class EscorteDeLuxe(Escorte): def calculer_prix(self, heures, tarif, supplement): tarif = heures * tarif return tarif + (tarif * supplement / 100) |
Sur cet exemple éminement intellectuel, calculer_prix()
est simple, donc tout réécrire dans EscorteDeLuxe
n’est pas grave. Mais si c’était une Geisha
, hein ? Avec un manuel en Japonais ?
Pour éviter ces problèmes de complexité liés à la globalisation, le perméabilisation des frontières et les sites de streaming, on peut appeler la méthode du parent, dans l’enfant, en utilisant super()
:
class EscorteDeLuxe(Escorte): def calculer_prix(self, heures, tarif, supplement): # ceci est une manière compliquée de faire Escorte.calculer_prix # et de récupérer le résultat tarif = super(EscorteDeLuxe, self).calculer_prix(heures, tarif) return tarif + (tarif * supplement / 100) |
C’est exactement la même chose que plus haut. Sauf qu’au lieu de copier / coller le code du parent, on l’appelle directement.
Je résume :
- on hérite du parent, et de son code
- on override son code, car on veut un comportement différent
- mais on veut quand même une partie du comportement du parent
- donc dans la méthode de l’enfant, on appelle la méthode du parent
Je réformule : quand vous overridez la méthode du parent dans l’enfant, celle du parent ne disparait pas. Elle est remplacée uniquement dans l’enfant. Et vous pouvez toujours vous servir de la version du parent en utilisant super(ClassEncours, self).nom_de_method(arguments)
si vous en avez besoin.
Bon, c’était un gros morceau, et je suis pas sûr de pas être allé trop fort. Donc laissez en comment les remarques sur ce qui pourrait être mieux expliqué. La prochaine fois, on verra des usages poussés comme la composition, la délégation et tous ces trucs d’un vrai code de production.
Et l’héritage multiple ? :'(
On en est qu’à la partie 4. Je pense qu’il y aura entre 6 et 8 parties.
Rien à dire. C’est du cousu main et repassé à la pâtemouille.
A part qu’on hallucine un peu sur l’exemple…Mais bon, c’est Dimanche,les cloches,toussa…Normal.
Tu m’a l’air d’être en grande forme.
je me barre avant l’arrivée des abeilles…ça va pas tarder à bourdonner sévère par ici.
Si je ne m’abuse, l’héritage de EscorteDeLuxe n’est pas correcte.
Excellente série pour le débutant, depuis le temps que j’en ai pas fait en python, ça me rafraichit la mémoire ;)
Ouai j’ai oublié de faire hérité d’escorte.
@Sam:
Il serait bon que lorsque toutes les corrections de tes ignobleries seront faites, tu mette un tampon “Valided”.
ça m’éviterais de recharger la page cinq fois, et de cinq fois en retirer les com’s, les images, et un tas de trucs chelous dont est copieusement garnis le html.
Pour n’en garder que la substantifique moelle, dans sa merveilleuse mise en page.
Le truc c’est que c’est un travail en perpétuelle continuation. Parfois un article a encore des corrections apportées par les lecteurs des jours après la publication. Je n’ai aucun moyen de savoir à l’avance si j’ai atteint la perfection, et je n’ai pas envie de passée des heures et des heures à checker tous les articles.
C’est aussi à ça que servent les coms.
Un article comme celui-ci me prend entre 2 et 4 heures à écrire. C’est normal qu’il y ai des coquilles. Je compte fortement sur l’intelligence collective pour soulager ma tâche de relecture.
Supposons que vous fassiez un jeu vidéo pour apprendre les prières chrétiennes, et que vous ayez une classe par prière :
Hop… ;-)
Prenez la bibliothèque path.py, par exemple.
Re’hop… ;-)
La qualité est toujours là ; ça m’a rappelé mon stage de formation prog en Java (où j’ai découvert les joies de la POO en même temps) mais en nettement moins douloureux…
Merci Sam & Max
Pour override j’aurai dit “surcharger” ;-)
@Sam:
Je te comprends. je reviendrai sur les anciens faire des “compare”, ça va aller.
Repose toi, on en a pour un moment à digérer…
@foxmask: nein. Surcharger, c’est overloader.
@roro Tu nettoie le html à la main ? Tu n’as pas essayé de créer un script pour ne récupérer que la substantifique moelle ? Y’a des modules python pour parser le html (il vaut mieux éviter de le faire à la main).
Et sinon, il n’y a pas de souci à ne pas mettre les strings en unicode ? Même en araméen ?
Je viens de tester, le .upper() marche pour les lettres accentuées en unicode, mais pas en ascii (d’où vos exemples tout moches). Et apparemment il n’y a pas de majuscules en araméen…
Il y a toujours des problèmes à ne pas utiliser l’unicode. Mais mélanger trop de choses dans le tuto ne va pas aider à sa compréhension. Pour l’exemple, c’est suffisant.
@kontre:
J’aime bien voir ce que je fais, et avec l’habitude, c’est très rapide. Après je mets tout dans un dossier, j’ajoute des liens menant directement à des parties de sujet. Ce qui me permets de voir différents emplois d’une même chose, et le “retour arrière” me renvoie d’où je viens, plus pratique que des ouvertures de fichiers + recherche dans le fichier.
De l’hybridation python/html, en quelque sôôrte.
Your site? 0bin.net has error.
The #hash contains charachter = which breaks almost all forum hyperlinks. please fix if you can and TY
The problem doesn’t come from 0bin. If a forum can’t parse the URL, their URL parser is broken. Still, you can use the “get short url” feature from 0bin which doesn’t contain any “=” sign.
Ding !! C’est encore moi !
une truc compliqué
un truc compliqué
Petite appartée sur object
Petit aparté sur object
notre père qui es au cieux
On croit que y’a une faute, j’ai vérifié, y’en a pas. le mot “es” est bien sans T.
par l’araméen c’est trop cool
car l’araméen c’est trop cool
Le paramètre ‘default’ du getattr ne fonctionne pas comme ça.
Il faut y mettre directement la valeur, qui sera renvoyée telle quelle si l’attribut n’existe pas. On ne peut pas mettre une chaîne de caractère correspondant à un nom d’attribut censé exister.
Faudrait donc remplacer par ça :
http://docs.python.org/2/library/functions.html#getattr
��ܫܐ ܘܒܫܥܬ ܘܡܘܬܢ
ܗܫܐ ܘܒܫܥܬ ܘܡܘܬܢ
Je vous laisse retrouver ou c’est. (Bidouille avec le caractère magique de l’unicode qui indique que le texte est de droite à gauche ?)
c’est implémenté avec les méthodes nommées avec __.
c’est implémenté par les méthodes nommées avec __.
Parce que sinon ça fait deux fois “avec”.
FillesDeMonExceptionPerso, qui hérite de MonExceptionPerso, et donc de type MonExceptionPerso est arrêtée.
FillesDeMonExceptionPerso, qui hérite de MonExceptionPerso, est donc de type MonExceptionPerso, elle est donc arrêtée.
de le lever dans son propre programme.
de les lever dans son propre programme.
manoeuvre
manœuvre
(Ça, pour mettre de l’araméen, y’a du monde. Mais pour faire un “œ”, y’a plus personne. Avec un clavier bépo, ce genre de subtilité ne pose aucun problème)
Utilisation un peu trop abusive de la variable “tarif”. Ça fait un risque de confusion entre le tarif horaire (la valeur passée en paramètre), et le tarif de la prestation (la valeur renvoyée par la fonction). Je propose d’utiliser “prix” à la place. Ce sera d’autant plus cohérent que la fonction s’appelle “calculer_prix”.
Donc :
Et du coup, le bloc de code qui vient après serait comme ça :
class EscorteDeLuxe(Escorte):
Mais ceci reste à l’appréciation du rédacteur. Utiliser le même nom de variable, ça se défend aussi.
Merci beaucoup Recher. Tu veux pas que je te donne directement un nouveau compte avec accès au backend plutôt ? Comme ça tu as pas à tout réécrire toi-même dans un poste, ça double ton taff pour rien là.
Merci beaucoup, mais c’est peut être pas la peine. En fait j’ai juste prévu de relire et corriger les articles sur la POO, parce que c’est un bazar qui me semble important. Pour le reste, je laisse les correcteurs dotés de plus d’abnégation s’en occuper.
Encore moi :]
c’est à dire : c’est-à-dire
je l’ai fais : fait
A partir : À partir
(D’ailleurs à partir de Python 3, elles sont activées par défaut): (D’ailleurs à partir de Python 3, elles sont activées par défaut.) (point dans la parenthèse
notre classe Priere : balise code manquante
Deux méthodes sont copiées de Priere vers AveMaria : __init__ et prier(). : pourquoi des parenthèses à prier et pas à __init__ ? (idem lignes suivantes)
d’autres bout de code : bouts
une exemple : un exemple
Prenez la bibliothèque path.py : prenez (pas de majuscule après «:» pas de capitale non plus :þ)
Path.py override ce comportement : … p = path à changer en »»
de la vibes du flex : j’utilise vibe mais ai entendu vibes. À voir.
le même chose : la
c’est à dire : c’est-à-dire
à être utilisé : a être
sans vous soucier de si c’est l’une ou l’autre : soit plus de ponctuation, soit «soucier de savoir si»
etc etc.
manoeuvre :
manœuvrenon, c’est bon…le perméabilisation : la
énumération sans ;