Les Classes combinent des données et du comportement.
Les classes servent à créer des copies, ou instances, de données et de comportements regroupés, que l'on appelle communément des objects.
Un objet peut représenter une entité du monde réel (comme une voiture ou un chat) ou un concept plus abstrait (comme un entier, un véhicule ou un mammifère).
Les classes sont au cœur d'une approche de programmation orientée objet (POO), qui invite le programmeur à modéliser un problème sous la forme d'un ou plusieurs objets qui interagissent entre eux, conservent un état et agissent sur des données.
Une classe est la définition d'un nouveau type d'objet, à partir de laquelle on crée de nouvelles instances d'objets.
Elle regroupe souvent des données (appelées fields, attributes, properties, data members ou variables) et du code ou des fonctions (appelées methods) qui opèrent sur ces données.
En ce sens, une classe est un plan ou un ensemble d'instructions à partir desquels on peut construire et utiliser de nombreux objets d'un type similaire.
Un programme complexe peut comporter de nombreuses classes, chacune produisant des objets de différentes sortes.
Le processus qui consiste à construire et à personnaliser un objet à partir d'une classe s'appelle l'instantiation (ou la création d'une instance de la classe).
La définition d'une classe en Python est simple :
class MyClass:
# Class body goes here
On peut ajouter des champs de classe (autrement dit des propriétés, des attributs, des membres de données ou des variables) au corps de la classe.
class MyClass:
number = 5
string = "Hello!"
On peut créer une instance (un objet) de MyClass et la lier à un nom :
>>> new_object = MyClass()
# Class is instantiated and resulting object is bound to the "new_object" name (variable).
# Note: the object address 'at 0x15adc55b0' will vary by computer.
>>> new_object
<__main__.MyClass at 0x15adc55b0>
Les Class attributes sont partagés par tous les objets (ou instances) créés à partir d'une classe, et sont accessibles via la dot notation, c'est-à-dire un . placé après le nom de l'objet et avant le nom de l'attribut :
>>> new_object = MyClass()
# Accessing the class attribute "number" via dot-notation.
>>> new_object.number
5
# Accessing the class attribute "string" via dot-notation.
>>> new_object.string
'Hello!'
# Instantiating an additional object and binding it to the "second_new_object" name.
>>> second_new_object = MyClass()
>>> second_new_object
<__main__.MyClass at 0x15ad99970>
# Second_new_object shares the same class attributes as new_object.
>>> new_object.number == second_new_object.number
True
Les attributs de classe sont définis dans le corps de la classe elle-même, avant toute autre méthode. Ils appartiennent à la classe, ce qui permet de les partager entre les instances. Comme ces attributs sont partagés par toutes les instances de la classe, leur valeur est accessible et modifiable directement depuis la classe. Modifier la valeur d'un attribut de classe modifie cette valeur pour tous les objets instanciés à partir de la classe :
>>> obj_one = MyClass()
>>> obj_two = MyClass()
# Accessing a class attribute from an object.
>>> obj_two.number
5
# Accessing the class attribute from the class itself.
>>> MyClass.number
5
# Modifying the value of the "number" class attribute.
>>> MyClass.number = 27
# Modifying the "number" class attribute changes the "number" attribute for all objects.
>>> obj_one.number
27
>>> obj_two.number
27
Avoir une multitude d'objets dont les données restent synchronisées en permanence n'est pas particulièrement utile.
Heureusement, les objets créés à partir d'une classe peuvent être personnalisés avec leurs propres instance attributes (ou propriétés, variables ou champs d'instance).
Comme leur nom l'indique, les attributs d'instance sont propres à chaque objet et peuvent être modifiés indépendamment les uns des autres.
__init__()
La "dunder method" (abréviation de ‹ double underscore method ›) spéciale __init__() sert à personnaliser les instances d'une classe, et permet d'initialiser les attributs ou propriétés d'instance des objets.
En raison de son rôle dans l'initialisation des attributs d'instance, __init__() est aussi appelée class constructor ou initializer.
__init__() prend un paramètre obligatoire appelé self, qui désigne l'objet tout juste initié ou créé.
On peut ensuite passer les données des attributs ou propriétés d'instance comme arguments de __init__(), après le paramètre self.
Ci-dessous, MyClass possède désormais des attributs d'instance appelés location_x et location_y.
Comme tu le vois, ces deux attributs ont été affectés au premier et au deuxième indice de l'argument location (un tuple) passé à __init__().
Les attributs location_x et location_y d'une instance de classe seront désormais initialisés quand tu instancies la classe et qu'un objet est créé :
class MyClass:
# These are class attributes, variables, or fields.
number = 5
string = "Hello!"
# This is the class "constructor", with a "location" parameter that is a tuple.
def __init__(self, location):
# This is an instance or object property, attribute, or variable.
# Note that we are unpacking the tuple argument into two separate instance variables.
self.location_x = location[0]
self.location_y = location[1]
# Create a new object "new_object_one", with object property (1, 2).
>>> new_object_one = MyClass((1, 2))
# Create a second new object "new_object_two" with object property (-8, -9).
>>> new_object_two = MyClass((-8, -9))
# Note that new_object_one.location_x and new_object_two.location_x two different values.
>>> new_object_one.location_x
1
>>> new_object_two.location_x
-8
Note qu'il te suffit de passer un seul argument pour initialiser MyClass ci-dessus : Python se charge de passer self quand la classe est appelée.
Une autre façon de créer une variable d'instance consiste simplement à accéder à une variable de classe via un objet, puis à lui donner une autre valeur :
>>> obj_one = MyClass()
>>> obj_two = MyClass()
>>> MyClass.string
'Hello!'
>>> obj_two.string = "Hi!"
>>> obj_two.string
'Hi!'
>>> obj_one.string
'Hello!'
Maintenant, regarde ce qui se passe quand la variable de classe change :
>>> MyClass.string = "World!"
>>> obj_two.string
# obj_two.string has not changed
'Hi!'
>>> obj_one.string
# obj_one.string changed
'World!'
L'attribut string est désormais une variable d'instance dans le cas de obj_two, mais reste une variable de classe dans obj_one.
On peut aussi faire cela depuis l'intérieur de la classe :
class Demo:
new_var = 3
def add_two(self):
self.new_var += 2
Au moment où <object>.add_two() est appelé, et où self.new_var += 2 est lu, new_var passe du statut de variable de classe à celui de variable d'instance du même nom.
Cela peut être utile lors de l'initialisation, quand toutes les instances d'une classe ont besoin que certains attributs démarrent avec la même valeur.
Cependant, la variable d'instance masque alors la variable de classe, ce qui rend cette dernière inaccessible depuis l'instance où elle est masquée.
Dans cette situation, il peut être plus sûr et plus clair de définir les attributs d'instance depuis la méthode __init__() sous la forme self.<attribute>.
Une method est une function liée soit à la classe elle-même (appelée class method, que nous verrons en détail dans un exercice ultérieur), soit à une instance de la classe (un objet).
Les méthodes qui opèrent sur un objet ou une instance doivent être définies avec self comme premier paramètre.
Tu peux ensuite définir le reste des paramètres comme pour une fonction « normale » ou non liée.
Les méthodes qui opèrent sur une classe doivent être définies avec le décorateur @classmethod et (par convention) avec cls comme premier paramètre.
Les méthodes de classe s'appellent directement sur une classe, sans avoir à créer au préalable un objet à partir de cette classe.
class MyClass:
number = 5
string = "Hello!"
# Class constructor.
def __init__(self, location):
# Instance properties
self.location_x = location[0]
self.location_y = location[1]
# Class method. Uses the @classmethod decorator, and cls as the first parameter.
# Can be called without first making an instance of the class.
@classmethod
def change_string(cls, new_string):
#Class attributes are referred to with cls.
cls.string = new_string
return cls.string
# Instance method. Note "self" as first parameter.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
Comme pour l'accès aux attributs, appeler une méthode se résume à placer un . après le nom de l'objet et avant le nom de la méthode.
La méthode appelée n'a pas besoin d'une copie de l'objet comme premier paramètre : Python remplit self automatiquement :
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Make a new test_object with location (3,7)
>>> test_object = MyClass((3,7))
>>> (test_object.location_x, test_object.location_y)
(3,7)
# Call change_location to increase location_x and location_y by 7.
>>> test_object.change_location(7)
(10, 14)
On peut accéder aux attributs de classe depuis l'intérieur des méthodes d'instance de la même manière que depuis l'extérieur de la classe :
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances from within an instance.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
>>> test_object_one = MyClass((0,0))
>>> test_object_one.number
5
>>> test_object_two = MyClass((13, -3))
>>> test_object_two.increment_number()
>>> test_object_one.number
6
pass
Dans les exercices d'apprentissage précédents et les ébauches d'exercices d'entraînement, tu as vu le mot-clé pass utilisé dans le corps des fonctions à la place du code réel.
Le mot-clé pass est un marqueur de remplissage syntaxiquement valide : il empêche Python de lever une erreur de syntaxe pour une fonction ou une définition de classe vide.
En substance, c'est une façon de dire à l'interprète Python : « Pas de panique ! Je vais mettre du code ici, je ne l'ai juste pas encore fait. »
class MyClass:
number = 5
string = "Hello!"
def __init__(self, location):
self.location_x = location[0]
self.location_y = location[1]
# Alter instance variable location_x and location_y.
def change_location(self, amount):
self.location_x += amount
self.location_y += amount
return self.location_x, self.location_y
# Alter class variable number for all instances.
def increment_number(self):
# Increment the 'number' class variable by 1.
MyClass.number += 1
# This will compile and run without error, but has no current functionality.
def pending_functionality(self):
# Stubbing or place-holding the body of this method.
pass