Cours Python avec exercices

écrit par Christophe Darmangeat dans le cadre du M2 PiSE

Python, un langage objet

Au cours de cet enseignement, on ne mettra pas spécialement l'accent sur le fait que Python est un langage objet et sur ce que cela implique. Autrement dit, au travers du langage python, il ne s'agit pas de pénétrer la logique spécifique de la programmation objet. Cependant, étant donné qu'on sera amené à croiser cette logique plus d'une fois et à en tenir compte, autant la comprendre, d'autant qu'elle gouverne aujourd'hui de très nombreux langages.

1. C'est quoi, un langage objet ?

Python, mais aussi bien d'autres langages (Java, Javascript, Visual Basic, C#, pour ne citer que les plus connus), sont des langages objets. Ces langages, apparus dans les années 1990, s'opposent à ceux de la génération précédente, qui étaient dits « procéduraux », comme le Cobol, le Fortran, le Pascal, le C et bien d'autres.

La première chose à dire des langages objet, c'est qu'ils permettent de faire tout, absolument tout, ce qu'on pouvait faire avec un langage procédural. Donc, et c'est la bonne nouvelle du jour, rien de ce que vous avez appris jusque là n'est perdu ! Les langages objet, comme leurs ancêtres les langages procéduraux, manipulent des variables, des tableaux et des structures, et organisent des instructions d'affectation, d'entrée-sortie, de tests ou de boucles dans des procédures et des fonctions. Donc, à la limite, on peut (presque) programmer en langage objet exactement comme on programmait en langage procédural. C'est d'ailleurs ce que nous ferons la plupart du temps avec Python. La programmation objet constitue cependant un monde fascinant (et fort utile) qu'il serait bien dommage d'ignorer.

Le nom choisi pour certains langages objets est d'ailleurs censé suggérer cette montée en puissance par rapport aux langages traditionnels. C'est ainsi que le plus célèbre des langages procéduraux, le C, a donné naissance à deux principaux avatars objets : ainsi, il y a le C++, c'est-à-dire le « C augmenté de 1 », puisqu'en C, l'instruction ++ incrémente la variable qui le précède d'une unité. Il y a aussi le C#, qui est un clin d'oeil (d'oreille ?) aux musiciens : en anglais, C correspond à notre note Do. Le C#, c'est donc le do dièze, situé juste au-dessus du do. Et après ça, on dira que les informaticiens ne sont que des bourrins de technique incapables de toute poésie ?

Les langages objet, tout en intégrant donc l'ensemble des capacités des langages procéduraux, possèdent deux grandes aptitudes supplémentaires, liées mais distinctes. Ces langages peuvent en effet :

  • gérer, en plus des variables, des tableaux et des structures, des choses appelées objets.
  • exploiter l'interface graphique de Windows.

Autant le dire tout de suite, si Python remplit parfaitement sa mission sur le premier point, il n'exploite le second que de manière très limitée, par rapport à des langages comme Java ou C#. C'est un choix de ses concepteurs : ce langage n'est pas fait (en tout cas, pas prioritairement) pour proposer de jolies interfaces graphiques bien léchées, et une application python aura la plupart du temps la mine rustique de l'informatique faite par et pour les geeks, les vrais, ceux qui n'ont pas besoin que ce soit joli (et à la limite, plus c'est moche, plus ça prouve que c'est du sérieux).

1.1 Qu'est-ce qu'un objet ? Parlons comme les gens normaux

Dans la vie de tous les jours, nous sommes entourés d'objets. Certains très simples, comme un peigne, un bouton de culotte ou une matraque de CRS. D'autres beaucoup plus complexes comme une automobile, un ordinateur ou une navette spatiale. Pour faire l'analogie avec les objets des langages objet, mieux vaut penser à un objet un peu compliqué qu'à un objet trop simple. Et pour cette analogie, rien ne nous oblige à penser à un objet inanimé. Des plantes, des animaux ou des êtres humains peuvent tout à fait être assimilés aux objets que manipulent les langages.

