2017-02-21 19 views
9

Próbuję zrozumieć, jak niezmienność działa w python. Ponieważ ciąg znaków jest niezmienny w pythonie, spodziewałem się, że id zmieni się za każdym razem, gdy wykonam operację łańcuchową, ale nie działa zgodnie z oczekiwaniami. przykład: Ostatnia operacja na t nie zmienia jej identyfikatora. Jakieś pomysły, dlaczego?Immutability in Python

Screen shot of the operation

+0

Powiązane: [Informacje o zmianie identyfikatora niezmiennego łańcucha Pythona] (http://stackoverflow.com/questions/24245324/about-tanging-id-of-a-python-immutable-string) – fredtantini

+1

Naprawdę nie znoszę, jak ta optymalizacja narusza semantykę języka Python. Zgodnie z semantyką języka wartości 't' przed i po' + = 'powinny być różnymi obiektami z (ledwo) nakładającymi się okresami życia, więc nie powinno im się dzielić' id'. – user2357112

Odpowiedz

5

miałem wiersz jabłek w różnych komórkach [memory containing variables (I will not go to the bit level)], z których niektóre są puste [cells containing garbage/empty value].

Wziąłem jedno. Było to w komórce 3 [logical address = 3].

Pomalowałem go na niebiesko (po sklonowaniu go za pomocą przyszłej techniki, w celu pokazania niezmienności) [committed an operation on it, same could go for addition for integers].

Spojrzałem, gdzie to umieścić, i chociaż komórka 4 była wolna, komórka 3 była również (ponieważ "oryginalne" jabłko już nie ma)! Więc umieściłem to z powrotem w komórce 3 [and although we get a "new" apple, it has the same address].


samo dotyczy t (zauważ, że id jest adres pamięci zmiennej w CPython), ale ponieważ mówimy o „łańcuchów jabłek” tutaj (struny wykonane są z sekwencji znaków, mamy aby wziąć pod uwagę ilość miejsca musimy kontynuować sekwencję, więc gdybym miała moja pamięć wygląda jak (_ trybuny dla dowolnych danych śmieci, „^” na przestrzeni)

H e l l o _ _ _ _ _ B O O M 
^ string pointer points here 

i chciałem zmienić ciąg "Hello you", Mogę rozważyć użycie wolnej przestrzeni:

H e l l o^y o u _ B O O M 
^ string pointer points here 

Ale jeśli chcę zmienić ciąg "Hello world!", musiałbym szukać wolnego miejsca w długości "Hello world!" gdzieś indziej (może mamy ją tuż po "BOOM", co jest prawdopodobne w środowisku śmieci zbierane, zobacz, jak różnią się Twoje identyfikatory):

H e l l o^y o u _ B O O M _ H e l l o^w o r l d ! _ G A R B A G E 
          ^string pointer points here 
+0

@ B.M. Problemem jest podobieństwo do interningu. To, co napisałem, jest zasadniczo podobne do komentarza Martijna - "" Python może ponownie wykorzystać gniazda pamięci. "' – Uriel

+0

@ B.M.Nie rozumiem, co masz na myśli mówiąc "To nie działa [sic!]". Opis tej odpowiedzi polega na tym, że Python ponownie wykorzystuje adres pamięci dla nowego ciągu, ponieważ poprzedni ciąg znaków został zbuforowany. Spojrzałem na link i nie widzę, jak mogłoby to zapewnić alternatywne wyjaśnienie zjawiska opisanego w pytaniu. –

+0

Przepraszam, to było zbyt bezpośrednie. Publikuję coś, co wyjaśni, co zrozumiałem. Myślę, że w tym przykładzie niebieskie jabłko nie jest umieszczane w komórce 3, po prostu wpuszczasz tutaj zieloną i dodajesz niebieską farbę na końcu komórki3. –

3

Identyfikatory obiektów można ponownie wykorzystać, o ile oryginalny obiekt nie jest już obecny. Nie jest to specyficzne dla łańcuchów, ale dla wszystkich typów Pythona. Na najprostszym przykładzie, można sprawdzić identyfikator prosty object:

>>> print id(object()) 
140437485756544 
>>> print id(object()) 
140437485756544 

Jeśli jednak zachować odniesienie do poprzedniego obiektu, id nie zostaną ponownie wykorzystane:

>>> a = object() 
>>> id(a) 
140437485756544 
>>> b = object() 
>>> id(b) 
140437485756560 

Można odtworzyć to samo zachowanie w testach z ciągami, dołączając do listy wyniki pośrednie (wartości w t).

+0

Dlaczego w pierwszych dwóch przypadkach testowych dołączania "Test" do t zmienił się identyfikator? Czy jest to "losowe" czy python ma systematyczny sposób przydzielania pamięci dla ciągów znaków w tym przypadku? – PrestonM

+1

@ PrestonM Nie można zagwarantować, że identyfikator zostanie ponownie użyty - coś innego mogło zająć tę lokalizację pamięci (w ten sposób CPython implementuje 'id') za pierwszym razem. Gwarantuje to, że ID obiektu aktywnego nie ulegnie zmianie i że dwa różne (i żywe) obiekty nie będą miały tego samego identyfikatora. – user4815162342

+0

To ma sens. Dzięki! – PrestonM