Python from Scratch Programmation orientée objet

Bienvenue à la quatrième leçon de notre Python à partir de zéro séries. Ce didacticiel suppose une connaissance préalable des variables, des types de données, des fonctions et de la sortie imprimée. Si vous n'êtes pas à jour, consultez les trois articles précédents de la série pour vous mettre à jour..

Aujourd'hui, nous allons nous pencher sur le sujet de la programmation orientée objet (OO). La POO est un moyen très puissant d’organiser votre code, et une solide compréhension des concepts qui le sous-tendent peut réellement vous aider à tirer le meilleur parti de votre code..


Préférer un screencast?


Transcription


Qu'est-ce que la programmation orientée objet??

Python est principalement conçu comme un langage de programmation orienté objet - mais que signifie "orienté objet"??

Il existe une variété de définitions pour le terme, et vous pourriez parler littéralement pendant des heures en essayant d'expliquer les tenants et les aboutissants, les nuances et les différences dans les implémentations, mais je vais essayer de vous donner un aperçu rapide..

En gros, la programmation orientée objet est le concept selon lequel, dans la programmation, les objets que nous manipulons sont plus importants que la logique nécessaire pour manipuler ces objets. Traditionnellement, un programme était considéré comme une recette - un ensemble d'instructions que vous suivez du début à la fin pour mener à bien une tâche. Cela peut encore être vrai, et pour de nombreux programmes simples, c'est tout ce qui est requis. Cette approche est parfois appelée programmation procédurale.

La POO place les objets au centre du processus.

D'autre part, à mesure que les programmes deviennent de plus en plus complexes et compliqués, la logique nécessaire pour les écrire de manière purement procédurale devient de plus en plus tordue et difficile à comprendre. Souvent, les approches orientées objet peuvent aider avec cela.

Lorsque nous parlons d’approches orientées objet, nous plaçons les objets au centre du processus, au lieu de les utiliser simplement en tant que conteneurs d’informations nécessaires dans le cadre de nos instructions procédurales. Tout d'abord, nous définissons les objets que nous voulons manipuler et leur relation les uns aux autres, puis nous commençons à préciser la logique pour que le programme fonctionne réellement..