Dans les objets, il y a trois sortes de choses qui intéressent les informaticiens.

  • ils possèdent des caractéristiques : une couleur, une taille, un poids, un compte en banque, un nombre de pattes, bref, que sais-je encore). Un objet très simple peut avoir une seule caractéristique (voire aucune, mais là, on peut raisonnablement se demander s'il existe - je laisse cette question aux philosophes désoeuvrés). Un objet complexe peut posséder des centaines, voire des milliers de caractéristiques.
  • ils peuvent accomplir certaines tâches sur demande, ou subir certaines modifications : une automobile peut voir son moteur tourner plus ou moins vite, Un chat peut marcher, courir, miauler, ronronner, etc. Un employé peut travailler, changer de bureau, engueuler son collègue, etc.
  • ils peuvent réagir automatiquement à certains événements : une automobile se met à hurler si on essaye de fracturer la serrure, un chien aussi si le facteur sonne à la porte, le chat court s'il voit une souris, etc.

Tous les objets possédant les mêmes caractéristiques, capables d'accomplir les mêmes tâches sur demande et de réagir automatiquement aux mêmes évènements forment un groupe qu'on appelle une classe. Par exemple, tous les chiens, et c'est à cela qu'on les reconnaît, ont une couleur de pelage, une taille, un poids, etc. Ils peuvent tous aboyer, courir, sauter, etc. Ils ont donc en commun de posséder certaines caractéristiques et de pouvoir effectuer certaines actions, et font donc partie d'une classe unique que j'appelle « les chiens ». Cela n'empêche nullement chacune de ces aptitudes d'être différente d'un chien à l'autre : le chihuahua de ma cousine est très différent du rottweiler de mon voisin, ma cousine en sait quelque chose lorsqu'elle croise mon voisin. Il n'empêche : tous deux sont des chiens, et pas des porte-manteaux ou des téléviseurs (qui, eux aussi, ont des tailles, des poids et des aptitudes différentes selon les modèles).

En prenant le problème à l'envers : si je définis une classe par l'ensemble de ses caractéristiques et de ses actions, je peux, à partir de cette classe, fabriquer tout plein de toutous différents les uns des autres, mais qui auront en commun d'être tous des chiens (donc, répétons-le lourdement, des êtres qui partageront les mêmes caractéristiques et qui seront capables des mêmes actions).

Eh bien, les langages objet, ce sont des langages qui permettent, en plus des traditionnels variables, tableaux et structures, de gérer et de manipuler des objets (donc des classes). C'est-à-dire que ces langages permettent notamment :

  • de créer des classes, en définissant les caractéristiques et les actions dont seront capables les objets qui en seront issus
  • de fabriquer des objets à partir de ces classes
  • de manipuler les caractéristiques individuelles de chacun de ces objets, et de leur faire accomplir les actions dont ils sont capables.

Tout ce que nous avons vu là peut être traduit dans des termes techniques propres aux informaticiens.

1.2 Qu'est-ce qu'un objet ? Parlons comme les informaticiens

Nous savons que tout programme informatique a pour but de manipuler des informations. Et nous savons que ces informations relèvent toujours, au bout du compte, de l'un des trois grands types simples : numériques, caractères (alphanumériques), ou booléens.

Lorsque nous disons qu'un objet (ou une classe) possède des caractéristiques comme la taille, le poids, la couleur, etc., nous disons en fait qu'un objet (ou une classe) regroupe un certain nombre de variables : une variable numérique pour stocker le poids, une autre variable numérique pour stocker la taille, une variable caractère pour stocker la couleur, etc.

Donc, première chose, un objet regroupe un ensemble de variables qui peuvent être de différents types. Et dans ce cas, on ne parlera pas des « variables » d'un objet, ni des ses « caractéristiques », mais de ses propriétés (ou encore, de ses attributs). Une propriété d'objet étant une des variables associées à cet objet, toute instruction légitime avec une variable est légitime avec une propriété d'un objet. Et lycée de Versailles (c'est du latin), tout ce qui n'avait pas de sens avec une variable n'a pas non plus de sens avec une propriété d'un objet.

