Il y a en fait deux choses à savoir à propos de CPython et de son comportement ici. Premièrement, les petits entiers de l'ordre de [-5, 256] sont internalisés en interne. Ainsi, toute valeur se situant dans cette fourchette partagera le même identifiant, même au niveau de la REPL :
>>> a = 100
>>> b = 100
>>> a is b
True
Puisque 300 > 256, il n'est pas interné :
>>> a = 300
>>> b = 300
>>> a is b
False
Deuxièmement, dans un script, les éléments littéraux sont placés dans une section constante du fichier code compilé. Python est suffisamment intelligent pour réaliser que, puisque les deux types de caractères a
y b
se réfèrent au texte littéral 300
et que 300
est un objet immuable, il peut simplement de référencer le même emplacement constant. Si vous modifiez votre script et que vous l'écrivez comme suit
def foo():
a = 300
b = 300
print(a==b)
print(a is b)
print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
import dis
dis.disassemble(foo.__code__)
Le début de la sortie ressemble à ceci :
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)
3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
...
Comme vous pouvez le voir, CPython charge le fichier a
y b
en utilisant le même créneau constant. Cela signifie que a
y b
se réfèrent maintenant au même objet (parce qu'ils référence au même slot) et c'est pourquoi a is b
es True
dans le script mais mais pas dans le REPL.
Vous pouvez également observer ce comportement dans la REPL, si vous intégrez vos instructions dans une fonction :
>>> import dis
>>> def foo():
... a = 300
... b = 300
... print(a==b)
... print(a is b)
... print("id(a) = %d, id(b) = %d" % (id(a), id(b)))
...
>>> foo()
True
True
id(a) = 4369383056, id(b) = 4369383056
>>> dis.disassemble(foo.__code__)
2 0 LOAD_CONST 1 (300)
2 STORE_FAST 0 (a)
3 4 LOAD_CONST 1 (300)
6 STORE_FAST 1 (b)
# snipped...
En conclusion : bien que CPython effectue parfois ces optimisations, vous ne devriez pas vraiment compter dessus - il s'agit vraiment d'un détail d'implémentation, qui a été modifié au fil du temps (CPython ne le faisait auparavant que pour les entiers jusqu'à 100, par exemple). Si vous comparez des nombres, utilisez ==
. :-)