• Aucun résultat trouvé

[PDF] Initiation à la programmation en Python et en JavaScript | Cours informatique

N/A
N/A
Protected

Academic year: 2021

Partager "[PDF] Initiation à la programmation en Python et en JavaScript | Cours informatique"

Copied!
12
0
0

Texte intégral

(1)

Le Python, c’est bon

Cours 4 : Classes et exceptions

1

Objets classes

On consid`ere ici que vous avez des notions de langage objets. En particulier, vous savez ce qu’est une classe, un attribut et une m´ethode. Nous n’aborderons pas ici les notions de m´eta-classes (des classes de classes), pr´esentes dans python, et laissons le soin au lecteur int´eress´e de lire la documentation pr´esente sur le site de python.

1.1

Premi`

eres d´

efinitions

En python, tout est objet, mˆeme les classes. Cr´eons donc un objet classe : class UneClasse(object) :

""" une classe vide """

pass

Le mot clef class d´efini une classe, il doit ˆetre suivi par le nom de la classe puis, entre parenth`eses, des classes dont il h´erite. Par d´efaut, toutes les classes h´eritent d’object.

help(UneClasse) print UneClasse

1.2

Variables internes

Python enrichi directement cette classe de plusieurs variables internes (c’est `a dire des variables commen¸cant et terminant par des “ ”. On peut les voir en utilisant la fonction dir() :

print dir(UneClasse)

La fonction dir est tr`es utile, elle d´ecrit tout ce que contient un objet. On pourra essayer dir() pour voir tout ce que contient l’interpr´eteur, ou encore dir( builtins ) pour voir, entre autres, les fonctions de bases de python.

Int´eressons-nous pour l’instant `a deux variables internes particuli`eres (nous verrons la plupart des autres au cours de ce cours) :

(2)

print UneClasse.__name__ #nom de la classe

print UneClasse.__doc__ #documentation de la classe

print UneClasse.__module__ #module dans lequel la classe a ´et´e cr´ee print UneClasse.__bases__ #parents direct de la classe

Mettez ceci en perspective de l’instruction : if __name__ == "__main__":

#des instructions

que nous avions utilis´ee les cours pr´ec´edents.

1.3

Instances de classes

Cr´eons une instance de UneCLasse (un objet UneClasse) : x = UneClasse()

help(x) print x print dir(x)

L’objet x est une instance de la classe UneClasse. Comme UneClasse h´erite de object, x en est ´egalement une instance :

>>> isinstance(x, UneClasse) True

>>> isinstance(x, object) True

>>> isinstance(x, list) #n’est pas une instance de list False

La classe d’une instance est d´efinie dans son attribut class : >>> print x.__class__

<class ’__main__.UneClasse’>

On peut dynamiquement ajouter des attributs `a un objet d’une classe que l’on a d´efini. Ainsi :

x.titre = "C’est la vie, Cui Cui"

D´efinit une variable affect´ee `a x. La liste des variables d’un objet est d´efinie dans le dictionnaire dict .

print x.__dict__

print x.__dict__["titre"]

x.__dict__["titre"] = "Cure toujours" print x.titre

(3)

Tout objet python (une classe, un module, ...) poss`ede une variable dict qui regroupe tout ce que d´eclare cet objet (on appelle ¸ca un namespace). On peut s’en servir pour acc´eder `a une variable, la modifier, ou en cr´eer une autre (la plupart du temps).

print UneClasse.__dict__

x.__dict__["paroles"] = "Oh non non non j’ai bronz´e,\ mes potes voudront plus me parler," #idem que x.paroles =

Supprimer une variable se fait simplement par l’instruction del : del x.paroles

print x.__dict__

2

ethodes

Un des int´erˆet d’utiliser le formalisme objet est que l’on peut attribuer des m´ethodes sp´ecifiques aux aux instances d’une classe. Pour les objets liste que nous avons manipul´es les cours pr´ec´edents par exemple, la m´ethode append permet d’ajouter un ´el´ement en fin de liste. Il existe en python trois grandes familles de m´ethodes. Les m´ethodes pr´ed´efinies commen¸cant et finissant par “ ” (comme init ou len ), les m´ethodes programm´ees et les m´ethodes de classe.

A part pour les fonctions de classes, le premier param`etre des m´ethodes est toujours l’objet qui invoque la fonction. Par convention on le nommera self. On peut ´egalement toujours invoquer une m´ethode en utilisant la classe elle-mˆeme (le premier argument ´etant l’objet consid´er´e), comme le montre l’exemple suivant :

>>> x = list() >>> x.append(1) >>> x

[1]

>>> list.append(x, "un autre") >>> x

[1, ’un autre’]

2.1

ethodes pr´

ed´

efinies

Lors de la cr´eation d’un objet, la m´ethode init est invoqu´ee. Elle existe donc toujours, mˆeme si l’on ne la programme pas explicitement :

