Odpowiedzi:
To doskonałe pytanie.
Kluczowym wnioskiem jest to, że krotki nie mają możliwości sprawdzenia, czy obiekty w nich zawarte są zmienne. Jedyną rzeczą, która sprawia, że obiekt jest zmienny, jest posiadanie metody, która zmienia jego dane. Ogólnie rzecz biorąc, nie ma sposobu, aby to wykryć.
Innym spostrzeżeniem jest to, że kontenery Pythona w rzeczywistości nic nie zawierają. Zamiast tego zachowują odniesienia do innych obiektów. Podobnie zmienne Pythona nie są jak zmienne w językach kompilowanych; zamiast tego nazwy zmiennych są po prostu kluczami w słowniku przestrzeni nazw, gdzie są skojarzone z odpowiednim obiektem. Ned Batchhelder ładnie wyjaśnia to na swoim blogu . Tak czy inaczej, obiekty znają tylko liczbę odniesień; nie wiedzą, jakie są te odwołania (zmienne, kontenery lub wewnętrzne elementy Pythona).
Razem te dwa spostrzeżenia wyjaśniają Twoją tajemnicę (dlaczego niezmienna krotka „zawierająca” listę wydaje się zmieniać, gdy zmienia się lista bazowa). W rzeczywistości krotka się nie zmieniła (nadal ma te same odwołania do innych obiektów, co wcześniej). Nie można zmienić krotki (ponieważ nie ma metod mutujących). Gdy lista uległa zmianie, krotka nie otrzymała powiadomienia o zmianie (lista nie wie, czy odwołuje się do niej zmienna, krotka czy inna lista).
Skoro już jesteśmy na ten temat, oto kilka innych przemyśleń, które pomogą uzupełnić twój model myślowy o tym, czym są krotki, jak działają i ich przeznaczeniem:
Krotki charakteryzują się mniejszą niezmiennością, a bardziej przeznaczeniem.
Krotki to sposób Pythona na zbieranie heterogenicznych informacji pod jednym dachem. Na przykład
s = ('www.python.org', 80)
łączy łańcuch i liczbę, dzięki czemu para host / port może być przekazywana jako gniazdo, obiekt złożony. Patrząc w tym świetle, posiadanie zmiennych elementów jest całkowicie uzasadnione.
Niezmienność idzie ręka w rękę z inną właściwością, hashability . Ale hashability nie jest własnością absolutną. Jeśli jeden ze składników krotki nie jest haszowalny, ogólna krotka również nie jest haszowalna. Na przykład t = ('red', [10, 20, 30])
nie można haszować.
Ostatni przykład przedstawia 2-krotkę, która zawiera ciąg i listę. Sama krotka nie jest zmienna (tj. Nie ma żadnych metod zmieniających jej zawartość). Podobnie ciąg jest niezmienny, ponieważ łańcuchy nie mają żadnych metod mutujących. Obiekt listy ma metody mutujące, więc można go zmienić. To pokazuje, że zmienność jest właściwością typu obiektu - niektóre obiekty mają metody mutujące, a inne nie. Nie zmienia się to tylko dlatego, że obiekty są zagnieżdżone.
Pamiętaj o dwóch rzeczach. Po pierwsze, niezmienność nie jest magią - to po prostu brak metod mutacji. Po drugie, obiekty nie wiedzą, jakie zmienne lub kontenery się do nich odnoszą - znają tylko liczbę odwołań.
Mam nadzieję, że ci się to przydało :-)
hash()
ponieważ wszystko, co dziedziczy po object () jest hashable, więc podklasy muszą jawnie wyłączyć haszowanie. 2) Hashibility nie gwarantuje niezmienności - łatwo jest stworzyć przykłady obiektów, które można mieszać, które są zmienne. 3) Krotki, podobnie jak większość kontenerów w Pythonie, mają po prostu odwołania do obiektu bazowego - nie mają obowiązku ich sprawdzać i wyciągać na ich temat wniosków.
Dzieje się tak , ponieważ krotki nie zawierają list, ciągów znaków ani liczb. Zawierają odniesienia do innych obiektów . 1 Brak możliwości zmiany kolejności odwołań, które zawiera krotka, nie oznacza, że nie można mutować obiektów powiązanych z tymi odwołaniami. 2
1. Obiekty, wartości i typy (patrz: przedostatni akapit)
2. Standardowa hierarchia typów (patrz: „Niezmienne sekwencje”)
Przede wszystkim słowo „niezmienny” może oznaczać wiele różnych rzeczy dla różnych ludzi. Szczególnie podoba mi się sposób, w jaki Eric Lippert skategoryzował niezmienność w swoim blogu . Wymienia tam te rodzaje niezmienności:
Można je łączyć na różne sposoby, aby uzyskać jeszcze więcej rodzajów niezmienności i jestem pewien, że istnieje więcej. Rodzaj niezmienności, który wydaje się być zainteresowany głęboką (znaną również jako przechodnia) niezmiennością, w której niezmienne obiekty mogą zawierać tylko inne niezmienne obiekty.
Kluczową kwestią jest to, że głęboka niezmienność jest tylko jednym z wielu, wielu rodzajów niezmienności. Możesz przyjąć dowolny preferowany rodzaj, o ile jesteś świadomy, że Twoje pojęcie „niezmiennego” prawdopodobnie różni się od pojęcia „niezmienności” kogoś innego.
Jak rozumiem, to pytanie należy przeformułować jako pytanie dotyczące decyzji projektowych: Dlaczego projektanci Pythona zdecydowali się utworzyć niezmienny typ sekwencji, który może zawierać zmienne obiekty?
Aby odpowiedzieć na to pytanie, musimy myśleć o celu krotki służyć: one służyć jako szybka , ogólnego przeznaczenia sekwencje. Mając to na uwadze, staje się całkiem oczywiste, dlaczego krotki są niezmienne, ale mogą zawierać zmienne obiekty. Dowcip:
Krotki są szybkie i wydajne pod względem pamięci: tworzenie krotek jest szybsze niż listy, ponieważ są niezmienne. Niezmienność oznacza, że krotki mogą być tworzone jako stałe i ładowane jako takie, przy użyciu stałego zwijania . Oznacza to również, że ich tworzenie jest szybsze i bardziej wydajne pod względem pamięci, ponieważ nie ma potrzeby nadmiernej alokacji itp. Są nieco wolniejsze niż listy w celu uzyskania losowego dostępu do elementów, ale ponownie szybsze przy rozpakowywaniu (przynajmniej na moim komputerze). Gdyby krotki były zmienne, nie byłyby tak szybkie do takich celów.
Krotki są uniwersalne : Krotki muszą zawierać dowolny obiekt. Są używane do (szybkiego) wykonywania takich rzeczy, jak listy argumentów o zmiennej długości (za pośrednictwem *
operatora w definicjach funkcji). Gdyby krotki nie mogły zawierać zmiennych obiektów, byłyby bezużyteczne do takich rzeczy. Python musiałby używać list, co prawdopodobnie spowolniłoby działanie i na pewno byłoby mniej wydajne pod względem pamięci.
Więc widzisz, aby spełnić swój cel, krotki muszą być niezmienne, ale także muszą być w stanie zawierać zmienne obiekty. Gdyby projektanci Pythona chcieli stworzyć niezmienny obiekt, który gwarantuje, że wszystkie obiekty, które „zawiera”, są również niezmienne, musieliby stworzyć trzeci typ sekwencji. Zysk nie jest wart dodatkowej złożoności.
Nie możesz zmienić id
jego pozycji. Dlatego zawsze będzie zawierał te same elementy.
$ python
>>> t = (1, [2, 3])
>>> id(t[1])
12371368
>>> t[1].append(4)
>>> id(t[1])
12371368
Wyjdę na skraj i powiem, że istotną częścią tutaj jest to, że chociaż możesz zmienić zawartość listy lub stan obiektu zawartego w krotce, nie możesz zmienić tego, że obiekt lub lista jest tam. Gdybyś miał coś, co zależało od rzeczy [3] będącej listą, nawet jeśli byłaby pusta, to widziałem, że jest to przydatne.
Jednym z powodów jest to, że w Pythonie nie ma ogólnego sposobu na przekonwertowanie zmiennego typu na niezmienny (zobacz odrzucony PEP 351 i połączoną dyskusję, dlaczego został odrzucony). W związku z tym niemożliwe byłoby umieszczanie różnych typów obiektów w krotkach, gdyby istniało takie ograniczenie, w tym prawie każdego obiektu utworzonego przez użytkownika, którego nie można hashować.
Jedynym powodem, dla którego słowniki i zestawy mają to ograniczenie, jest to, że wymagają one, aby obiekty były hashowane, ponieważ są wewnętrznie implementowane jako tabele skrótów. Należy jednak pamiętać, że, jak na ironię, same słowniki i zestawy nie są niezmienne (ani hashowalne). Krotki nie używają skrótu obiektu, więc jego zmienność nie ma znaczenia.
Krotka jest niezmienna w tym sensie, że sama krotka nie może się rozszerzać ani zmniejszać, a nie wszystkie zawarte w niej elementy są niezmienne. W przeciwnym razie krotki są nudne.