Jestem zdezorientowany, czym jest niezmienny typ. Wiem, że float
obiekt jest uważany za niezmienny, z tego rodzaju przykładem z mojej książki:
class RoundFloat(float):
def __new__(cls, val):
return float.__new__(cls, round(val, 2))
Czy jest to uważane za niezmienne ze względu na strukturę / hierarchię klas ?, co float
oznacza, że znajduje się na szczycie klasy i jest własnym wywołaniem metody. Podobny do tego typu przykładu (chociaż moja książka mówi, że dict
można go modyfikować):
class SortedKeyDict(dict):
def __new__(cls, val):
return dict.__new__(cls, val.clear())
Podczas gdy coś zmiennego ma metody wewnątrz klasy, z tego rodzaju przykładem:
class SortedKeyDict_a(dict):
def example(self):
return self.keys()
Poza tym class(SortedKeyDict_a)
, jeśli przekażę mu ten typ zestawu:
d = (('zheng-cai', 67), ('hui-jun', 68),('xin-yi', 2))
bez wywoływania example
metody zwraca słownik. SortedKeyDict
Z __new__
flagami jako błąd. Próbowałem przekazać liczby całkowite do RoundFloat
klasy __new__
i nie oznaczało to żadnych błędów.
python
immutability
mutable
użytkownik1027217
źródło
źródło
Odpowiedzi:
Co? Pływaki są niezmienne? Ale nie mogę
Czy to nie „mut” x?
Cóż, zgadzasz się, że ciągi są niezmienne, prawda? Ale możesz zrobić to samo.
Wartość zmiennej zmienia się, ale zmienia się poprzez zmianę tego, do czego odnosi się zmienna. Zmienny typ może zmienić w ten sposób, a także może zmienić „na miejscu”.
Oto różnica.
Konkretne przykłady
źródło
def f(my_list): my_list = [1, 2, 3]
. W przypadku przekazywania przez odwołanie w C wartość argumentu może się zmienić przez wywołanie tej funkcji. W Pythonie ta funkcja nic nie robi.def f(my_list): my_list[:] = [1, 2, 3]
zrobiłby coś.a += b
czasem jest mutacją. A fakt, że przypisanie do części większego obiektu czasami oznacza mutację tego większego obiektu, po prostu nigdya[0] = b
nie powoduje mutacji części - np. Nie mutujea[0]
, ale prawdopodobnie mutujea
… Właśnie dlatego lepiej nie próbowaćMusisz zrozumieć, że Python reprezentuje wszystkie swoje dane jako obiekty. Niektóre z tych obiektów, takie jak listy i słowniki, można modyfikować, co oznacza, że możesz zmieniać ich zawartość bez zmiany ich tożsamości. Inne obiekty, takie jak liczby całkowite, zmiennoprzecinkowe, łańcuchy i krotki są obiektami, których nie można zmienić. Łatwy sposób to zrozumieć, jeśli spojrzysz na identyfikator obiektu.
Poniżej widać ciąg niezmienny. Nie możesz zmienić jego zawartości. Podniesie a,
TypeError
jeśli spróbujesz to zmienić. Ponadto, jeśli przypiszemy nową treść, zamiast modyfikowanej zawartości tworzony jest nowy obiekt.Możesz to zrobić za pomocą listy, która nie zmieni tożsamości obiektów
Aby dowiedzieć się więcej o modelu danych Pythona, zapoznaj się z odnośnikiem do języka Python:
źródło
Typowy niezmienny typ:
int()
,float()
,complex()
str()
,tuple()
,frozenset()
,bytes()
Typowy typ mutable (prawie wszystko inne):
list()
,bytearray()
set()
dict()
Jednym ze sposobów szybkiego sprawdzenia, czy typ jest zmienny, czy nie, jest użycie
id()
wbudowanej funkcji.Przykłady na liczbach całkowitych
używając na liście,
źródło
id()
. +1.id()
tutaj jest mylące. Dany obiekt zawsze będzie miał ten sam identyfikator podczas swojego życia, ale różne obiekty, które istnieją w różnych czasach, mogą mieć ten sam identyfikator z powodu wyrzucania elementów bezużytecznych.Po pierwsze, to, czy klasa ma metody, czy jaka jest jej struktura, nie ma nic wspólnego ze zmiennością.
int
sifloat
są niezmienne . Jeśli zrobięWskazuje ona nazwę
a
na1
gdzieś w pamięci na pierwszej linii. W drugiej linii, wygląda się, że1
dodaje5
, dostaje6
, to punktya
na to6
w pamięci - to nie zmienia1
Do6
w jakikolwiek sposób. Ta sama logika dotyczy następujących przykładów, wykorzystując inne niezmienne typy:W przypadku zmiennych typów mogę robić rzeczy, które faktycznie zmieniają wartość, w której są przechowywane w pamięci . Z:
I stworzyliśmy listę miejsc
1
,2
oraz3
w pamięci. Jeśli to zrobięWskazuję tylko
e
na te samelist
d
punkty. Mogę wtedy zrobić:A lista, na którą zarówno
e
id
wskazuje, zostanie zaktualizowana, aby zawierała również lokalizację4
i5
w pamięci.Jeśli wrócę do niezmiennego typu i zrobię to z
tuple
:Wtedy
f
nadal wskazuje tylko oryginałtuple
- wskazałeśg
na zupełnie nowytuple
.Teraz na przykładzie
Gdzie mijasz
(co jest
tuple
ztuples
) jakoval
, dostajesz błąd, ponieważtuple
s nie ma.clear()
sposobu - trzeba by przekazaćdict(d)
jakval
do niego do pracy, w takim przypadku dostaniesz pustySortedKeyDict
wyniku.źródło
Jeśli przyjeżdżasz do Pythona z innego języka (z wyjątkiem tego, który jest podobny do Pythona, takiego jak Ruby) i nalega na zrozumienie go w odniesieniu do tego innego języka, tutaj ludzie zwykle się mylą:
W Pythonie przypisanie nie jest mutacją w Pythonie.
W C ++, jeśli piszesz
a = 2
, dzwonisza.operator=(2)
, co zmutuje obiekt przechowywany wa
. (A jeśli nie było w nim żadnego obiektua
, to błąd).W Pythonie
a = 2
nic nie robi na to, co zostało zapisanea
; oznacza to po prostu, że2
teraz jest przechowywanya
. (A jeśli nie było w nim żadnego obiektua
, to w porządku.)Ostatecznie jest to część jeszcze głębszego rozróżnienia.
Zmienna w języku takim jak C ++ to wpisana lokalizacja w pamięci. Jeśli
a
jest toint
, oznacza to, że gdzieś jest 4 bajty, o których kompilator wie, że należy je interpretować jakoint
. Kiedy to zrobisza = 2
, zmienia to, co jest zapisane w tych 4 bajtach pamięci od0, 0, 0, 1
do0, 0, 0, 2
. Jeśli gdzieś jest inna zmienna int, ma ona swoje 4 bajty.Zmienna w języku takim jak Python jest nazwą obiektu, który ma własne życie. Istnieje obiekt dla liczby
1
i inny obiekt dla liczby2
. Ia
nie ma 4 bajtów pamięci, które są reprezentowane jakoint
, to tylko nazwa wskazująca na1
obiekt. Nie ma sensua = 2
przekształcanie liczby 1 w liczbę 2 (dałoby to każdemu programistowi w Pythonie o wiele za dużo mocy, aby zmienić podstawowe zasady działania wszechświata); zamiast tego po prostua
zapomina o1
obiekcie i2
zamiast tego wskazuje na obiekt.Jeśli więc przypisanie nie jest mutacją, czym jest mutacja?
a.append(b)
. (Zauważ, że te metody prawie zawsze powracająNone
). Niezmienne typy nie mają takich metod, zwykle mają zmienne typy.a.spam = b
luba[0] = b
. Niezmienne typy nie pozwalają na przypisanie atrybutów lub elementów, typy zmienne zwykle pozwalają na jedno lub drugie.a += b
, czasem nie. Zmienne typy zwykle mutują wartość; niezmienne typy nigdy tego nie robią i zamiast tego dają ci kopię (obliczająa + b
, a następnie przypisują wynika
).Ale jeśli przypisanie nie jest mutacją, w jaki sposób przypisanie do części mutacji obiektowej? To tam staje się trudne.
a[0] = b
robi nie mutacjia[0]
(ponownie, w przeciwieństwie do C ++), ale robi mutacjia
(w przeciwieństwie do C ++, z wyjątkiem pośrednio).Wszystko to sprawia, że prawdopodobnie lepiej nie próbować układać semantyki języka Python w kategoriach języka, w którym się przyzwyczaiłeś, a zamiast tego uczyć się semantyki języka Python na własnych warunkach.
źródło
To, czy obiekt można modyfikować, zależy od jego typu. Nie zależy to od tego, czy ma pewne metody, ani od struktury hierarchii klas.
Typy zdefiniowane przez użytkownika (tj. Klasy) są generalnie zmienne. Istnieją pewne wyjątki, takie jak proste podklasy niezmiennego typu. Inne typy niezmienne obejmują niektóre typy wbudowane, takie jak
int
,float
,tuple
istr
, a także niektóre klasy Pythona realizowane w C.Ogólne wyjaśnienie z rozdziału „Model danych” w Skorowidzu języka Python ” :
źródło
Różnica między obiektami zmiennymi i niezmiennymi
Definicje
Zmienny obiekt : Obiekt, który można zmienić po utworzeniu.
Niezmienny obiekt : Obiekt, którego nie można zmienić po utworzeniu.
W Pythonie, jeśli zmienisz wartość niezmiennego obiektu, utworzy on nowy obiekt.
Zmienne obiekty
Oto obiekty w Pythonie, które są typu zmiennego:
list
Dictionary
Set
bytearray
user defined classes
Niezmienne przedmioty
Oto obiekty w Pythonie, które są niezmiennego typu:
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
Niektóre pytania bez odpowiedzi
Pytania : Czy ciąg znaków jest niezmienny?
Odpowiedź : tak , ale czy możesz to wyjaśnić: Dowód 1 :
Wynik
W powyższym przykładzie ciąg został kiedyś utworzony jako „Hello”, a następnie zmieniony na „Hello World”. Oznacza to, że ciąg jest typu zmiennego. Nie dzieje się tak jednak, gdy sprawdzamy jego tożsamość, aby sprawdzić, czy jest typu zmiennego, czy nie.
Wynik
Dowód 2 :
Wynik
Pytania : Czy Tuple jest niezmiennym typem?
Odpowiedź : tak jest. Dowód 1 :
Wynik
źródło
Zmienny obiekt musi mieć przynajmniej metodę zdolną do zmutowania obiektu. Na przykład
list
obiekt maappend
metodę, która faktycznie zmutuje obiekt:ale klasa
float
nie ma metody mutacji obiektu zmiennoprzecinkowego. Możesz to zrobić:ale
=
operand nie jest metodą. Po prostu tworzy powiązanie między zmienną a tym, co jest po jej prawej stronie, niczym więcej. Nigdy nie zmienia ani nie tworzy obiektów. Jest to deklaracja tego, na co wskazuje zmienna, od teraz.Kiedy robisz operand wiąże zmienną do nowej float, w którym jest utworzony TE wyniku .
b = b + 0.1
=
5 + 0.1
Po przypisaniu zmiennej do istniejącego obiektu, zmiennego lub nie,
=
operand wiąże zmienną z tym obiektem. I nic więcej się nie dziejeW obu przypadkach
=
wystarczy wykonać powiązanie. Nie zmienia ani nie tworzy obiektów.Gdy to zrobisz
a = 1.0
,=
operand nie tworzy pływaka, ale1.0
część linii. Właściwie podczas pisania1.0
jest to skrót dlafloat(1.0)
wywołania konstruktora zwracającego obiekt zmiennoprzecinkowy. (Z tego powodu, jeśli wpiszesz1.0
i naciśniesz Enter, wyświetli się „echo”1.0
wydrukowane poniżej; to jest wartość zwracana przez wywołaną funkcję konstruktora)Teraz, jeśli
b
jest pływak i przypisaća = b
obie zmienne są skierowane do tego samego obiektu, ale w rzeczywistości zmienne sami nie mogą porozumieć betweem, ponieważ obiekt jest inmutable, a jeśli nieb += 1
, terazb
punkt do nowego obiektu, aa
jest wciąż wskazuje na oldone i nie może wiedzieć, na cob
wskazuje.ale jeśli
c
jest, powiedzmy, alist
, a ty przypisujesza = c
, teraza
ic
możesz „komunikować się”, ponieważlist
jest zmienny, a jeśli takc.append('msg')
, to po prostu sprawdź,a
czy dostałeś wiadomość.(Nawiasem mówiąc, do każdego obiektu przypisany jest unikalny numer identyfikacyjny, który można uzyskać
id(x)
. Możesz więc sprawdzić, czy obiekt jest taki sam lub nie sprawdzać, czy jego unikalny identyfikator się zmienił).źródło
Innymi słowy zmień całą wartość tej zmiennej
(name)
lub zostaw ją w spokoju.Przykład:
spodziewałeś się, że to zadziała i wydrukuje hello world, ale spowoduje to zgłoszenie następującego błędu:
Tłumacz mówi: nie mogę zmienić pierwszego znaku tego ciągu
będziesz musiał zmienić całość
string
, aby działała:sprawdź tę tabelę:
źródło
źródło
my_string = 'h' + my_string[1:]
. Spowoduje to wygenerowanie nowego ciągu o nazwie my_string, a oryginalny my_string zniknie (wydrukuj,id(my_string)
aby to zobaczyć). Oczywiście nie jest to zbyt elastyczne, w bardziej ogólnym przypadku można przekonwertować na listę iz powrotem:l = list(my_string)
l[0] = 'h'
my_string = ''.join(l)
Wydaje mi się, że walczysz z pytaniem, co tak naprawdę oznacza zmienność / niezmienność . Oto proste wyjaśnienie:
Najpierw potrzebujemy podstaw, na których oprą się badania.
Pomyśl więc o wszystkim, co programujesz jako o obiekcie wirtualnym, o czymś, co jest zapisane w pamięci komputera jako ciąg liczb binarnych. (Nie próbuj jednak zbytnio sobie tego wyobrażać. ^^) Teraz w większości języków komputerowych nie będziesz pracować bezpośrednio z tymi liczbami binarnymi, ale raczej używasz interpretacji liczb binarnych.
Np. Nie myślisz o liczbach takich jak 0x110, 0xaf0278297319 lub podobnych, ale zamiast tego myślisz o liczbach takich jak 6 lub Ciągach takich jak „Witaj, świecie”. Mimo to tezy liczb lub ciągów są interpretacją liczby binarnej w pamięci komputera. To samo dotyczy dowolnej wartości zmiennej.
W skrócie: My nie programować z rzeczywistych wartości, ale z interpretacji rzeczywistych wartości binarnych.
Teraz mamy interpretacje, których nie można zmieniać ze względu na logikę i inne „czyste rzeczy”, podczas gdy istnieją interpretacje, które mogą ulec zmianie. Pomyśl na przykład o symulacji miasta, innymi słowy program, w którym jest wiele wirtualnych obiektów, a niektóre z nich to domy. Czy te wirtualne obiekty (domy) mogą zostać zmienione i czy nadal można je uznać za te same domy? Oczywiście, że mogą. Są więc zmienne: można je zmieniać, nie stając się „całkowicie” innym przedmiotem.
Pomyślmy teraz o liczbach całkowitych: są to także obiekty wirtualne (sekwencje liczb binarnych w pamięci komputera). Jeśli więc zmienimy jedną z nich, na przykład zwiększając wartość sześć po drugiej, czy nadal będzie to szóstka? Oczywiście, że nie. Zatem każda liczba całkowita jest niezmienna.
Tak więc: jeśli jakakolwiek zmiana w obiekcie wirtualnym oznacza, że faktycznie staje się on kolejnym obiektem wirtualnym, to nazywa się to niezmiennym.
Uwagi końcowe:
(1) Nigdy nie mieszaj swojego prawdziwego doświadczenia ze zmiennością i niezmiennością z programowaniem w określonym języku:
Każdy język programowania ma własną definicję, na których obiektach można wyciszać, a które nie.
Chociaż możesz teraz zrozumieć różnicę w znaczeniu, nadal musisz nauczyć się faktycznej implementacji dla każdego języka programowania. ... Rzeczywiście może istnieć cel języka, w którym 6 może zostać wyciszony, aby stać się 7. W takim razie byłyby to całkiem szalone lub interesujące rzeczy, takie jak symulacje równoległych wszechświatów. ^^
(2) To odkrycie z pewnością nie jest naukowe, ma pomóc ci zrozumieć różnicę między zmienną a niezmienną.
źródło
Celem tej odpowiedzi jest stworzenie jednego miejsca, w którym można znaleźć wszystkie dobre pomysły na temat tego, jak stwierdzić, czy masz do czynienia z mutacją / mutacją (niezmienną / zmienną) i, gdzie to możliwe, co z tym zrobić? Są chwile, kiedy mutacja jest niepożądana, a zachowanie Pythona w tym zakresie może wydawać się sprzeczne z intuicją dla koderów przychodzących z innych języków.
Jak na przydatny post @ mina-gabriel:
Analizując powyższe i łącząc w / post przez @ arrakëën:
Co nie może się zmienić nieoczekiwanie?
Co może?
przez „nieoczekiwanie” mam na myśli to, że programiści z innych języków mogą nie oczekiwać tego zachowania (z wyjątkiem Ruby i może kilku innych języków „podobnych do Pythona”).
Dodanie do tej dyskusji:
Takie zachowanie jest korzystne, gdy zapobiega przypadkowemu zapełnieniu kodu wielowymiarowymi kopiami dużych struktur danych zajmujących pamięć. Ale kiedy jest to niepożądane, jak sobie z tym poradzić?
W przypadku list prostym rozwiązaniem jest zbudowanie nowego takiego:
list2 = lista (lista1)
z innymi strukturami ... rozwiązanie może być trudniejsze. Jednym ze sposobów jest zapętlenie elementów i dodanie ich do nowej pustej struktury danych (tego samego typu).
funkcje mogą mutować oryginał, gdy przechodzisz w zmienne struktury. Jak powiedzieć?
Podejścia niestandardowe (w razie potrzeby): Znaleziono to na github opublikowanym na licencji MIT:
W przypadku klas niestandardowych @semicolon sugeruje sprawdzenie, czy istnieje
__hash__
funkcja, ponieważ zmienne obiekty zasadniczo nie powinny mieć__hash__()
funkcji.To wszystko, co na razie zgromadziłem na ten temat. Inne pomysły, poprawki itp. Są mile widziane. Dzięki.
źródło
Jeden sposób myślenia o różnicy:
Przypisania niezmiennych obiektów w pythonie można traktować jako głębokie kopie, podczas gdy przypisania do obiektów zmiennych są płytkie
źródło
Najprostsza odpowiedź:
Zmienna zmienna to taka, której wartość może ulec zmianie w miejscu, natomiast w zmiennej niezmiennej zmiana wartości nie nastąpi. Modyfikacja niezmiennej zmiennej odbuduje tę samą zmienną.
Przykład:
Utworzy wartość 5, do której odnosi się x
x -> 5
To stwierdzenie spowoduje, że y odniesie się do 5 z x
x -------------> 5 <----------- y
Ponieważ x jest liczbą całkowitą (typ niezmienny) został odbudowany.
W oświadczeniu wyrażenie na RHS będzie miało wartość 10, a gdy zostanie ono przypisane do LHS (x), x przebuduje się na 10. Więc teraz
x ---------> 10
y ---------> 5
źródło
Nie przeczytałem wszystkich odpowiedzi, ale wybrana odpowiedź jest nieprawidłowa i myślę, że autor ma pomysł, że możliwość zmiany przypisania zmiennej oznacza, że każdy typ danych jest zmienny. Tak nie jest. Zmienność ma związek z przekazywaniem przez odniesienie, a nie przekazywaniem wartości.
Powiedzmy, że utworzyłeś listę
Gdybyś powiedział:
Nawet jeśli ponownie przypisałeś wartość na B, to również zmieni przypisanie wartości na a. Jest tak, ponieważ kiedy przypisujesz „b = a”. Przekazujesz „odwołanie” do obiektu, a nie kopię wartości. Nie dotyczy to ciągów, liczb zmiennoprzecinkowych itp. To sprawia, że lista, słowniki i podobne zmienne są zmienne, ale wartości logiczne, zmiennoprzecinkowe itp. Są niezmienne.
źródło
W przypadku obiektów niezmiennych przypisanie tworzy na przykład nową kopię wartości.
W przypadku obiektów zmiennych przypisanie nie tworzy kolejnej kopii wartości. Na przykład,
źródło
x=10
jest to po prostu inne zadanie , podczas gdyx[2] = 5
wywołuje metodę mutatora.int
obiektom po prostu brakuje metod mutatora , ale semantyka przypisania pytona nie zależy od typuW Pythonie istnieje prosty sposób na sprawdzenie:
Niezmienny:
Zmienny:
I:
Myślę więc, że wbudowana funkcja jest również niezmienna w Pythonie.
Ale tak naprawdę nie rozumiem, jak działa float:
To takie dziwne.
źródło
x = (1, 2)
a następnie spróbuj mutowaćx
, nie jest to możliwe. Jednym ze sposobów, w jaki znalazłem sprawdzanie zmienności, jest tohash
, że działa ono przynajmniej dla wbudowanych obiektów.hash(1)
hash('a')
hash((1, 2))
hash(True)
cała praca ihash([])
hash({})
hash({1, 2})
wszyscy nie działają.hash()
będzie działać, jeśli obiekt__hash__()
zdefiniuje metodę, nawet jeśli klasy zdefiniowane przez użytkownika są ogólnie zmienne.hash
metoda jest wciąż całkiem dobra, ponieważ zmienne obiekty zasadniczo nie powinny mieć__hash__()
metody, ponieważ tworzenie ich kluczy w słowniku jest po prostu niebezpieczne.