L'instanciation de classes en Python
est simple et directe. Pour instancier une classe, appelez simplement
la classe comme si elle était une fonction, en lui passant les
arguments que la méthode __init__ définit. La
valeur de retour sera l'objet nouvellement créé.
Exemple 5.7. Création d'une instance de FileInfo
>>> import fileinfo>>> f = fileinfo.FileInfo("/music/_singles/kairo.mp3")>>> f.__class__<class fileinfo.FileInfo at 010EC204>>>> f.__doc__'store file metadata'>>> f{'name': '/music/_singles/kairo.mp3'}
Nous créons une instance de la classe
FileInfo (définie dans le module fileinfo) et assignons l'instance
nouvellement créée à la variable f. Nous
passons un paramètre,
/music/_singles/kairo.mp3, qui sera l'argument
filename de la méthode
__init__ de FileInfo.
Chaque instance de classe à un attribut prédéfini,
__class__, qui est la classe de l'objet (notez
que la représentation de cet attribut comprend l'adresse physique
de l'instance sur ma machine, votre sortie sera différente). Les
programmeurs Java sont sans doute
familiers de la classe Class, qui contient
des méthodes comme getName et
getSuperclass permettant d'obtenir les
métadonnées d'un objet. En Python, ce
type de métadonnées est accessible directement par le biais de
l'objet lui-même à travers des attributs comme
__class__, __name__ et
__bases__.
Vous pouvez accéder à la doc string de
l'instance comme pour une fonction ou un module. Toutes les
instances d'une classe partagent la même doc string.
Rappelez vous quand la méthode __init__
a assigné son argument
filename à
self["name"]. Voici le résultat. Les
arguments que nous passons lorsque nous créons une instance de
classe sont envoyés directement à la méthode
__init__ (en même temps que la référence à
l'objet, self, que
Python ajoute automatiquement).
En Python, vous appelez simplement
une classe comme si c'était une fonction pour créer une nouvelle
instance de la classe. Il n'y a pas d'opérateur new
explicite comme pour C++
ou Java.
5.4.1. Ramasse-miettes
Si créer des instances est simple, les détruire est encore plus
simple. En général, il n'y a pas besoin de libérer explicitement les
instances, elles sont libérées automatiquement lorsque les variables
auxquelles elles sont assignées sont hors de portée. Les fuites mémoire
sont rares en Python.
Exemple 5.8. Tentative d'implémentation d'une fuite mémoire
>>> def leakmem():... f = fileinfo.FileInfo('/music/_singles/kairo.mp3')... >>> for i in range(100):... leakmem()
A chaque fois que la fonction leakmem
est appelée, nous créons une instance de
FileInfo et l'assignons à la variable
f, qui est une variable locale à la fonction.
La fonction s'achève sans jamais libérer f,
vous pourriez donc vous attendre à une fuite mémoire, mais vous
auriez tort. Lorsque la fonction se termine, la variable locale
f est hors de portée. A ce moment, il n'y a
plus de référence à l'instance nouvellement créée de
FileInfo (puisque nous ne l'avons jamais
assignée à autre chose qu'à f),
Python détruit alors l'instance pour
nous.
Peu importe le nombre de fois que nous appelons la fonction
leakmem, elle ne provoquera jamais de fuite
mémoire puisque Python va détruire à
chaque fois la nouvelle instance de la classe
FileInfo avant le retour de
leakmem.
Le terme technique pour cette forme de ramasse-miettes est
«comptage de référence». Python
maintien une liste des références à chaque instance créée. Dans
l'exemple ci-dessus, il n'y avait qu'une référence à l'instance de
FileInfo : la variable locale
f. Quand la fonction se termine, la variable
f sort de la portée, le compteur de référence descend
alors à 0 et Python
détruit l'instance automatiquement.
Dans des versions précédentes de
Python, il y avait des situations où le
comptage de référence échouait et Python ne
pouvait pas nettoyer derrière vous. Si vous créiez deux instances qui se
référençaient mutuellement (par exemple une liste doublement chaînée où
chaque noeud a un pointeur vers le noeud prochain et le précédent dans
la liste), aucune des deux instances n'était jamais détruite car
Python pensait (correctement) qu'il y avait
toujours une référence à chaque instance.
Python 2.0 a une forme additionnele de
ramasse-miettes appelée «mark-and-sweep» qui est assez
intelligente pour remarquer ce blocage et nettoyer correctement les
références circulaires.
En tant qu'ancien étudiant en Philosophie, cela me dérange de
penser que les choses disparaissent quand personne ne les regarde, mais
c'est exactement ce qui se passe en Python.
En général, vous pouvez simplement ignorer la gestion mémoire et laisser
Python nettoyer derrière vous.