Mais tout cela, allez-vous dire, n'est qu'une manière d'inventer des termes nouveaux pour parler de quelque chose qu'on connaît déjà depuis belle lurette. Parce qu'enfin quoi, un bidule constitué de différentes variables de différents types, on n'a pas attendu les objets pour en avoir. Tous les langages procéduraux connaissent cela, sauf qu'on ne parle pas de classe mais de structures, qu'on ne parle pas d'objets mais de variables structurées, et qu'on ne parle pas de propriétés, mais de champs. Mais pour le reste, c'est tutti quanti et du pareil au même.

Les mauvais esprits qui feraient cette remarque auraient parfaitement raison... si les objets n'étaient effectivement qu'un ensemble de caractéristiques (de propriétés). Mais les objets ne sont pas que cela : ils incluent également, comme on l'a vu, des actions possibles. Autrement dit, un objet (une classe) est un assemblage d'informations (les propriétés) mais aussi d'instructions (les actions, que l'on appelle les méthodes) et de réactions automatiques à des évéments. C'est la présence de ces méthodes et de ces événements qui différencie une classe d'une simple structure, et un objet d'une simple variable structurée.

On peut donc dire qu'une classe, c'est une structure plus des méthodes (procédures et fonctions) et des événements.

Note : Une méthode est un ensemble d'instructions associé à un objet (car associée à sa classe). Toute méthode est donc une procédure ou une fonction.

Nous mettons donc dès à présent le doigt sur la différence profonde qui existe entre un langage procédural traditionnel et un langage objet : il s'agit de la manière dont sont articulées les informations et les traitements permettant de les modifier.

Dans un langage procédural, il existe une séparation rigoureuse entre les informations et les traitements qui les modifient. Au cours de l'exécution d'un programme, les informations sont stockées des conteneurs spécifiques (variables, tableaux, structures) et les traitements (instructions) agissent sur ces informations, si j'ose dire, « du dehors ». Dans un langage objet, on a regroupé au sein d'une même entité (la classe, donc les objets qui en sont issus) les propriétés et les méthodes, c'est-à-dire les informations et les instructions qui permettent de les manipuler. Autrement dit, les concepteurs d'une classe peuvent faire en sorte que les propriétés ne soient plus librement accessibles par les programmeurs - au risque de provoquer des erreurs en leur affectant des valeurs problématiques – mais qu'elles soient dissimulées, protégées, par du code qui en régit l'accès, exactement comme sur un téléviseur ou un amplificateur Hi-fi, l'utilisateur ne modifie l'état de la machine qu'au travers une série de boutons qui limitent ses actions. Cette façon de protéger l'accès aux propriétés par du code (des méthodes) porte le doux nom d'encapsulation.

2. La syntaxe objet

2.1 Généralités

Lorsque nous fabriquions (et nous en fabriquerons encore) une variable, nous utilisions un « moule » à variable, qui s'appelle un type. Pour créer une nouvelle variable, il fallait préciser le type utilisé pour la fabrication de cette variable, par exemple un entier, et lui donner un nom par lequel on la désignerait ensuite tout au long du programme. Dans la plupart des langages, il est même possible de l'affecter directement à la création, par exemple par la valeur 100. D'où la syntaxe en C :

int toto = 100;

En ce qui concerne les objets, le principe est exactement le même, hormis qu'on ne les fabrique pas d'après un type, mais d'après une classe. Si nous disposons par exemple d'une classe Chien, nous allons pouvoir créer autant de chiens individuels que nous voulons. Voilà par exemple un nouveau compagnon :

Rantanplan = Chien();

