M1 Informatique - Python - Cours 2

Orientation objet: les classes et leurs instances

On voit qu'il y a déjà pas mal d'attributs prédéfinis.
Les attributs commençant et finissant par deux soulignés sont les méthodes spéciales (ou attributs spéciaux). Ils ne sont pas destinés à être appelés tels quels (on écrira len(x) plutôt que x__len__()).

Ils permettent la surcharge des opérateurs.

Les méthodes sont définies comme des fonctions ordinaires. Leur premier argument doit toujour être l'instance appelante, conventionnellement appelée self (équivalent de this dans d'autres langages, mais self n'est pas un mot réservé).

La méthode spéciale __init__ sert à initialiser les instances. Elle est appelée imédiatement après la création d'une instance. Son premier argument est l'instance elle même, les suivants sont les paramètres éventuels :

Les attributs (modifiables) d'un objet sont enregistrés dans un dictionnaire object.__dict__

On peut ajouter des attributs à la volée :

Héritage

À la place de object, on peut passer en argument n'importe quel type existant. La classe crée héritera de ses attributs, et on pourra les modifier si nécessaire. S'il y a des paramètres à initialiser, on doit appeler la méthode __init__ de la classe parent.

On voit que Blah a hérité de l'addition des listes. On lui a seulement rajouté une méthode de multiplication, qui définit l'opération $*$.

Les instances des classes dérivées sont vues comme des instances de leurs parents.

Les classes de Python 3 possèdent une méthode __new__ qui prend en charge la construction de l'instance.

Elle est utile pour sous-classer les types non mutables :

L'attribut __class__ d'un objet fait référence à la classe dont il est une instance. Il permet aux instances d'accéder aux attributs de la classe elle-même.

La classe suivante possède un compteur qui compte le nombre de ses instances.

count est un attribut de la classe counter.

__class__ est un attribut prédéfini de toute instance d'une classe. C'est une référence à la classe dont self. est une instance.

count est accessible par référence directe à la classe, avant même la création d'une instance. Chaque instanciation incrémente count, ce qui affecte la classe elle-même.

Sans l'attribut __class__ on aurait

Public, privé, protégé

Python distingue les attributs publics et privés. Sont privés tous ceux qui commencent (mais ne finissent pas) par un double souligné.

Python n'a pas d'attributs protégés, c'est à dire accessibles seulement dans les classes dérivées. L'usage est de les préfixer par un simple souligné, de manière à ce que les utilisateurs d'une classe comprennent qu'il s'agit d'un détail d'implémentation, mais qu'ils restent accessibles aux classes dérivées.

Propriétés

Python supporte les propriétés, c'est à dire, les couples de méthodes fget/fset qui sont appelées de manière transparente lorsqu'on accède à un attribut.

Attributs statiques et méthodes statiques

N'ont pas besoin de connaître l'instance, et ne peuvent pas modifier l'état de leur classe.

Méthodes de classes

Elle n'ont besoin que de connaître les paramètres de leur classe, qui leur est donnée par l'argument cls (au lieu de self), pas ceux des instances. Le mécanisme est similaire. Elles peuvent modifier les paramètres de leur classe.

Les exceptions

Mots clés : try - except - raise - finally

La clause finally permet de terminer proprement (en refermant fichiers, sockets, etc. par exemple). Elle sera exécutée quoi qu'il arrive (et avant les éventuels gestionnaires d'exception).

On peut capturer les exceptions :

Les exceptions prédéfinies sont décrites dans la documentation du module exceptions.

On peut définir de nouvelles exceptions :

Commentaires et docstrings

Le commentaires ordinaires commencent par des #. Une chaîne flottant à l'intérieur d'un programme est vue comme un commentraire. Juste après une définition, elle esyt vue comme une docstring.

L'itération en Python

Syntaxe :

for i in iterable_object: do_something

Les listes, tuples, chaînes et dictionnaires sont itérables.

Les objets itérables possèdent une méthode __iter__ qui renvoie un itérateur.

On l'appelle au moyen de la fonction iter

Un itérateur possède une méthode next() qui renvoie l'élément suivant.

Normalement, on écrit plutôt

On remarque que l'itérateur se consume au fur et à mesure que next est appelée. Si on continue :

for x in obj:
   # faire quelque chose

est équivalent à

_iter = iter(obj)
while 1:
    try:
        x = next(_iter)
    except StopIteration:
        break
    # faire quelque chose

Les générateurs permettent de créer des itérateurs sur des objets qui n'ont pas besoin d'être contruits à l'avance. La syntaxe est identique à celle des fonctions ordinaires, avec le mot clé yield au lieu de return. La fonction retourne alors un générateur.

L'exécution est stoppée après yield et reprend à l'appel suivant de next().

Expressions generatrices

Lorsqu'on remplace les crochets par des parenthèses autour d'une liste en compréhension, on obtient un générateur :

On peut définir des classes qui supportent l'itération : il suffit d'implémenter les méthodes $\tt\_\_iter\_\_$ et next:

Manipulation de fichiers

La fonction open permet de créer ou de modifier des objets de type fichier (file objects). Un fichier peut être ouvert dans les modes 'r','w','a','rw' (read,write,append,read-write) et 'b' (binary, pour windows). En python 3, c'est un peu différent, il faut préciser un encodage.

Ces file objects ont des méthodes read et write.

Il ne faut pas oublier de refermer un fichier ouvert avec la méthode close().