Inny duplikat pytał, dlaczego dwa równe ciągi generalnie nie są identyczne, na co tak naprawdę nie ma odpowiedzi:
>>> x = 'a'
>>> x += 'bc'
>>> y = 'abc'
>>> x == y
True
>>> x is y
False
Więc dlaczego nie są tym samym ciągiem? Szczególnie biorąc pod uwagę to:
>>> z = 'abc'
>>> w = 'abc'
>>> z is w
True
Odłóżmy na chwilę drugą część. Jak pierwszy mógł być prawdziwy?
Interpreter musiałby mieć „tablicę interningową”, tabelę odwzorowującą wartości łańcuchowe na obiekty łańcuchowe, więc za każdym razem, gdy próbujesz utworzyć nowy łańcuch z zawartością 'abc'
, otrzymujesz ten sam obiekt. Wikipedia zawiera bardziej szczegółowe omówienie tego, jak działa staż.
A Python ma tablicę umieszczania łańcuchów; możesz ręcznie internować ciągi za pomocą sys.intern
metody.
W rzeczywistości Python może automatycznie internować wszystkie niezmienne typy, ale nie jest to wymagane . Różne implementacje będą miały różne wartości.
CPython (implementacja, której używasz, jeśli nie wiesz, której implementacji używasz) auto-interns małe liczby całkowite i niektóre specjalne single, takie jak False
, ale nie łańcuchy (lub duże liczby całkowite, małe krotki lub cokolwiek innego). Możesz to dość łatwo zobaczyć:
>>> a = 0
>>> a += 1
>>> b = 1
>>> a is b
True
>>> a = False
>>> a = not a
>>> b = True
a is b
True
>>> a = 1000
>>> a += 1
>>> b = 1001
>>> a is b
False
OK, ale dlaczego były z
i w
identyczne?
To nie jest interpreter automatycznie internujący, to wartości składane kompilatora.
Jeżeli ten sam ciąg czasu kompilacji pojawia się dwa razy w tym samym module (co dokładnie oznacza to jest trudne do zdefiniowania, to nie to samo, co ciągiem znaków, ponieważ r'abc'
, 'abc'
i 'a' 'b' 'c'
są różne literały ale ten sam ciąg, ale łatwe do zrozumienia intuicyjnie), kompilator utworzy tylko jedno wystąpienie ciągu z dwoma odwołaniami.
W rzeczywistości kompilator może pójść nawet dalej: 'ab' + 'c'
może zostać przekonwertowany 'abc'
przez optymalizator, w którym to przypadku może zostać złożony razem ze 'abc'
stałą w tym samym module.
Ponownie, jest to coś, co Python jest dozwolony, ale nie jest do tego zobowiązany. Ale w tym przypadku CPython zawsze składa małe łańcuchy (a także np. Małe krotki). (Chociaż kompilator instrukcji interpretera interaktywnego nie uruchamia takiej samej optymalizacji, jak kompilator modułu w czasie, więc nie zobaczysz dokładnie tych samych wyników interaktywnie).
Co więc powinieneś z tym zrobić jako programista?
Jak nic. Prawie nigdy nie masz powodu, by przejmować się, czy dwie niezmienne wartości są identyczne. Jeśli chcesz wiedzieć, kiedy możesz użyć a is b
zamiast a == b
, zadajesz niewłaściwe pytanie. Po prostu zawsze używaj a == b
z wyjątkiem dwóch przypadków:
- Aby uzyskać bardziej czytelne porównania z wartościami pojedynczymi, takimi jak
x is None
.
- W przypadku wartości zmiennych, kiedy musisz wiedzieć, czy mutacja
x
wpłynie na y
.