Ici, deux remarques s'imposent. La première est que la classe requiert la présence d'une paire de parenthèses. En fait, en créant un objet d'après cette classe, on utilise une méthode de la classe, et on effectue donc un appel de fonction. Le second point est que cette syntaxe légère est particulière à Python. Dans la plupart des autres langages-objet, la syntaxe est un peu plus fournie, en particulier avec la présence de ce qu'on appelle un constructeur, qui s'avère la plupart du temps être le mot new. Je vous laisse approfondir ce point en Java...

Au passage, profitons-en pour régler un point de vocabulaire. Selon les termes techniques consacrés, créer un objet d'après une classe se dit instancier la classe. Un objet s'appelle donc aussi une instance de classe.

Notre classe Chien ayant forcément été créée avec un certain nombre de propriétés et de méthodes, pour chaque objet instancié à partir de cette classe, nous pouvons donc accéder à ces propriétés et à ces méthodes. Ceci s'effectue par la syntaxe suivante, universelle :

NomObjet.NomPropriété

Et également :

NomObjet.NomMéthode

Remarque fondamentale : dans un langage objet, on ne peut rencontrer que les deux syntaxes ci-dessus. Sauf dans des cas exceptionnels, il est impossible de désigner un objet sans le faire suivre d'une propriété ou d'une méthode : c'est forcément une faute de syntaxe. De même, on ne trouvera jamais une propriété ou une méthode seules, non précédées de l'objet auxquelles elles se réfèrent.

2.2 Propriétés

Admettons pour les besoins de la cause que notre classe Chien possède entre autres propriétés :

  • Taille (float)
  • Poids (integer)
  • Couleur (string)
  • Vacciné (bool)

Alors, je le rappelle, ces propriétés étant en réalité des variables – les champs d'une structure – les règles de leur utilisation sont très exactement les mêmes que celles des variables. Sachant que le signe d'affectation, en Python, est le signe d'égalité, je peux donc écrire :

Rantanplan.Poids = 14;

Et je viens de fixer le poids de mon toutou à 14 kg. Pour le faire grossir de 5 kg, rien de plus simple :

Rantanplan.Poids = Rantanplan.Poids + 5;

...et le tour est joué. Si je veux torturer la pauvre bête, je peux aussi la rendre aussi lourde que haute, en écrivant :

Rantanplan.Poids = Rantanplan.Taille;

L'utilisation de propriétés non numériques ne pose pas davantage de problèmes :

Rantanplan.Couleur = "Beige";
Rantanplan.Vacciné = True;

2.3 Méthodes

Faut-il le répéter, les méthodes sont des fonctions ou des procédures qui ont été définies pour tous les objets d'une classe donnée. Utiliser convenablement une méthode suppose donc de respecter la manière dont la procédure ou la fonction a été écrite. En particulier, comme à chaque fois en pareil cas, il va falloir respecter le nombre et le type des paramètres dont la méthode (la procédure, la fonction) a besoin pour s'exécuter. Ainsi, certaines méthodes peuvent-elles être utilisées sans passer de paramètres. D'autres en exigeront un, d'autres deux, etc.

Lorsque la méthode est un appel de procédure, elle représente en elle-même une instruction à part entière. Lorsqu'elle est un appel de fonction, elle renvoie un résultat. Les appels aux méthodes pourront donc donner lieu à des lignes du genre :

Rantanplan.Aboyer();

...si la méthode Aboyer s'emploie sans arguments,

Rantanplan.Courir(15);

...si la méthode Courir nécessite un argument numérique, celui fixant la vitesse de course.

Rantanplan.DonnerlaPapatte("gauche");

...si la méthode DonnerlaPapatte réclame un argument de type caractère, etc.

Pour finir, ce qui précède ne constitue évidemment qu'un premier aperçu de la programmation objet. Il reste envore bien des aspects à découvrir, dont un qui constitue un petit univers à lui tout seul : celui de la programmation événementielle. Nous y reviendrons en temps utile.