dir(UneClasse)

(4)

class UneClasse(object) :

""" une classe en construction """

def __init__(self, letitre="Cure Toujours"): self.titre = letitre

Maintenant : >>> x = UneClasse() >>> print x.titre Cure Toujours

>>> y = UneClasse("Goldorak est mort") >>> print y.titre

Goldorak est mort

Les m´ethodes pr´ed´efinies sont particuli`erement utiles pour l’interaction de classes entres-elles et avec python. Ainsi :

• len (self) : appel´e par la commande len, • str (self) : appel´e par la commande str, • del (self, attr) : appel´e par la commande del,

Impl´ementez pour notre classe une fonction len qui rend le nombre de car-act`eres de son titre.

Vous trouverez ici un certain nombre de m´ethodes sp´eciales de classes : http://www.python.org/doc/2.5.2/ref/customization.html. De fa¸con plus g´en´erale, rendez-vous ici pour tous les renseignements n´ecessaires : http://www. python.org/doc/2.5.2/ref/specialnames.html.

Trouvez par exemples les m´ethodes permettant les comparaisons entres vos objets (>, <, ==, 6=, . . . ), et comment faire pour que votre objet puisse ˆetre appel´e comme une fonction.

2.2

ethodes programm´

ees

Les m´ethodes programm´ees sont toutes les m´ethodes que vous pouvez impl´ementer pour enrichir vos classes. Comme pour les m´ethodes pr´ed´efinies (qui ne sont qu’un cas particulier de m´ethodes programm´ees) le premier argument de chaque m´ethode est self (votre objet).

Impl´ementez une m´ethode maj qui rend le titre de votre objet en majuscules.

2.3

Attributs et m´

ethodes de classe

Les attributs et m´ethodes de classes sont partag´es par toutes les instances de cette classe.

(5)

class UneClasse(object) :

""" une classe en construction """

titre = "C’est la vie, Cui Cui" #attribut de classe On peut alors :

>>> x = UneClasse() >>> x.titre

"C’est la vie, Cui Cui" >>> y = UneClasse() >>> y.titre

"C’est la vie, Cui Cui"

>>> UneClasse.titre = "Cure Toujours" >>> print y.titre

Cure Toujours >>> print x.titre Cure Toujours

Attention cependant. Si vous d´efinissez une variable dans un objet ayant le mˆeme nom que la variable de classe, celle-ci sera masqu´ee :

>>> print x.titre Cure Toujours

>>> x.titre = "Goldorak est mort" #cr´eation d’une nouvelle variable ! >>> print x.titre

Goldorak est mort >>> print y.titre Cure Toujours

>>> del x.titre #suppression de la variable de l’instance >>> print x.titre

Cure Toujours

Les variables de classes et d’instances ne sont pas dans le mˆeme namespace (l’un est dans UneClasse. dict , l’autre dans x. dict ). Si Deux noms co¨ıncide, c’est la variable d’instance qui est privil´egi´ee.

Pour les m´ethodes de classes, tout se passe comme pour les m´ethodes d’instances saut que le premier param`etre n’est plus une instance, mais une classe. Le nom de ce param`etre est par convention cls. On peut ainsi reprendre l’exemple pr´ec´edent en utilisant une m´ethode de classe :

class UneClasse(object) :

""" une classe en construction """

titre = "C’est la vie, Cui Cui" #attribut de classe def changeTitre(cls, titre):

cls.titre = titre

(6)

Et l`a :

>>> x = UneClasse()>>> y = UneClasse() >>> x.titre

"C’est la vie, Cui Cui" >>> y.titre

"C’est la vie, Cui Cui"

>>> x.changeTitre("Cure toujours") >>> x.titre

’Cure toujours’ >>> y.titre ’Cure toujours’

Pour une m´ethode de classe, c’est la classe de l’objet qui est pass´ee en param`etre (x. class ), plus l’objet lui-mˆeme.

2.4

ethodes statiques

Les m´ethodes statiques sont des m´ethodes d´eclar´ees dans des classes, mais qui se comportent comme des m´ethodes normales. Le premier param`etre n’a ici aucune signification particuli`ere.

class UneClasse(object) :

""" une classe en construction """

def maMethodeStatique(titre): print titre

maMethodeStatique = staticmethod(maMethodeStatique)

Pour une m´ethode statique, qu’on l’appelle via la classe ou un objet n’a aucune importance. >>> x = UneClasse() >>> x.maMethodeStatique("ici") ici >>> UneClasse.maMethodeStatique("ici") ici

2.5

Propri´

et´

es (Setter/getter)

Il est souvent plus clair d’utiliser une affectation directe d’un attribut que de passer par une fonction. Plutˆot que d’´ecrire :

x.changeReponse("42") print x.donneReponse()