Quand je parle d’objets, je peux parler de toutes sortes de choses. Un "objet" peut représenter une personne (définie par des propriétés telles que le nom, l'âge, l'adresse, etc.), une entreprise (définie par le nombre d'employés, etc.) ou même quelque chose de beaucoup plus abstrait, comme un bouton dans une interface d'ordinateur.

Dans cette introduction, nous n'allons pas couvrir tous les concepts de ce sujet car nous serions là toute la nuit, mais à la fin du didacticiel, j'espère que vous aurez une solide compréhension des principes dont vous avez besoin. pour commencer tout de suite en utilisant des techniques simples orientées objet dans vos programmes Python. Mieux encore, ces concepts sont assez similaires dans de nombreux environnements de programmation. La connaissance passe assez bien d'une langue à l'autre.


Commencer

J'ai mentionné plus tôt que la première chose à faire lorsque nous adoptons une approche OOP est de définir les objets que nous allons utiliser. Pour ce faire, nous devons d’abord définir les propriétés qu’il possède à l’aide d’une classe. Vous pouvez considérer une classe comme une sorte de modèle. un guide sur la manière dont un objet doit être structuré. Chaque objet appartient à une classe et hérite des propriétés de cette classe, mais agit individuellement avec les autres objets de cette classe..

Un objet est parfois appelé une "instance" d'une classe.

Par exemple, vous pourriez avoir une classe nommée 'personne' avec, par exemple, une propriété age et un nom, et une instance de cette classe (un objet) serait une personne unique. Cette personne pourrait avoir un nom? Andy? et 23 ans, mais vous pouvez simultanément avoir une autre personne appartenant à la même classe avec le nom de? Lucy? et un age de 18 ans.

Il est difficile de comprendre cela sans le voir en pratique, alors allons-y avec du code réel.

Définir une classe

Pour définir une classe, à la manière simple typique de Python, nous utilisons le mot 'classe', suivi du nom de votre nouvelle classe. Je vais faire une nouvelle classe ici, appelée «animal de compagnie». Nous utilisons deux points après le nom, puis tout élément contenu dans la définition de classe est mis en retrait. Cependant, avec une classe, il n'y a pas de parenthèses:

 classe animal de compagnie: 

Alors maintenant, nous avons un cours, mais c'est plutôt inutile sans rien dedans. Pour commencer, donnons-lui quelques propriétés. Pour ce faire, vous définissez simplement certaines variables dans la classe - je vais aller avec le nombre de jambes pour commencer. Comme d'habitude, vous devez toujours nommer vos variables afin qu'il soit facile de savoir ce qu'elles sont. Soyons original et appelons-le 'number_of_legs'. Nous devons définir une valeur ou nous aurons une erreur. J'utiliserai 0 ici (cela n'a pas beaucoup d'importance dans ce cas car le nombre de pattes sera spécifique à chaque instance de la classe - un poisson n'a pas la même quantité de pattes qu'un chien ou un canard, etc. - il faudra donc changer cette valeur pour chaque objet de toute façon).

 classe pet: number_of_legs = 0 

Instances et variables membres

Une classe en soi n'est pas quelque chose que vous pouvez manipuler directement; Tout d'abord, nous devons créer une instance de la classe avec laquelle jouer. Nous pouvons stocker cette instance dans une variable. En dehors de la classe (sans indentation), créons une instance de la classe et stockons-la dans la variable 'doug'. Pour créer une nouvelle instance d'une classe, il vous suffit de taper le nom de la classe, puis une paire de parenthèses. À ce stade, vous n'avez pas à vous soucier des parenthèses, mais vous verrez plus tard qu'elles sont présentes car, comme une fonction, il existe un moyen de transmettre une variable à la classe pour la première fois que vous créez l'instance..

Une classe seule n'est pas quelque chose que vous pouvez manipuler directement.

 classe pet: number_of_legs = 0 doug = pet () 

Maintenant que nous avons une instance d'une classe, comment pouvons-nous accéder à ses propriétés et les manipuler? Pour référencer une propriété d'un objet, nous devons d'abord dire à Python de quel objet (ou de quelle instance de classe) nous parlons, nous allons donc commencer par «doug». Ensuite, nous allons écrire une période pour indiquer que nous référons à quelque chose qui est contenu dans notre instance doug. Après la période, nous ajoutons le nom de notre variable. Si nous accédons à la nombre_de_léges variable, ça va ressembler à ça:

 numéro_de_personne 

Nous pouvons traiter cela maintenant exactement comme nous traiterions n'importe quelle autre variable - ici, je suppose que doug est un chien, et nous allons donner à cette variable la valeur 4.

Pour accéder à cette variable, nous allons l’utiliser à nouveau exactement comme nous traiterions toute autre variable, mais en utilisant cette numéro_de_personne propriété au lieu du nom de variable normal. Mettons dans une ligne pour imprimer combien de jambes a Doug afin que nous puissions montrer qu'il fonctionne comme il se doit:

 class pet: number_of_legs = 0 doug = pet () doug.number_of_legs = 4 print "Doug a% s jambes." % doug.number_of_legs 

Si vous exécutez le code ci-dessus, vous verrez qu'il est imprimé pour nous. Il a défini notre classe 'animalier', créé une nouvelle instance de cette classe et l'a stockée dans la variable 'doug', puis, à l'intérieur de cette instance, la valeur 4 lui a été attribuée. nombre_de_léges variable qu'il a hérité de sa classe.

Vous pouvez donc voir, à partir de cet exemple très simplifié, comment vous pouvez commencer à créer de belles structures de données modulaires, claires et faciles à utiliser, et qui peuvent très bien évoluer..


Présentation de la logique

D'accord, c'est donc la base même des classes et des objets, mais pour le moment, nous ne pouvons vraiment utiliser que des classes en tant que structures de données - ou des conteneurs pour des variables. C'est très bien, mais si nous voulons commencer à effectuer des tâches plus complexes avec les données que nous manipulons, nous avons besoin d'un moyen d'introduire une logique dans ces objets. Nous faisons cela avec des méthodes.

Les méthodes sont essentiellement des fonctions contenues dans une classe. Vous en définissez un exactement comme vous le feriez avec une fonction, mais la différence est que vous le placez dans une classe et que celle-ci appartient à cette classe. Si vous souhaitez appeler cette méthode, vous devez référencer un objet de cette classe, tout comme les variables que nous examinions précédemment..

Les méthodes sont essentiellement des fonctions contenues dans une classe.

Je vais écrire un exemple rapide ici dans notre classe d’animaux de compagnie pour le démontrer; Créons une méthode, appelée 'veille', qui imprimera un message lors de son premier appel. Tout comme une fonction, je vais mettre 'def' pour 'define', puis je vais écrire le nom de la méthode que je veux créer. Ensuite, nous allons mettre nos parenthèses et notre point-virgule, puis commencer une nouvelle ligne. Comme d'habitude, tout ce qui est inclus dans cette méthode va être mis en retrait d'un niveau supplémentaire.

Maintenant, il y a une autre différence entre une méthode et une fonction: une méthode doit toujours, toujours, avoir un argument, appelé «self» entre les parenthèses. Lorsque Python appelle une méthode, elle passe l'objet actuel à cette méthode en tant que premier argument. En d'autres termes, quand on appelle doug.sleep (), Python va en fait passer l'objet 'doug' comme argument à la méthode sleep.

Nous verrons pourquoi c'est plus tard, mais pour le moment vous devez savoir qu'avec une méthode, vous devez toujours inclure un argument appelé 'self' en premier dans la liste (si vous voulez ajouter d'autres arguments, vous pouvez les ajouter). ensuite, exactement comme si vous passiez plusieurs arguments à une fonction). Si vous n'incluez pas cet argument, lorsque vous exécuterez le code, vous obtiendrez une erreur, car Python transmet un argument (cet objet 'self'), et la méthode dit: 'Hey, mec, Je ne prends aucun argument, de quoi parlez-vous? C'est la même chose que si vous essayiez de passer un argument à une fonction qui n'accepte aucun argument.

Alors voici ce que nous avons jusqu'à présent:

 classe pet: number_of_legs = 0 def sommeil (auto): doug = animal () 

Dans cette méthode, nous allons écrire une déclaration print comme ceci:

 classe pet: number_of_legs = 0 def sleep (auto): affiche "zzz" doug = animal () 

Maintenant, si nous voulons utiliser cette méthode, nous utilisons simplement une instance de la classe pet pour la référencer. Comme le nombre_de_léges variable, nous écrivons le nom de l’instance (nous en avons un appelé doug), puis un point, puis le nom de la méthode, y compris les parenthèses. Notez que nous appelons sleep sans arguments, mais Python va ajouter cet argument seul, nous allons donc nous retrouver avec la bonne quantité d'arguments au total..

 classe pet: number_of_legs = 0 def sleep (self): affiche "zzz" doug = pet () doug.sleep () 

Si vous exécutez ce code, vous devriez voir qu'il imprime le message que nous avons écrit.

Les données

Génial, alors pourquoi ne pas écrire une nouvelle méthode pour imprimer le nombre de pattes de l’animal, pour montrer comment utiliser des méthodes pour manipuler les données au sein de la classe, et pour démontrer pourquoi nous devons inclure ce «moi» déroutant argument. Faisons une nouvelle méthode, appelée 'count_legs'.

C’est là que l’argument du «moi» entre en jeu. Rappelez-vous quand nous avions accès à nombre_de_léges de l'extérieur de la classe et nous avons dû utiliser «doug.number_of_legs» au lieu de «number_of_legs»? Le même principe s'applique; si nous voulons savoir ce que contient cette variable, nous devons la référencer en spécifiant d'abord l'instance contenant cette variable.

Cependant, nous ne savons pas comment l'instance sera appelée lors de l'écriture de la classe. Nous contournons cela en utilisant la variable 'self'. 'self' est juste une référence à l'objet en cours de manipulation. Donc, pour accéder à une variable de la classe en cours, il vous suffit de la préfacer par 'self' puis par un point, comme ceci:

 class pet: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "j'ai les jambes% s"% self.number_of_legs doug = pet () doug.number_of_legs = 4 doug.count_legs () 

En pratique, cela signifie que partout où vous écrivez 'self' dans votre méthode, lorsque vous exécutez la méthode, self est remplacé par le nom de l'objet. Ainsi, lorsque nous appelons 'doug.count_legs ()', le 'self' est remplacé par «doug». Pour montrer comment cela fonctionne avec plusieurs instances, ajoutons une seconde instance, représentant un autre animal de compagnie, appelée 'nemo':

 class pet: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "j'ai les jambes% s"% self.number_of_legs doug = pet () doug.number_of_legs = 4 doug.count_legs () nemo = pet () nemo.number_of_legs = 0 nemo.count_legs () 

Cela imprimera un message pour 4 et ensuite 0 jambes, comme nous le souhaitions, car lorsque nous appelons 'nemo.count_legs (),' le 'moi' est remplacé par 'nemo' au lieu de 'doug'.

De cette manière, notre méthode fonctionnera exactement comme prévu car la référence 'self' changera dynamiquement en fonction du contexte et nous permettra de manipuler les données uniquement dans l'objet actuel..

La principale chose à retenir à propos des méthodes est qu’elles sont exactement identiques aux fonctions, sauf que le premier argument doit être 'self' et que pour référencer une variable interne, vous devez préfacer le nom de la variable avec 'self'..

Juste comme note: Vous pouvez réellement utiliser n'importe quel nom au lieu de 'self' pour vos méthodes. -Les méthodes ici fonctionneraient aussi bien si nous renommions la variable 'self' en n'importe quel mot. L'utilisation du nom 'self' est simplement une convention utile aux programmeurs Python, car elle rend le code beaucoup plus standard et facile à comprendre, même s'il est écrit par quelqu'un d'autre. Mon conseil serait de s'en tenir aux conventions.


Quelques fonctionnalités plus avancées

Maintenant que nous avons passé en revue les bases, examinons quelques fonctionnalités plus avancées des classes et expliquez-leur comment elles peuvent faciliter la structuration de votre programmation..

La prochaine chose dont nous allons parler est l'héritage. Comme son nom l'indique, l'héritage est le processus consistant à créer une nouvelle classe autour d'une classe parent et à permettre à la nouvelle classe d'hériter des fonctionnalités de la classe parent. La nouvelle classe peut prendre toutes les méthodes et variables de la classe parente (souvent appelée classe 'base').

L'héritage est le processus de création d'une nouvelle classe autour d'une classe parente.

Étendons notre exemple d'animal pour voir comment cela pourrait être utile. Si nous utilisons 'pet' comme classe parent, nous pourrions créer une classe enfant qui hériterait de la classe pet. La classe enfant peut être quelque chose comme "chien" ou "poisson" - quelque chose qui reste un "animal de compagnie", mais qui est plus spécifique que cela. Un chien est un animal de compagnie et fait les mêmes choses que tous les animaux de compagnie - par exemple, il mange et dort et a un âge et plusieurs jambes - mais il fait d'autres choses qui sont spécifiques à être un chien, ou au moins plus spécifique que d'être un animal de compagnie: les chiens ont de la fourrure, mais pas tous les animaux de compagnie. Un chien peut aboyer ou aller chercher un bâton, mais tous les animaux ne le feraient pas..

Pour en revenir au fait, disons que nous voulions faire un cours dans notre programme pour représenter un chien. Nous pourrions utiliser l'héritage pour hériter des méthodes et des variables contenues dans "pets" afin que notre chien puisse avoir un "nombre de pattes" et la capacité de "dormir", en plus de toutes les choses spécifiques au chien que nous pourrions stocker ou faire..

Maintenant, vous vous demandez peut-être pourquoi nous ne mettons pas ces méthodes et ces variables dans la classe des chiens sans supprimer entièrement la classe des animaux de compagnie? Eh bien, l'héritage nous donne deux avantages distincts par rapport à cette approche: Premièrement, si nous voulons un objet qui est un animal de compagnie, mais n'est pas un chien - un animal de compagnie générique, si vous voulez - nous pouvons toujours le faire. Deux, peut-être plus tard, souhaitons-nous ajouter un deuxième type d'animal de compagnie, peut-être un poisson. Nous pouvons faire en sorte que cette seconde classe hérite également de pet, de sorte que les deux classes puissent tout partager dans pet, tout en ayant leurs propres méthodes et variables plus spécifiques qui ne s'appliquent qu'à ce type d'objet..

La théorie s’embourbe un peu, alors écrivons quelque chose pour la rendre un peu plus claire. Tout d'abord, nous allons écrire une nouvelle classe, appelée 'chien', mais cette fois, entre le nom de la classe et le colon, nous allons mettre des parenthèses et dans celles-ci, nous allons écrire le nom. de la classe dont nous voulons hériter, un peu comme si nous passions un argument à la nouvelle classe, comme une fonction.

Ensuite, donnons à cette classe une méthode simple pour illustrer son fonctionnement. Je vais ajouter un 'écorce'méthode qui va imprimer' woof ':

 class pet: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "j'ai% s legs"% self.number_of_legs class chien (animal domestique): def écorce (self): print "Woof" 

Voyons maintenant ce qui se passe si nous faisons une instance de cette classe. Je vais appeler notre nouveau chien 'doug' à nouveau. Maintenant, si nous appelons doug.bark ():

 class pet: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "j'ai% s legs"% self.number_of_legs class chien (animal domestique): def écorce (self): print "Woof" doug = chien () doug.bark () 

Comme prévu, Doug aboie. C'est bien, mais nous n'avons encore rien vu de nouveau - juste un cours avec une méthode. Ce que l'héritage a fait pour nous, cependant, est de mettre à notre disposition toutes les fonctions et variables de l'animal de compagnie par le biais de notre objet 'doug'. Par conséquent, si je fais quelque chose comme ça:

 class pet: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "j'ai% s legs"% self.number_of_legs class chien (animal domestique): def écorce (self): print "Woof" doug = chien () doug.sleep () 

Ensuite, la méthode sleep sera également exécutée correctement. En effet, notre objet doug appartient à la fois à la classe "animal domestique" et à la classe "chien". Pour que les variables fassent la même chose que les méthodes, essayons ceci:

 class pet: number_of_legs = 0 def sleep (self): print "zzz" def count_legs (self): print "j'ai% s legs"% self.number_of_legs class chien (animal domestique): def écorce (self): print "Woof" doug = chien () doug.number_of_legs = 4 doug.count_legs () 

Vous pouvez voir que doug agit exactement comme avant, montrant que nos variables sont héritées. Notre nouvelle classe enfant est simplement une version spécialisée de la classe parente, avec quelques fonctionnalités supplémentaires mais en conservant toutes les fonctionnalités précédentes.


Voilà donc une introduction rapide à la programmation orientée objet. Restez à l'écoute pour le prochain épisode de cette série, où nous allons travailler avec Python sur le Web.!