Chociaż to pytanie nie ma żadnego rzeczywistego zastosowania w praktyce, jestem ciekawy, jak Python dokonuje internowania ciągów. Zauważyłem, co następuje.
>>> "string" is "string"
True
To jest tak, jak się spodziewałem.
Ty też możesz to zrobić.
>>> "strin"+"g" is "string"
True
I to całkiem sprytne!
Ale nie możesz tego zrobić.
>>> s1 = "strin"
>>> s2 = "string"
>>> s1+"g" is s2
False
Dlaczego Python miałby nie ocenić s1+"g"
i zdać sobie sprawę, że to to samo, co s2
i skierować go pod ten sam adres? Co właściwie dzieje się w tym ostatnim bloku, że wraca False
?
"string1" + "s2"
,10 + 3*20
etc.) w czasie kompilacji, ale ograniczenia wynikające sekwencje do zaledwie 20 elementów (w celu zapobieżenia[None] * 10**1000
z nadmiernie rozszerza swoją kodu bajtowego). To właśnie ta optymalizacja zapadła"strin" + "g"
się"string"
; wynik jest krótszy niż 20 znaków.intern()
funkcja jest specjalnie internowana .intern
funkcję w Pythonie 3 - zostaje przeniesiona do sys.internPrzypadek 1
>>> x = "123" >>> y = "123" >>> x == y True >>> x is y True >>> id(x) 50986112 >>> id(y) 50986112
Przypadek 2
>>> x = "12" >>> y = "123" >>> x = x + "3" >>> x is y False >>> x == y True
Teraz twoje pytanie brzmi, dlaczego identyfikator jest taki sam w przypadku 1, a nie w przypadku 2.
W przypadku 1, przypisałeś literał łańcuchowy
"123"
dox
iy
.Ponieważ ciągi znaków są niezmienne, sensowne jest, aby interpreter przechował literał ciągu tylko raz i wskazywał wszystkie zmienne na ten sam obiekt.
Dlatego widzisz identyfikator jako identyczny.
W przypadku 2 modyfikujesz
x
za pomocą konkatenacji. Zarównox
iy
ma te same wartości, ale nie samą tożsamość.Oba wskazują na różne obiekty w pamięci. Stąd mają inny
id
iis
zwrócony operatorFalse
źródło
id(x) != id(x)
na przykład, ponieważ ciąg został przesunięty w procesie oceny.x = "12" + "3"
dox = "123"
(konkatenacja dwóch literałów łańcuchowych w jednym wyrażeniu), więc przypisanie faktycznie przeprowadza wyszukiwanie i znajduje ten sam „wewnętrzny” ciąg, co fory = "123"
.