(7)

x.reponse = 42 print x.reponse

Si les op´erations `a effectuer sont plus complexes que juste affecter une valeur `

a un attribut, python permet de masquer les appels de fonction via la commande properties

class UneClasse(object) :

""" une classe en construction """

def __init__(self, titre = "rien"): self.__titre = titre

self.longueur = len(titre) def gettitre(self):

return self.__titre def settitre(self, titre):

self.__titre = titre self.longueur = len(titre) titre = property(gettitre, settitre)

La variable titre est maintenant utilisable de fa¸con transparente : >>> x = UneClasse()

>>> print x.titre rien

>>> print x.longueur 4

>>> x.titre = "Guerre et Paix" >>> print x.titre

Guerre et Paix >>> print x.longueur 14

3

eritage multiple

Python autorise l’h´eritage multiple et utilise une r`egle appel´ee diamond rule pour r´egler les conflits.

class A(object): classe = "A" class B(object): classe = "B" class C(A, B): pass

(8)

Pour savoir qui est quoi, on peut utiliser la fonction issubclass() ou l’attribut de classe bases (les sup´erieurs directs) ou encore la m´ethode de classe subclasses (les successeurs directs) :

>>> A.__bases__ (<type ’object’>,) >>> B.__bases__ (<type ’object’>,) >>> C.__bases__

(<class ’__main__.A’>, <class ’__main__.B’>) >>> A.__subclasses__() [<class ’__main__.C’>] >>> issubclass(C, A) True >>> issubclass(C, object) True

3.1

Attributs h´

erit´

es

La recherche d’une m´ethode ou variable partag´ee par h´eritage peut ˆetre ex-plicit´ee en regardant la variable de classe mro (method resolution order) : >>> C.__mro__

(<class ’__main__.C’>, <class ’__main__.A’>, <class ’__main__.B’>, <type ’object’>)

Cette variable contient l’ordre de parcours des classes. La premi`ere classe dans cet ordre ayant la propri´et´e requise est retenue. La cr´eation de cette liste suit la r`egle de la diamond rule. L’exemple suivant montre cette r`egle en action : class A(object): classe = "A" class B(A): pass class C(object): classe = "C" class D(B,C): pass print D.classe class Cprim(A):

(9)

class Dprim(B,Cprim): pass

print Dprim.classe

Lisez le document http://docs.python.org/whatsnew/2.2.html?highlight= diamond%20rule#multiple-inheritance-the-diamond-rule et expliciter cette m´ethode de r´esolution des conflits.

3.2

ethodes parents

La fa¸con la plus simple d’appeler une fonction d’une classe parent (par exemple init ) est de l’appeler directement :

class maListe(list):

def __init__(self, param): list.__init__(self, param) print "ma liste"

>>> x = maListe(range(5)) ma liste

>>> x

[0, 1, 2, 3, 4]

Attention, une m´ethode h´erit´ee n’est pas appel´ee directement. Reprenez le code pr´ec´edent et supprimez l’appel direct `a l’initiation de la class list. Votre liste n’est pas initialis´ee.

On peut ´egalement utiliser la classe super(). Liser l’aide de cette classe. Je reprendrai ici l’exemple donn´e l`a http://www.python.org/download/releases/ 2.2/descrintro/#cooperation. Pour plus de d´etails, lisez cette partie.

class A(object):

def m(self): "save A’s data" class B(A):

def m(self): "save B’s data"; super(B, self).m() class C(A):

def m(self): "save C’s data"; super(C, self).m() class D(B, C):

def m(self): "save D’s data"; super(D, self).m() On a alors :

A.__mro__ == (A, object) B.__mro__ == (B, A, object) C.__mro__ == (C, A, object) D.__mro__ == (D, B, C, A, object)

(10)

super(C, self).m fonctionne ainsi. On commence par trouver la position de C dans self. class . mro puis on recherche la premi`ere classe apr`es C qui contient la fonction m. Il est recommand´e de n’utiliser la classe super que pour la surcharge de la mˆeme fonction (super(MaClasse, self).maMethode ne doit utilis´e que dans la surcharge de maMethode pour une classe fille de MaClasse).

Que donne le r´esultat de m pour les quatre classes ? Pourquoi ?

4

Exceptions

Vous avez sˆurement d´ej`a rencontr´e des exceptions lors de vos premiers essais en python :

print uneVariableNonAffectee # une erreur

La gestion des erreurs est cruciale dans tout programme. Rappelez vous une des deux r`egles du zen of Python (PEP20) :

Errors should never pass silently. Unless explicitly silenced.

Il n’est pas n´ecessaire de tout v´erifier au d´ebut de chaque fonction sous peine d’alourdir consid´erablement votre programme, mais lorsqu’une erreur survient, il faut la laisser se propager.

