Instanciez un objet
Vous vous souvenez de notre exemple de Rectangle et de son constructeur ? Il ressemblait à peu près à ceci :
class Rectangle:
def __init__(self, length, width, color="red"):
self.length = length
self.width = width
self.color = color
Nous utilisons ces constructeurs pour créer des objets d’une classe spécifique. À la fin du chapitre précédent, nous avons écrit quelques constructeurs. Utilisons-les enfin pour créer un objet.
Voici un exemple qui crée un Rectangle
de longueur 5 et de largeur 3 :
rectangle = Rectangle(5, 3)
Lorsque nous instancions un objet, nous devons habituellement l’affecter à une variable pour pouvoir l’utiliser. Dans ce cas, le nom de la variable est « rectangle ». Nous pourrions alors passer rectangle
dans notre programme et appeler des méthodes dessus.
… et le paramètre optionnel ?
Vous vous souvenez peut-être que nous avons dit précédemment que, si un paramètre optionnel n’était pas fourni, le paramètre par défaut serait utilisé. Dans ce cas, notre rectangle de dimension 5 sur 3 est rouge.
On peut utiliser l’une de ces deux options pour spécifier une couleur :
rect1 = Rectangle(4, 2, "blue")
rect2 = Rectangle(3, 1, color="pink")
La deuxième option est plus explicite, et moins susceptible de prêter à confusion si vous avez plusieurs paramètres optionnels.
Reprenons maintenant notre exemple des gâteaux pour voir l’instanciation plus en détail :
Maintenant, vous avez un objet, alors lancez-vous et…
Modifiez un objet
Imaginons que nous ayons notre rectangle de tout à l’heure : rectangle = Rectangle(5, 3)
– utilisons-le !
Nous pouvons accéder aux attributs d’un objet et leur affecter des valeurs comme ceci :
print(rectangle.length)
rectangle.color = "yellow"
Les attributs rectangle.length
et rectangle.color
fonctionnent ici exactement comme d’autres variables le feraient – ils peuvent faire partie d’expressions ou de calculs, être passés comme paramètres à des fonctions/méthodes, et être modifiés. Le grand intérêt des objets est que leurs valeurs sont stockées en eux. Vous pouvez donc passer le rectangle de fonction en fonction en modifiant ses attributs, il gardera en mémoire ses modifications sur le temps.
Nous pouvons également assigner des variables aux retours de méthodes, comme avec les fonctions :
area = rectangle.calculate_area()
print(area)
La méthode de calcul de l’aire (longueur x largeur) retournera le nombre 15, qui sera ensuite affiché via la fonction print
.
Je pensais que self
était un argument pour calculate_area()
? On ne devrait pas le donner ?
Python s’en occupe pour nous ! Souvenez-vous queself
fait simplement référence à cet objet
, et que Python sait déjà sur quel objet vous invoquez la méthode.
Maintenant, voyons ensemble comment modifier les attributs de notre gâteau. Après tout, vous n’aimez peut-être pas le chocolat… Il est encore temps de changer de saveur !
Découvrez les différents attributs
Vous serez amené à lire trois types d’attributs de classe dans votre pratique du Python :
les attributs d’instance ;
les attributs de classe ;
les attributs statiques.
Les attributs d’instance sont des variables définies à l’aide deself
. Elles sont relatives à l’instance, et ne peuvent être accédées sans instanciation. Dans le cadre des méthodes, ce sont les méthodes classiques d'une classe, qui possèdent self
en premier paramètre.
Regardons un exemple :
class Bird:
"""Un oiseau. 🐦"""
def __init__(self):
"""Les attributs définis ici sont des attributs d'instance."""
self.wings = 2
def fly(self):
"""Cette méthode est une méthode d'instance."""
print("Je vole !")
bird = Bird() # obligation d'instancier un oiseau pour utiliser ses attributs
bird.wings
bird.fly()
Les attributs de classe sont des variables définies directement dans le corps de la classe. Elles peuvent être accédées par la classe, sans passer par l’instanciation. Les attributs de classe peuvent se référencer entre eux, mais ne peuvent pas accéder aux attributs d’instance.
Dans le cadre des méthodes, elles seront précédées par un @classmethod
, et leur premier paramètre seracls
(à la place deself
) :
class Bird:
"""Un oiseau. 🐦"""
# ici on utilise deux attributs de classe.
names = ("mouette", "pigeon", "moineau", "hirrondelle")
positions = {}
def __init__(self, name):
"""Les attributs définis ici sont des attributs d'instance."""
self.position = 1, 2
self.name = name
# On accède à l'attribut de classe "positions" avec self (c'est possible).
self.positions[self.position] = self.name
@classmethod
def find_bird(cls, position):
"""Retrouve un oiseau selon la position donnée."""
if position in cls.positions:
return f"On a trouvé un {cls.positions[position]} !"
return "On a rien trouvé..."
# On peut accéder aux variables de classe sans instanciation.
Bird.names
Bird.positions
print(Bird.find_bird((2, 5)))
# On instancie un oiseau
bird = Bird("mouette")
# On le retrouve avec la méthode find_bird.
print(Bird.find_bird((1, 2)))
Enfin, les attributs statiques sont des attributs qui n’ont pratiquement aucun lien avec la classe. Seules les méthodes peuvent être statiques, et l’ajout par rapport aux attributs de classe est minime : on n'a plus besoin de spécifier le paramètre cls
. Pour créer un attribut statique, il suffit de faire précéder la méthode par @staticmethod
:
class Bird:
"""Un oiseau. 🐦"""
@staticmethod
def get_definition():
"""Donne la définition d'un oiseau."""
return (
"Animal (vertébré à sang chaud) au corps recouvert de plumes, "
"dont les membres antérieurs sont des ailes et qui a un bec."
)
print(Bird.get_definition())
À vous de jouer : créez et utilisez des objets
Dans le chapitre précédent, nous avons écrit des classes basées sur notre exemple de boîte à outils – il est temps maintenant de les utiliser. Nous ajoutons aux classes de base les classes correspondant aux Vis et aux Clous. Notez aussi que j’ai ajouté le corps des méthodes : 😉
class ToolBox:
"""Boite à outils."""
def __init__(self):
"""Initialise les outils."""
self.tools = []
def add_tool(self, tool):
"""Ajoute un outil."""
self.tools.append(tool)
def remove_tool(self, tool):
"""Enleve un outil."""
index = self.tools.index(tool)
del self.tools[index]
class Screwdriver:
"""Tournevis."""
def __init__(self, size=3):
"""Initialise la taille."""
self.size = size
def tighten(self, screw):
"""Serrer une vis."""
screw.tighten()
def loosen(self, screw):
"""Desserre une vis."""
screw.loosen()
def __repr__(self):
"""Représentation de l'objet."""
return f"Tournevis de taille {self.size}"
class Hammer:
"""Marteau."""
def __init__(self, color="red"):
"""Initialise la couleur."""
self.color = color
def paint(self, color):
"""Paint le marteau."""
self.color = color
def hammer_in(self, nail):
"""Enfonce un clou."""
nail.nail_in()
def remove(self, nail):
"""Enleve un clou."""
nail.remove()
def __repr__(self):
"""Représentation de l'objet."""
return f"Marteau de couleur {self.color}"
class Screw:
"""Vis."""
MAX_TIGHTNESS = 5
def __init__(self):
"""Initialise son degré de serrage."""
self.tightness = 0
def loosen(self):
"""Déserre le vis."""
if self.tightness > 0:
self.tightness -= 1
def tighten(self):
"""Serre le vis."""
if self.tightness < self.MAX_TIGHTNESS:
self.tightness += 1
def __str__(self):
"""Retourne une forme lisible de l'objet."""
return "Vis avec un serrage de {}".format(self.tightness)
class Nail:
"""Clou."""
def __init__(self):
"""Initialise son statut "dans le mur"."""
self.in_wall = False
def nail_in(self):
"""Enfonce le clou dans un mur."""
if not self.in_wall:
self.in_wall = True
def remove(self):
"""Enlève le clou du mur."""
if self.in_wall:
self.in_wall = False
def __str__(self):
"""Retourne une forme lisible de l'objet."""
wall_state = "dans le mur" if self.in_wall else "hors du mur"
return f"Clou {wall_state}."
Alors, prêt à taper sur des clous ? 🔨👷♀️
Essayez d’accomplir les actions suivantes :
Instanciez une boîte à outils, un tournevis, et un marteau.
Placez le marteau et le tournevis dans la boîte à outils.
Instanciez une vis, et serrez-la avec le tournevis. Affichez la vis avant et après avoir été serrée.
Instanciez un clou, puis enfoncez-le avec le marteau. Affichez le clou avant et après avoir été enfoncé.
Que pouvez-vous faire d’autre avec ces classes et ces objets ? Une fois que vous aurez fini les tâches ci-dessus, voyez s’il y a d’autres actions que vous pouvez accomplir.
En résumé
On peut instancier des objets en utilisant le nom de leur classe.
Lorsqu’on instancie un objet, on appelle son constructeur, et il faut lui fournir les bons paramètres.
Nous pouvons accéder aux attributs, les modifier, et appeler des méthodes en utilisant la syntaxe
objet.attribut
.
Votre prochaine étape est celle du quiz de première partie, où vous allez récapituler vos connaissances sur l’écriture de classes et l’utilisation d’objets. Après cela, nous passerons à l’héritage en Partie 2.