Objets et classes

Dans les faits, ce chapitre pourrait faire l'objet d'un cours complet. Nous allons simplement nous concentrer sur les fonctionnalités les plus simples dont vous aurez besoin pour pouvoir travailler avec python. En effet, on peut distinguer deux approches de l'objet en python :

  • Le côté utilisateur, il faut savoir utiliser les objets
  • Le côté développeur, pour la création de nouveaux objets

Nous allons nous focaliser sur le premier point.

Vous pouvez trouver une version jupyter notebook de cette partie sur l'espace de cours elearn.

Toute valeur est un objet

Toutes les choses que nous avons appelées valeur jusqu'à présent peuvent être appelé "un objet" dans l'univers de Python. On dit souvent qu'en Python "tout est objet".

Par exemple les entiers, pour lesquels la fonction help() nous retournait des dizaines de lignes d'information à propos de int() sont aussi des objets.

Tout objet a une classe

Une classe est le type d'un objet (un type d'objet ?). Par analogie, on peut dire que c'est le moule qui permet de créer l'objet.

On peut tout simplement utiliser la fonction type() pour connaitre le type d'un objet :

>>> type(2)
<class 'int'>
>>> type(2.0)
<class 'float'>
>>> type("spam eggs")
<class 'str'>
>>> x = 1, 2
>>> type(x)
<class 'tuple'>
>>> type([])
<class 'list'>

Nous avons déjà parlé des classes que vous pouvez voir ici : int, float, str, tuple.

Quand nous utilisons des nombres dans notre programme, nous attendons qu'ils se comportent comme des nombres, et nous savons intuitivement ce qu'est un nombre. Par contre, Python doit savoir exactement ce que signifie "être un nombre".

Par exemple que se passe-t-il lorsqu'on additionne deux nombres ? Ou qu'on les divise ? La classe int définit tout cela et bien plus.

En utilisant la fonction help(), vérifiez ce que nous donne la classe str. Voici quelques fonctionnalités intéressantes :

>>> help(str.lower)
Help on method_descriptor:

lower(...)
    S.lower() -> str

    Return a copy of the string S converted to lowercase.

>>> help(str.upper)
Help on method_descriptor:

upper(...)
    S.upper() -> str

    Return a copy of S converted to uppercase.

>>> help(str.ljust)
Help on method_descriptor:

ljust(...)
    S.ljust(width[, fillchar]) -> str

    Return S left-justified in a Unicode string of length width. Padding is
    done using the specified fill character (default is a space).

>>> help(str.center)
Help on method_descriptor:

center(...)
    S.center(width[, fillchar]) -> str

    Return S centered in a string of length width. Padding is
    done using the specified fill character (default is a space)

Toutes ces opérations (ou méthodes) sont applicable à n'importe quelle chaîne de caractères. Pour y accéder, on ajoute un point suivi de l'appel de la fonction à appliquer :

>>> x = "Ala"
>>> x.upper()
'ALA'
>>> x.lower()
'ala'
>>> x.center(9)
'   Ala   '

Une fonction appliquée à un objet est appelée une méthode de l'objet. Il est important de comprendre le rôle du point. Dans ces situations, on lit de droite à gauche :

  • méthode upper appliquée à x
  • méthode lower appliquée à x
  • méthode center appliquée à x

Le point sépare en quelque sorte un contenant et un contenu. On applique la méthode upper contenue dans la classe str.

Encore une dernière chose importante, pour créer un nouvel objet, on appelle la classe de l'objet (dans le jargon technique on dit qu'on instancie un objet). L'objet ainsi créé est appelé une instance de la classe :

>>> int()
0
>>> str()
''
>>> list()
[]
>>> tuple()
()

Une instance est donc une nouvelle valeur du type décrit par la classe.

Pour résumer, nous avons vu les classes int(), str(), tuple() et list(). Nous avons vu que pour connaitre la classe décrivant une valeur (un objet), nous pouvions regarder son type avec la fonction type(). Pour créer une instance de la classe (un nouvel objet), on appelle la classe de la même manière que nous appelons une fonction, en ajoutant des parenthèses (). Par exemple : int().

Définir une classe

Les classes telles que int ou str font partie du langage Python et sont déjà définies, mais nous pouvons créer nos propres classes pour définir leur comportement. Cela s'appelle définir une classe.

Il est aussi facile de définir une classe que de définir une fonction. En fait une classe n'est rien de plus qu'un ensemble de fonctions, appelées méthodes. Prenons par exemple une classe Dog qui contient une méthode bark :

class Dog(object):

    def bark(self):
        print("Woof! Woof!")

