Ok, chaque chose en son temps.
Il n'existe pas de "déclaration de variable" ou d'"initialisation de variable" en Python.
Il y a simplement ce que nous appelons "affectation", mais que nous devrions probablement appeler simplement "dénomination".
L'assignation signifie "ce nom sur le côté gauche se réfère maintenant au résultat de l'évaluation du côté droit, sans tenir compte de ce à quoi il se référait auparavant (le cas échéant)".
foo = 'bar' # the name 'foo' is now a name for the string 'bar'
foo = 2 * 3 # the name 'foo' stops being a name for the string 'bar',
# and starts being a name for the integer 6, resulting from the multiplication
En tant que tels, les noms de Python (un meilleur terme que "variables", sans doute) n'ont pas de types associés ; les valeurs, si. Vous pouvez réappliquer le même nom à n'importe quoi, quel que soit son type, mais la chose a toujours un comportement qui dépend de son type. Le nom est simplement un moyen de faire référence à la valeur (objet). Cela répond à votre deuxième question : Vous Ne le fais pas. créer des variables pour contenir un type personnalisé. Vous ne créez pas de variables pour contenir un type particulier. Vous ne "créez" pas de variables du tout. Vous donnez des noms aux objets.
Deuxième point : Python suit une règle très simple en ce qui concerne les classes, qui est en fait beaucoup plus cohérente que ce que font des langages comme Java, C++ et C# : tout ce qui est déclaré à l'intérieur du class
fait partie de la classe . Ainsi, les fonctions ( def
) écrites ici sont des méthodes, c'est-à-dire qu'elles font partie de l'objet de la classe (et ne sont pas stockées par instance), tout comme en Java, C++ et C# ; mais les autres noms ici sont également partie de la classe. Encore une fois, les noms ne sont que des noms, et ils n'ont pas de types associés, et les fonctions sont aussi des objets en Python. Ainsi :
class Example:
data = 42
def method(self): pass
Les classes sont aussi des objets en Python.
Nous avons donc créé un objet nommé Example
qui représente la classe de toutes les choses qui sont Example
s. Cet objet possède deux attributs (En C++, "membres" ; en C#, "champs ou propriétés ou méthodes" ; en Java, "champs ou méthodes"). L'un d'entre eux est nommé data
et il stocke la valeur entière 42
. L'autre s'appelle method
et il stocke un objet fonction. (Il existe plusieurs autres attributs que Python ajoute automatiquement).
Ces attributs ne font cependant pas vraiment partie de l'objet. Fondamentalement, un objet n'est qu'un paquet de noms supplémentaires (les noms des attributs), jusqu'à ce que l'on arrive à des choses qui ne peuvent plus être divisées. Ainsi, les valeurs peuvent être partagées entre différentes instances d'une classe, ou même entre des objets de différentes classes, si vous le faites délibérément.
Créons une instance :
x = Example()
Maintenant nous avons un objet séparé nommé x
qui est une instance de Example
. Le site data
et method
ne font pas réellement partie de l'objet, mais nous pouvons quand même les rechercher via x
à cause d'une certaine magie que Python fait dans les coulisses. Lorsque nous cherchons method
en particulier, nous obtiendrons plutôt une "méthode liée" (lorsque nous l'appelons, x
est transmise automatiquement en tant que self
ce qui ne peut pas se produire si l'on recherche Example.method
directement).
Que se passe-t-il quand on essaie d'utiliser x.data
?
Quand on l'examine, on le cherche d'abord dans l'objet. S'il n'est pas trouvé dans l'objet, Python le cherche dans la classe.
Cependant, lorsque nous affecter à x.data
Python va créer un attribut sur l'objet. Il va pas remplace l'attribut "classe".
Cela nous permet de faire objet initialisation. Python appellera automatiquement la classe __init__
sur les nouvelles instances lorsqu'elles sont créées, si elle est présente. Dans cette méthode, nous pouvons simplement assigner des attributs pour définir les valeurs initiales de cet attribut sur chaque objet :
class Example:
name = "Ignored"
def __init__(self, name):
self.name = name
# rest as before
Nous devons maintenant spécifier un name
lorsque nous créons un Example
et chaque instance a sa propre name
. Python ignorera l'attribut de classe Example.name
quand on cherche le .name
d'une instance, car l'attribut de l'instance sera trouvé en premier.
Un dernier avertissement : la modification (mutation) et l'affectation sont des choses différentes !
En Python, les chaînes de caractères sont immuables. Elles ne peuvent pas être modifiées. Lorsque vous le faites :
a = 'hi '
b = a
a += 'mom'
Vous ne pas changer la chaîne originale 'hi'. C'est impossible en Python. Au lieu de cela, vous créez un nouveau chaîne de caractères 'hi mom'
et causer a
pour cesser d'être un nom pour 'hi '
et commencez à être un nom pour 'hi mom'
à la place. Nous avons fait b
un nom pour 'hi '
également, et après avoir réappliqué le a
nom, b
est toujours un nom pour 'hi '
parce que 'hi '
existe toujours et n'a pas été modifié.
Mais les listes peuvent être modifiées :
a = [1, 2, 3]
b = a
a += [4]
Maintenant b
est [1, 2, 3, 4] aussi, parce que nous avons fait b
un nom pour la même chose que a
nommé, et ensuite nous avons changé cette chose. Nous n'avons pas créé une nouvelle liste pour a
à nommer, car Python traite tout simplement +=
différemment pour les listes.
Ceci est important pour les objets car si vous avez une liste comme attribut de classe et que vous utilisez une instance pour modifier la liste, le changement sera "vu" dans toutes les autres instances. En effet, (a) les données font en réalité partie de l'objet de classe et non d'un objet d'instance ; (b) comme vous modifiez la liste et que vous ne faites pas une simple affectation, vous n'avez pas créé un nouvel attribut d'instance cachant l'attribut de classe.