La gestion des erreurs s’effectuent en utilisant les mots cl´es try et except. try:

print uneVariableNonAffectee except:

print "une erreur"

La s´equence ci-apr`es vous montre un exemple plus g´en´eral : x = []

try:

print x[1] except IndexError:

print "L’indice n’existe pas" except (TypeError, NameError):

print "le nom ou le type n’est pas bon" except:

print "les autres erreurs" else:

print "tout s’est bien pass´e" try:

raise NameError, "C’est farfelu comme nom" except NameError, inst:

(11)

Comprenez son fonctionnement en utilisant l’aide du manuel disponible ici http://docs.python.org/tutorial/errors.html.

Les exceptions sont des classes comme les autres. La classe de base ´etant Exception. On peut l’utiliser pour lever une exception (avec l’aide de la com-mande raise) ou s’en servir pour cr´eer ses propres exceptions.

try:

raise NameError, "C’est farfelu comme nom" except Exception, inst:

print inst try:

raise Exception(’un’, ’deux’, ’et trois z´ero’) except Exception, inst:

print inst

class ErreurDeLaNature(Exception): def __init__(self, val):

self.commentaire = val def __str__(self):

return repr(self.commentaire) try:

raise ErreurDeLaNature("et c’est pas joli `a voir") except ErreurDeLaNature, val:

print "Une erreur de la nature arrive", val

5

Exercice

Les fichiers graph.py et test graphs.py contiennent une impl´ementation d’une classe permettant de manipuler les graphes.

Nous consid´ererons ici :

• que les graphes sont non orient´es,

• que chaque arˆete peut poss´eder un attribut (un nombre, ou tout autre objet).

Pour la compr´ehension de la classe, on pourra lire le lien suivant : http: //www.python.org/doc/essays/graphs.html.

5.1

La classe Graph

C’est votre premier exemple de code python que vous n’avez pas fait. Essayer de comprendre sa signification. En particulier :

(12)

• quelle est l’utilit´e de la fonction iter ? En quoi diff`ere-t-elle de la m´ethode vertices() ?

• `A quoi correspond getitem et comment l’utilise-t-on ?

• Que signifie la commande lambda (retenez cette commande, une fois qu’on a compris comment ¸ca fonctionne on ne peut s’empˆecher de l’utiliser partout) ?

• Pourquoi avoir d´efini une classe Sommet vide ?

Vous devriez pouvoir trouver toutes les r´eponses `a vos questions dans les documentations et liens fournis.

Le module graphs.py d´efinie ´egalement un algorithme BellmanFord et une erreur CircuitError. A l’aide de Wikip´` edia (par exemple) comprenez leurs utilit´es.

5.2

Les tests

Assurez-vous que les tests sont suffisants et que toutes les lignes sont parcourus dans les tests.

5.3

Ajout de fonctionnalit´

es `

a Graph

Pour la suite de nos aventures, il va falloir ´etoffer un peu la classe graphe. En particulier il vous est demand´e de coder et de tester les fonctionnalit´es suivantes :

• l’ajout et la suppression de sommets (un ou plusieurs en mˆeme temps), • l’ajout et la suppression d’arˆetes (une ou plusieurs en mˆeme temps), • le renommage de sommets,

• qu’il soit possible de trouver un chemin entre deux nœuds donn´ee, et que ce ce chemin soit le plus court possible.On pourra impl´ementer une ver-sion non orient´e de l’algorithme de Dijkstra (il faut pour cela que tous les poids des arˆetes soient positif, sinon rendre une erreur) que l’on trou-vera ici http://fr.wikipedia.org/wiki/Algorithme_de_Dijkstra par exemple.

Références

Documents relatifs

• tendance `a mieux fonctionner pour les petites donn ´ees. • Avantages de l’approche de maximum

Montrer qu’on peut d´ eriver l’expression de F sous le signe somme en tout point x &gt;

La distinction entre véracité historique et élan narratif est plus évidente encore lorsqu’il s’agit d’un programme de fantasy, comme la série animée Désenchantée

A mandioca pode cumprir um papel ecológico importante na preservação dos siste- mas tradicionais de galinha caipira, desempenhando múltiplas funções. A partir de sua Introdução

D’autre part, dans l’ensemble du Kérala, du pays tamoul et au Sri Lanka, il est au cœur de l’histoire de Kannaki, mais sans être davantage qu’un élément narratif :

À l’aide des données issues d’une enquête ethnographique et par collecte de récits de vie, conduite en France et en Belgique, auprès de cette typologie de couple,

La configuration pourrait être une réunion programmée par demi-journée, avec des candidats qui se connectent et sont en salle d’attente, et qu’on fait entrer dans la salle de

() R´eciproquement, montrer que si Y e une variable al´eatoire uniforme sur [, ], alors les bits de son ´ecriture en base  forment une suite de variables