Les classes commencent par le mot clé class, suivi du nom de la classe. L'(object) indique que le nouveau type Dog est un nouveau type de l'ensemble des classes de type object. Ainsi, les instances de notre classe, c'est à dire les objets créés, seront de type Dog mais également du type plus général des objects. Pour les habitués de la programmation orientée objet, cela signifie que la classe Dog hérite de la classe object, mais laissons cela de côté pour l'instant.

En fait c'est exactement pour cela qu'on dit que "tout est objet en Python". Car chaque classe est une spécialisation de la classe object de Python. C'est pourquoi quasiment chaque valeur est de type général object.

Il est important de noter que chaque fonction d'une classe doit prendre pour premier argument la valeur de l'objet duquel elle a été appelée. Nous l'appelons systématiquement self par convention. Dans notre exemple, nous avons une fonction appelée bark ("aboyer" en anglais), qui comme vous le voyez n'a qu'un seul argument, self. Regardons comment elle fonctionne :

>>> my_new_pet = Dog()
>>> my_new_pet.bark()
Woof! Woof!

Attributs des objets

Outre les méthodes (les fonctions définies dans une classe), les objets peuvent également avoir des attributs. Par exemple :

my_new_pet = Dog()
my_new_pet.name = "Snoopy"

print(my_new_pet.name)
Snoopy

Parfois nous souhaitons que tous les objets d'une classe aient un attribut, par exemple tous les chiens doivent avoir un nom. Nous pouvons le spécifier en créant une fonction, au nom spécial, appelée __init__(). Par exemple, attribuer un nom à notre chien :

class Dog(object):

    def __init__(self, name):
        self.name = name

    def bark(self):
        print("Woof! Woof!")

Dans la fonction __init__(), nous avons assigné une valeur à un nouvel attribut name de l'objet self. Comme expliqué précédemment, self est l'objet courant de la classe Dog que nous sommes en train de manipuler.

Remarque : On retrouve le point qui comme pour les méthodes indique que l'attribut name est un attribut de self (le nom est contenu dans la classe).

Nous pouvons maintenant utiliser cet attribut dans les autres méthodes :

class Dog(object):

    def __init__(self, name):
        self.name = name

    def bark(self):
        print(self.name, " Woof! Woof!")

snoopy = Dog("Snoopy")
pluto = Dog("Pluto")
print(snoopy.bark())
print(pluto.bark())
Snoopy Woof! Woof!
Pluto Woof! Woof!

La fonction __init__() est appelée durant la création de l'objet. On l'appelle constructeur, car elle aide à la création de l'objet et lui donne un état de départ.

Dans cet exemple, la fonction __init__() accepte deux arguments: self et name, mais quand on créé une instance de la classe Dog, nous ne spécifions que l'argument name, self est automatiquement spécifié par Python. Désormais, lorsque que nous instancions un nouvel objet Dog, celui-ci a un attribut : son nom.

Héritage

Dans le chapitre précédent, nous avons créé une classe Dog comme sous-ensemble du type object, mais ce n'est pas la seule possibilité. Nous pouvons également dire que Dog est aussi un Animal :

class Animal(object):
    pass

class Dog(Animal):

    def __init__(self, name):
        self.name = name

    def bark(self):
        print(self.name, " Woof! Woof!")

Nous avons donc une nouvelle classe Animal, qui hérite du type object. Dog hérite du type Animal. En d'autres termes :

  • Tout Animal est un object
  • Tout Dog est un Animal, tout Dog est un object

Ainsi nous pouvons décrire des comportements communs à tous les Animaux dans notre classe Animal, par exemple le fait de courir, et laisser dans la classe Dog des comportements plus spécifiques, comme aboyer:

class Animal(object):

    def run(self, distance):
        print("Run ", distance, " meters.")

La méthode run sera disponible pour tous les sous-types de Animal (comme les objets de type Dog par exemple) :

>>> scooby = Dog("Scooby")
>>> print(scooby.run(10))
Run 10 meters.

Arbre de noël

Revenons à l'arbre de noël que nous avons vu au chapitre précédent. Écrire une classe XMASTree qui pour une taille donnée et lors de l'appel de la méthode draw() va afficher les résultats suivants (pour les tailles 1, 2 et 3) :

  *
 /|\
/_|_\
  |
   *
  /|\
 /_|_\
  /|\
 / | \
/__|__\
   |
    *
   /|\
  /_|_\
   /|\
  / | \
 /__|__\
   /|\
  / | \
 /  |  \
/___|___\
    |

results matching ""

    No results matching ""