Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

id a un comportement différent entre int et float

3 réponses
Avatar
LL.Snark
Bonjour,

Quelqu'un aurait une idée de la raison pour laquelle ce code :

a=3
b=3
c=a
id(a),id(b),id(c)

affiche trois fois le même id :

(137479680, 137479680, 137479680)

alors que celui-ci :

a=3.5
b=3.5
c=a
id(a),id(b),id(c)

indique que l'id de b est différent des deux autres :

(145621988, 145621972, 145621988)

Je comprends les deux comportements (l'id est un identifiant unique pour
l'objet, souvent son adresse), mais pas la raison pour laquelle un int
et un float devraient se comporter différemment.


Ces tests ont été réalisés avec Python 3.2 ou Python 2.6 c'est pareil.

J'attendais comme comportement que a et b aient des ids différents alors
que a et c devraient avoir le même.
J'ai été surpris dans le cas des int que a et b aient le même id. J'ai
pensé à une optimisation qui éviterait de stocker des entiers très
grands (comme on peut le faire en Python) une fois au lieu de deux.
Mais il me semble que la fusion des types int et Bigint date de Python 3
(je n'en suis pas sûr). Or j'ai la même chose en Python 2.6. Et pourquoi
ne pas avoir fait profiter les floats du même comportement ?

Par avance, merci pour vos réponses éclairantes :)

3 réponses

Avatar
Francois Lafont
Bonjour,

Le 26/08/2011 15:43, LL.Snark a écrit :

a=3
b=3
c=a
id(a),id(b),id(c)

affiche trois fois le même id :

(137479680, 137479680, 137479680)



Les entiers sont des objets immuables, c'est-à-dire que leur état ne
change jamais. Du coup, il est inutile d'avoir plusieurs instances
distinctes de l'objet int(3) si c'est pour créer 3 objets rigoureusement
identiques qui en plus ne changeront jamais d'état du début à la fin du
programme. C'est sans doute pour économiser de la mémoire, d'autant plus
que les objets de type int dans python sont quand même très fréquents.

alors que celui-ci :

a=3.5
b=3.5
c=a
id(a),id(b),id(c)

indique que l'id de b est différent des deux autres :

(145621988, 145621972, 145621988)



Je ne sais pas pourquoi l'optimisation faite pour les objets de type int
ne se fait pas pour les objets de type float car il me semble que les
objets de type float sont immuables aussi. Il doit bien y avoir une
raison... mais cela relève fois de l'implémentation de python.

Ici http://docs.python.org/reference/datamodel.html, on peut lire :

« after a = 1; b = 1, a and b may or *may not* refer to the same object
with the value one, depending on the implementation, but after c = []; d
= [], c and d are guaranteed to refer to two different, unique, newly
created empty lists. »

Donc avec «a=1;b=1», suivant l'implémentation de python, tu pourras
avoir «id(a)==id(b)» ou non. En revanche, les listes par exemple sont
des objets non immuables, donc avec «a=[];b=[]», quelle que soit
l'implémentation, tu auras «id(a)!=id(b)» à tous les coups.


--
François Lafont
Avatar
LL.Snark
a=3
b=3
c=a
id(a),id(b),id(c)
affiche trois fois le même id :
(137479680, 137479680, 137479680)
alors que celui-ci :
a=3.5
b=3.5
c=a
id(a),id(b),id(c)
indique que l'id de b est différent des deux autres :
(145621988, 145621972, 145621988)



Ici http://docs.python.org/reference/datamodel.html, on peut lire :
« after a = 1; b = 1, a and b may or *may not* refer to the same object
with the value one, depending on the implementation, but after c = []; d
= [], c and d are guaranteed to refer to two different, unique, newly
created empty lists. »

Donc avec «a=1;b=1», suivant l'implémentation de python, tu pourras
avoir «id(a)==id(b)» ou non. En revanche, les listes par exemple sont
des objets non immuables, donc avec «a=[];b=[]», quelle que soit
l'implémentation, tu auras «id(a)!=id(b)» à tous les coups.



Bonsoir,

La réponse de Francois me semble tout à fait satisfaisante.
Je n'étais pas tombé sur la doc en question (il y en a tellement sur
Python que je ne sais plus où chercher...), mais comme c'est une
histoire d'implémentation, c'est réglé en ce qui me concerne. Je pensais
que le comportement d'avoir a=b ou non était lié au caractère immuable
ou non. Ce n'est simplement pas "vraiment" le cas.
Si le type est muable, on n'a jamais a=b (exemple des listes de
François, je suppose que ce sera pareil avec les sets ou les dicts). Si
en revanche le type est immuable, on a ou pas, selon l'implémentation,
a=b apèrs avoir affecté la même valeur aux deux variables.
Le comportement avec les tuples (immuables) (contenant un seul entier,
par exemple), est le même que pour les float :
a=(5,)
b=(5,)
mais id(a)!=id(b)
En revanche, pour les str (immuables aussi), c'est comme pour les int :
a="toto"
b="toto"
et on a id(a)==id(b)

C'est en tout cas comme ça avec CPython 2.6 ou 3.2

Merci pour la réponse.
Avatar
Laurent Pointal
LL.Snark wrote:

Bonjour,

Quelqu'un aurait une idée de la raison pour laquelle ce code :

a=3
b=3
c=a
id(a),id(b),id(c)

affiche trois fois le même id :

(137479680, 137479680, 137479680)

alors que celui-ci :

a=3.5
b=3.5
c=a
id(a),id(b),id(c)

indique que l'id de b est différent des deux autres :

(145621988, 145621972, 145621988)

Je comprends les deux comportements (l'id est un identifiant unique pour
l'objet, souvent son adresse), mais pas la raison pour laquelle un int
et un float devraient se comporter différemment.



Pour des raisons d'optimisation, une partie des entiers de faible valeur est
stockée une fois pour toutes en mémoire - ça évite d'avoir à créer/supprimer
des objets immutables qui stockent des valeurs très utilisées.

Tu peux essayer:
for i in range(-100,100):






if id(i)==id(i+1-1):
print (i)

Ca m'indique (Python 3.1.2) que les entiers de -5 à 256 sont ainsi présents.

Cette optimisation n'est pas considérée utile pour les flottants.

A+