Dieses Verhalten ist zumindest teilweise damit zu tun, wie der Interpreter faltende Konstante und wie die REPL Code ausführt.
Denken Sie daran, dass CPython zuerst Code kompiliert (zu AST und dann Bytecode). Es wertet dann den Bytecode aus. Während der Kompilierung sucht das Skript nach Objekten, die unveränderlich sind, und speichert sie zwischen. Es dedupliziert sie auch . Also, wenn es
a = 257
b = 257
sieht, wird es a und b gegen das gleiche Objekt speichern:
import dis
def f():
a = 257
b = 257
dis.dis(f)
#>>> 4 0 LOAD_CONST 1 (257)
#>>> 3 STORE_FAST 0 (a)
#>>>
#>>> 5 6 LOAD_CONST 1 (257)
#>>> 9 STORE_FAST 1 (b)
#>>> 12 LOAD_CONST 0 (None)
#>>> 15 RETURN_VALUE
Notiere die LOAD_CONST 1
. Der 1
ist der Index in co_consts
:
f.__code__.co_consts
#>>> (None, 257)
So diese beiden die gleiche 257
laden. Warum tritt dies nicht auf mit:
$ python2
Python 2.7.8 (default, Sep 24 2014, 18:26:21)
>>> a = 257
>>> b = 257
>>> a is b
False
$ python3
Python 3.4.2 (default, Oct 8 2014, 13:44:52)
>>> a = 257
>>> b = 257
>>> a is b
False
?
Jede Zeile ist in diesem Fall eine separate Kompilierungseinheit und die Deduplizierung kann nicht über sie hinweg erfolgen. Es funktioniert ähnlich wie
Als solche haben diese Codeobjekte beide einzigartige konstante Caches. Dies bedeutet, dass, wenn wir den Zeilenumbruch zu entfernen, wird die is
True
zurück:
>>> a = 257; b = 257
>>> a is b
True
Tat dies der Fall für beide Python-Versionen ist.In der Tat ist dies genau, warum
>>> a, b = 257, 257
>>> a is b
True
kehrt True
als auch, Es ist nicht wegen irgendeiner Eigenschaft des Auspackens; Sie nur in der gleichen Compilierungseinheit platziert werden.
Dies gibt False
für Versionen zurück, die nicht richtig falten; filmor links to Ideone, die diesen Fehler bei 2.7.3 und 3.2.3 zeigt. Auf diesen Versionen, die ihre Produkte mit den anderen Konstanten erstellt Tupel nicht teilen:
import dis
def f():
a, b = 257, 257
print(a is b)
print(f.__code__.co_consts)
#>>> (None, 257, (257, 257))
n = f.__code__.co_consts[1]
n1 = f.__code__.co_consts[2][0]
n2 = f.__code__.co_consts[2][1]
print(id(n), id(n1), id(n2))
#>>> (148384292, 148384304, 148384496)
Wieder aber ist es hier nicht um eine Änderung, wie die Objekte werden ausgepackt; es ist nur eine Änderung, wie die Objekte in co_consts
gespeichert werden.
ist es wirklich egal, man sollte sich nicht auf irgendein Internierungsverhalten verlassen ... Vergleich verwenden. –
Python Praktikanten Zahlen in den gleichen Ausdruck, ich werde den entsprechenden Code finden (hatte es schon für eine frühere Frage :)) – filmor
Dies könnte mit Ihrer Implementierung zu tun haben, und wie es kleine ganze Zahlen zwischenspeichert. Hast du es mit einer kleineren Nummer als 257 probiert? War die Wahl von 257 zufällig? –