LangageMethodesSpeciales

[wiki: Méthodes spéciales] [#license ©]

PageOutline

#!comment


A traiter :
nonzero


Constructeur et destructeur

Le constructeur est une méthode spéciale, appelée init(), qui est appelée lors de la création d’une instance de classe.

Le destructeur est une méthode spéciale, appelée del(), qui est appelée lors de la destruction d’une instance. ATTENTION : on ne contrôle pas vraiment le moment ou le destructeur est appelé. De ce fait, il est rarement utilisé.

#!div style="width:600px"


{{{
#!python
class Vecteur:
def init(self,u=0,v=0):
self.__x = u
self.__y = v
def getx(self):
return self.__x
def gety(self):
return self.__y
def norm(self):
x2 = self.__x**2
y2 = self.__y**2
return (x2+ y2)**(1/2)

v1 = Vecteur(3, 4)
print(v1.getx(),v1.gety())


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
3 4
</pre>
#!python
v2 = Vecteur(-2, 7)
print(v2.getx(),v2.gety())
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
-2 7
</pre>

}}}

Affichage

Par défaut, l’affichage d’une instance renvoie son nom de classe et son adresse en mémoire :

#!div style="width:600px"


{{{
#!python
class Vecteur:
def init(self,u=0,v=0):
self.__x = u
self.__y = v

v = Vecteur(3,4)

print(v)


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
<main.Vecteur object at ...>
</pre>

}}}

On peut personnaliser cet affichage en s’appuyant sur les méthodes spéciales str() et repr() :

#!div style="width:600px"


{{{
#!python
class Vecteur:
def init(self,u=0,v=0):
self.__x = u
self.__y = v
def str(self):
return "({:.0f},{:.0f})".format(self.x,self.y)
def repr(self):
return "Vecteur({:.0f},{:.0f})".format(self.x,self.y)

v = Vecteur(3,4)

print(v)


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
(3,4)
</pre>
#!python
v
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
Vecteur(3,4)
</pre>

}}}

En cas d’affichage destiné à l’utilisateur, tel qu’un appel à print(), c’est la méthode str() qui est recherchée en priorité, et seulement en dernier recours la méthode repr(). En principe, cette dernière est supposée retourner un texte qui, si il était exécuté, recréerait l’objet original.

Objets-fonctions

En dotant une classe de la méthode call, les instances de cette classe peuvent être utilisées comme des fonctions. On parle d’objets-fonctions. Cela peut-être utile lorsqu’on veut utiliser un programme générique qui attend une fonction en paramètre, et que l’on veut lui donner à la place des objets qui savent se comporter en fonction, tout en ayant des paramètres internes.

#!div style="width:600px"


{{{
#!python
class FonctionLineaire:
def init(self,constant):
self.constant = constant
def call(self,other):
return self.constant*other

fois2 = FonctionLineaire(2)
print(fois2(6))
print(map(fois2,[1,2,3,4,5]))


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
12
[2, 4, 6, 8, 10]</pre>

}}}

Ce mécanisme est souvent le plus sain pour associer des données persistantes à une fonction, plutôt que l’utilisation de variables globales, de fonctions imbriquées, ou de valeurs par défaut modifiables.

Opérateurs mathématiques

Il est possible de permettre l’utilisation des opérateurs habituels avec les nouvelles classes, en redéfinissant des méthodes spéciales au nom prédéfini :

  • + : add(self,other)
  • - : sub(self,other)
  • * : mul(self,other)
  • / : truediv(self,other)
  • // : floordiv(self,other)
  • % : mod(self,other)
  • ** : pow(self,other)
#!div style="width:600px"


{{{
#!python
class Vecteur:
def init(self,u=0,v=0):
self.__x = u
self.__y = v
def add(self, other):
if isinstance(other, Vecteur):
newx = self.x + other.x
newy = self.y + other.y
return Vecteur(newx, newy)
def str(self):
return "({:.0f},{:.0f}".format(self.x,self.y)

v1 = Vecteur(2,3)
v2 = Vecteur(-4,7)
v3 = v1 + v2

print(v3)


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
(-2,10)
</pre>

}}}

Index de séquence

En dotant une classe de la méthode getitem(), on peut utiliser ses instances avec toutes les formes de [] :

#!div style="width:600px"


{{{
#!python
class MonTexte:
def init(self,value):
self.data = value
def getitem(self,index):
return self.data[index]

txt = MonTexte("Bonjour")
print(txt[2])


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
n
</pre>
#!python
print(txt[-1::-1])
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
ruojnoB
</pre>

}}}

En bonus, la présence de getitem() permet d’utiliser un objet au sein d’une boucle for. L’interpréteur va invoquer cette méthode avec des valeurs entières croissantes, en commencant par 0, et jusqu’à l’émission d’une exception IndexError.

#!div style="width:600px"


{{{
#!python
for c in txt:
print(c)


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
B
o
n
j
o
u
r
</pre>

}}}

En réalité, la présence de getitem() permet d’utiliser un objet dans de multiples autres « contextes d’itération », tels que qu’un test d’appartenance in, une « compréhension de liste », la fonction prédéfinie map, l’assignation de séquences, …

#!div style="width:600px"


{{{
#!python
'i' in txt


#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
False
</pre>
#!python
[c for c in txt]
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
['B', 'o', 'n', 'j', 'o', 'u', 'r']
</pre>
#!python
map(ord,txt)
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
[66, 111, 110, 106, 111, 117, 114]
</pre>
#!python
(c1, c2, c3, c4, c5, c6, c7) = txt
c3, c2, c1
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
('n', 'o', 'B')
</pre>
#!python
list(txt), tuple(txt), '-'.join(txt)
#!html
<pre  style="margin-left:22px;margin-right:22px;border: 1px solid lightgoldenrodyellow;padding:10px;background-color:lightyellow">
(['B', 'o', 'n', 'j', 'o', 'u', 'r'],
 ('B', 'o', 'n', 'j', 'o', 'u', 'r'),
 'B-o-n-j-o-u-r')
</pre>

}}}

#!comment


Itérateurs

  • Un objet peut être utilisé comme itérateur si sa classe définit :
  • iter(self)
  • next(self) # En python 3 : next

{{{
#!div style="width:600px"

{{{
#!python
>>> class Reverse:
... def init(self, data):
... self.data = data
... self.index = len(data)
... def iter(self):
... return self
... def next(self):
... if self.index == 0:
... raise StopIteration
... self.index = self.index - 1
... return self.data[self.index]

>>> for char in Reverse('Jour'):
... print(char)
r
u
o
J


}}}

}}}

Travaux Pratiques

1. Dotez la classe Expression d’un constructeur à partir d’une chaîne de caractère, (et y fondre la fonction analyse()).
1. Transformez la méthode display() en méthode str().
1. Dotez la classe Expression d’un comportement de séquence (Transformez paires() en getitem()).
1. Dotez la classe Calculatrice d’un constructeur, puis transformez là en objet-fonction.

le fichier « calculatrice.py » contient à présent :

#!python
    .....
    expr = Expression(chaine)
    print(expr)
    for op, num in expr:
	if op=='=': res = num
	else:
            fct = operateurs.operations[op]
            res = fct(res,num)
    .....

et le fichier « main.py » :

#!python
calc = Calculatrice()


print()
ligne=input(">>> ")
while ligne!='OFF':
calc(ligne)
ligne=input(">>> ")


© David Chamont, Laboratoire Leprince-Ringuet (LLR) / IN2P3 / CNRS, Ecole polytechnique / Université Paris-Saclaybr
© Ce(tte) œuvre est mise à disposition selon les termes de la Licence Creative Commons Attribution – Partage dans les Mêmes Conditions 4.0 International [=#license]


Attachments