Programmation orientée objet
Retour au sommaire
Introduction
- SourceIl est temps de mettre le doigt sur une caractéristique fondamentale de Python. Python est un langage dit de haut niveau, dans le sens où il permet une certaine abstraction vis-à-vis de la machine. Comprenez par là que les outils qui sont mis à votre disposition en Python sont censés vous donner une plus grande liberté, en vous obligeant à vous soucier de moins de détails que dans d'autres langages.
L'abstraction, cette capacité qu'il faut développer à détacher différents éléments les uns des autres pour pouvoir tous les comprendre et/ou les programmer chacun à leur tour, est facilitée en Python par l'introduction d'un concept assez populaire de nos jours : la programmation orientée objet. C'est un terme qui veut tout et rien dire à la fois (et, de fait, qui est employé par à peu près tout le monde de manière abusive) : nous allons découvrir une nouvelle façon de concevoir les données, qui sera très générale (et s'appliquera à toutes les données) mais pourtant assez précise et élaborée pour nous donner un confort certain dans l'écriture de nos programmes.
Présenté comme ça, ça a l'air surpuissant, non ?
Un nouveau concept
- SourceJusqu'à maintenant, nous avons rencontré différents types de données : les entiers, les flottants, les chaînes et les booléens. Chacun nous a paru différent, notamment en proposant ses propres opérations que les autres ne partageaient pas nécessairement. C'est normal, toutes ces données ne s'utilisent pas dans les mêmes situations. Lorsque nous manipulons une chaîne, Python gère pour nous les allocations mémoire pour la stocker, ce qui nous simplifie grandement la tâche et nous permet de nous concentrer sur l'essentiel (à savoir, nos programmes et nos algorithmes). De même, lorsque nous manipulons des nombres décimaux, Python s'occupe à notre place des arrondis, qui sont un problème épineux en informatique.
Tout ceci se fait à notre insu. Python nous propose une interface cohérente et simple qui nous permet de faire abstraction de ces problèmes. Tout se passe, en fait, comme si les nombres, les chaînes et les autres données savaient eux-mêmes comment se gérer, pour nous éviter ces tracas. En fait, nous pouvons considérer que c'est le cas : quelque part dans Python, des types de données ont été définis, et nous nous contentons de les utiliser à travers les opérations qu'ils proposent. Ces types, en interne, possèdent des variables privées (auxquelles nous ne pouvons pas accéder), et les fonctions définissant les opérations qui nous sont proposées utilisent ces variables privées pour, par exemple, gérer les arrondis de manière intelligente. Tout cela ne nous concerne pas, nous ne sommes que des utilisateurs.
C'est à peu de choses près dans cet état d'esprit que nous définirons la programmation orientée objet, du moins dans un premier temps : désormais, quand nous parlerons d'objets, nous considérerons des données de notre programme appartenant à un certain type, qui nous masquent leur fonctionnement et nous proposent des opérations pour être manipulés.
Comme nous l'avons constaté, tous les entiers supportent les mêmes opérations, même s'ils sont tous différents. Ces opérations sont en fait définies au sein d'un objet particulier, appelé classe, qui sert de moule pour chaque entier. En fait, la classe des entiers est tout simplement int, dont nous avons déjà parlé. De même, la classe des chaînes est str, et ainsi de suite. Nous reviendrons sur les classes et la façon dont on les définit dans quelques chapitres, pour l'instant nous nous contenterons d'utiliser des classes déjà définies.
Les objets possèdent, comme nous l'avons dit, un état interne qu'ils ne nous communiquent pas nécessairement. Néanmoins, il est possible d'accéder à une partie de ces variables lorsque ces objets le proposent. On les appelle alors champs, attributs ou propriétés (même si ce nom désigne plutôt un concept proche mais différent que nous étudierons... dans longtemps). Par exemple, on pourrait définir des objets de type ordinateur, qui posséderaient un champ nommé système, qui contiendrait le système d'exploitation utilisé (qui pourrait être stocké sous la forme d'une chaîne de caractères ou d'un objet d'une autre nature). En Python, on écrirait alors ordi.système pour accéder au champ système de l'objet ordi.
Une interaction plus importante peut être définie avec les objets, sous la forme de fonctions possédées par ceux-ci, et appelées méthodes. Elles se comportent de l'extérieur comme des fonctions : elles peuvent prendre des arguments et renvoyer un résultat. Cependant, elles font un petit peu plus puisque, la plupart du temps, elles modifient également l'objet qui les possède. Nous reviendrons sur leurs propriétés au long de notre apprentissage de Python. Pour faire appel à la méthode meth de l'objet obj, on écrit obj.meth.
Des tas de nouvelles opérations
- SourceQuelle différence y a-t-il alors entre les fonctions et les méthodes ? L'appartenance à un objet. Une méthode agit toujours sur l'objet qui la possède. Souvent, quand plusieurs objets seront susceptibles d'être utilisés d'une même façon, on préférera en Python passer par une fonction capable de traiter ces différents types (bien souvent en appelant par la suite une méthode particulière de l'objet). Par exemple, dans certains langages comme Smalltalk ou Io, print est une méthode plutôt qu'une fonction, et chaque objet la redéfinit à sa façon (puisqu'elle change de comportement selon l'objet étudié).
Mais quand les opérations sont plus spécifiques à un type d'objet, on les utilisera surtout en faisant appel à des méthodes. Maintenant que nous connaissons ces concepts, nous allons pouvoir découvrir de nouvelles opérations sur les chaînes de caractères.
Changer la casse
Premièrement, découvrons la possibilité de changer facilement la casse d'une chaîne. Les méthodes upper et lower convertissent respectivement les caractères d'une chaîne cible en majuscules et en minuscules. La chaîne transformée est renvoyée par la fonction (notez bien que la chaîne initiale n'est pas modifiée). N'hésitez pas à faire quelques expériences dans le shell Python ou à l'aide d'un script :
>>> "bonjour à tous".upper() 'BONJOUR À TOUS' >>> "Les accents sont bien supportés : éàçâü".upper() 'LES ACCENTS SONT BIEN SUPPORTÉS : ÉÀÇÂÜ' >>> s = "Une chaîne" >>> s.upper() 'UNE CHAÎNE' >>> print(s) Une chaîne
Sans doutes moins utiles, les méthodes capitalize et title permettent de transformer respectivement la première lettre d'une chaîne, et la première lettre de chaque mot :
>>> "premier essai".capitalize() 'Premier essai' >>> "deuxième essai".title() 'Deuxième Essai'
L'intérêt de la méthode titleest malheureusement limité, puisqu'en Français les titres ne s'écrivent pas Avec Une Majuscule Au Début De Chaque Mot. Mais bon…
Chercher une sous-chaîne
Il y a plusieurs moyens d'intéragir avec le contenu d'une chaîne. Nous verrons au chapitre suivant comment considérer chaque caractère, et comment découper une chaîne selon selon un ou plusieurs indice(s). Pour l'instant, étudions simplement quelques outils pratiques pour étudier ce que contient une chaîne.
La méthode count compte le nombre d'occurrences d'une chaîne. Elle prend des paramètres optionnels, qui sont les positions de début et de fin de la recherche :
>>> "ceci est une phrase".count("e")
4
>>> "ceci est une phrase".count("e", 6, 11)
0
>>> "ceci est une phrase".count("e", 5, 11)
1
La méthode find renvoie le premier indice auquel on a trouvé la chaîne passée en argument. Elle aussi peut prendre des paramètres pour délimiter la zone de recherche. Elle renvoie -1 si rien n'a été trouvé. La méthode rfind effectue le même travail mais renvoie l'indice le plus élevé. Les méthodes index et rindex font le même travail, mais déclenchent une erreur quand la chaîne n'est pas trouvée, au lieu de renvoyer -1.
>>> "ceci est une phrase".find("est")
5
>>> "ceci est une phrase".find("est", 2, 7)
-1
>>> "ceci est une phrase".find("est", 2, 8)
5
>>> "ceci est une phrase".rfind("est", 2, 8)
5
Enfin, les méthodes startswith et endswith prennent en argument une chaîne et vérifient si celle-ci se trouve respectivement au début et à la fin de la chaîne étudiée, en renvoyant un booléen.
Altérer une chaîne
Plusieurs opérations permettant de modifier une chaîne sont possibles (la chaîne modifiée étant renvoyée). Il est d'abord possible de rogner les espaces de début et de fin à l'aide de la méthode strip :
>>> s = " cette chaîne va être rognée ! " >>> s.strip() 'cette chaîne va être rognée !'
Les méthodes lstrip et rstrip font le même travail, mais se limitent respectivement à la gauche et à la droite de la chaîne.
Il est également possible de remplacer une sous-chaîne par une autre, à l'aide de la méthode replace :
>>> ch = "J'adore le PHP !"
>>> ch.replace("PHP", "Python")
"J'adore le Python !"
Cette dernière méthode peut également prendre en paramètre le nombre de remplacements à faire.
>>> ch = "Bettlejuice ! Bettlejuice ! Bettlejuice !"
>>> ch.replace("Bettlejuice", "Python", 2)
'Python ! Python ! Bettlejuice !'
Au fait, essayez, dans une chaîne de votre choix, de remplacer la chaîne vide par une autre chaîne de votre invention. Que se passe-t-il ?
Différents tests
Afin de vérifier la pertinence de l'entrée d'un utilisateur, il peut être intéressant de tester la forme du contenu d'une chaîne (par exemple avant de risquer une conversion en entier). Python propose différents tests, dont le nom commence à chaque fois par is, renvoyant un booléen. On trouve notamment les tests isupper, islower et istitle qui testent la casse d'une chaîne.
Les tests isalnum, isdigit et isspace peuvent servir à vérifier qu'une chaîne n'est composée respectivement que de caractères alphanumériques, de chiffres ou d'espaces, ce qui inclut notamment les retours à la ligne et les tabulations. Rappelons que les retours à la ligne s'écrivent avec la notation spéciale "n" et que les tabulations se notent "t".
Le test isprintable vérifie, enfin, qu'une chaîne ne contient que des caractères affichables (ce qui inclut par exemple l'espace mais exclut le retour à la ligne ou la tabulation).
Le programme suivant s'assure de bien recevoir un âge entier de la part de l'utilisateur :
entree = "" while not entree.isdigit(): print("Entrez votre âge s'il vous plaît") entree = input() print("Vous avez", entree, "ans.")
Exercices :
- Essayez, dans le shell Python, le code
str.lower("FOO"). Que se passe-t-il selon vous ? Trouvez un autre exemple avec une méthode prenant d'habitude plusieurs arguments, comme la méthodereplace.