Niniejszy artykuł można potraktować jako uzupełnienie do kursów Pythona zamieszczonego na stronie. Dla tych co lubią zrozumieć 🙂

Spis treści:

Czym jest zmienna i co tak naprawdę robimy, kiedy przypisujemy do zmiennej (za pomocą znaku “=”) jakąś wartość?

Jeśli nie jesteś całkiem początkującym adeptem programowania, to już wiesz, że zmienne przechowują wartości o różnych typach danych (string, liczby itd.). Może spotkałeś się z określeniem, że zmienna jest pojemnikiem, w którym są przechowywane wartości. Myślenie o zmiennych jako o pojemnikach nie jest do końca właściwe. Jest to użyteczna metafora, którą wykorzystuje się, aby wytłumaczyć nowicjuszom pojęcie zmiennej. Tak naprawdę zmienna jest odwołaniem do danego obiektu. Jeśli lubisz porównania, to dla mnie zmienna jest czymś w rodzaju etykiety na pudełku, w którym jest przechowywana wartość.  Etykietę tę mogę w każdej chwili odkleić i przyczepić do nowego pudełka z inną wartością.

Wszystko jest obiektem

Na początku nauki najpierw poznawałeś typy danych. Nauczyłeś się, co to są stringi, listy czy słowniki. Poznałeś niektóre metody, które można wykonywać na tekście, jak np. upper(), lower(), split(). Kiedy doszedłeś do klas, dowiedziałeś się, że metody to funkcje wewnątrz klasy. Może zaświtała ci wtedy myśl: “Chwila moment, przecież już wcześniej nauczyłem się jakichś metod”. To nie jest żadna pomyłka w nazewnictwie. Wymienione przeze mnie metody są metodami klasy str. Z kolei metoda append(), za pomocą której dodajesz nowy element do listy, jest metodą klasy list. Kiedy wpiszesz, do swojego interpretera jakiś tekst, liczbę, czy cokolwiek innego, to tworzysz obiekt.

>>> "nic"
'nic'
>>> type("nic")
<class 'str'>

Zmienna jest po prostu odwołaniem do tego obiektu. W Pythonie instrukcja przypisania (znak “=”) nie kopiuje obiektu, lecz tworzy powiązanie między celem a obiektem. Przyjrzymy się teraz kilku zmiennym i temu co robi Python.

a=1000
b=a
a+=1000
print("a: ", a, "b: ", b)
>>>
a: 2000 b: 1000  

Do zmiennej a przypisaliśmy liczbę 1000, więc Python stworzył obiekt int o wartości 1000. Następnie do zmiennej b przypisaliśmy zmienną a, co oznacza, że obie zmienne odwołują się do tego samego obiektu.

Kiedy do zmiennej a dodaliśmy 1000, Python utworzył nowy obiekt z nową wartością, ale odwołanie zmiennej b do obiektu z wartością 1000 się nie zmieniło.

c=[1,2,3,10,11,12]
d=c
d.append(13)
print("Lista d:", d)
print("Lista c:", c)

>>>
Lista d: [1, 2, 3, 10, 11, 12, 13]
Lista c: [1, 2, 3, 10, 11, 12, 13]

Do zmiennej c przypisaliśmy obiekt klasy list i poprzez przypisanie zmiennej c do d utworzyliśmy dwa odwołania do tej samej listy. Zauważ, że po zastosowaniu metody append() dodaliśmy liczbę 13 nie tylko do zmiennej d, ale również zmieniła się wartość c. Przypisanie zmiennej do innej zmiennej nie tworzy kopii. I tutaj pojawia się pytanie: w jaki sposób zrobić kopię listy, tak żebyśmy mogli zmieniać tę kopię, nie zmieniając oryginalnej listy? Na to pytanie odpowiem w następnym artykule, który będzie dotyczył kopiowania list i słowników.

Chciałabym teraz napisać jeszcze kilka słów o stringach i metodach klasy string. Wyjaśnię dlaczego w poprzednim kodzie zmieniając wartość zmiennej a, nie zmieniła się b, pomimo że obie zmienne odwoływały się do tego samego obiektu.

Immutable vs mutable

Kiedy wykonujesz jakąś operację na liście, np. dodawanie nowego elementu, usunięcie, łączenie list, czy cokolwiek innego, to wykonujesz operację na tym samym obiekcie, do którego odwołuje się lista. A jak to jest w przypadku stringów?

var1="Ania"
var1.replace("a","o")
print(var1)

>>> Ania

Dlaczego wartość naszej zmiennej się nie zmieniła? Przecież jak używaliśmy list.append(item), to lista się zmieniała. Czemu Python nic nie zrobił? Ależ zrobił! Podczas wykonywania var1.replace("a","o") utworzył nowy obiekt o wartości “onio”, ale nigdzie go nie przypisaliśmy. Nasz obiekt, do którego się odwołujemy w var1, czyli łańcuch znaków “Ania” nie może się zmienić, bo stringi są niemutowalne (immutable), czyli niezmienialne. Poza stringami niemutowalne są także liczby (float, integer) czy krotki (tuple). Poniżej zamieszczam ściągę:

Typy niemutowalneTypy mutowalne
int
float
decimal
complex
bool
string
tuple
range
frozenset
bytes
list
dictionary
set
bytearray
klasy zdefiniowane przez użytkownika

Jeśli chcesz “zmienić” typ niemutowalny, to musisz robisz to przez utworzenie nowego obiektu. Na przykład, jeśli chciałbyś zmienić jakiś element w krotce, to musisz ją najpierw przekonwertować na listę, a potem możesz z powrotem zamienić w krotkę.
Uwaga: nie można bezpośrednio przekonwertować int na list, ale można najpierw zamienić na str, a potem na list 🙂

some_tuple=(1,2,3,4,5)
some_tuple=list(some_tuple)
some_tuple+=[6]
print(some_tuple)
some_tuple=tuple(some_tuple)
print(some_tuple)

>>>
[1, 2, 3, 4, 5, 6]
(1, 2, 3, 4, 5, 6)
var1 = "Ania"
var1 = var1.replace("a","o") #Python tworzy nowy obiekt
print(var1)

>>>
onio

Operator “is”, czyli jak sprawdzić czy coś jest tym samym obiektem.

Przy zwykłym operatorze porównania “==” sprawdzane jest, czy obie strony mają taki sam typ danych i wartość. W przypadku is obie strony muszą się odnosić do tego samego obiektu.

v1="5"
v2=5
v3=v2
print(v1==v2)
print(v1 is v2)
print(v3 is v2)

>>>
False
False
True

Jak widać w Pythonie nie prawdą jest, że “5”==5, bo są inne typy danych. Jeśli ktoś uczył się JavaScript, to tam pokazałoby True. W Pythonie trzeba przekonwertować string na integer albo integer na string. Możecie się trochę pobawić z is i posprawdzać wasze zmienne.

x = [1, 2, 3, 4, 5]
y = [1, 2, 3, 4, 5]
print(x is y)
print(x==y)

>>>
False
True

Powyższy kod pokazuje,że listy x i y nie są tym samym obiektem, chociaż mają tę samą wartość.  Można także użyć innego sposobu, np. wbudowanej funkcji id(object)

x = [1, 2, 3, 4, 5]
y = x
print(id(x),id(y))

>>>
164116232 164116232

Podsumowanie

Zmienne nie przechowują bezpośrednio wartości, a jedynie odwołanie do niej. Jeśli chcesz zmienić niemutowalny obiekt (string, krotka, itd.), to musisz nadpisać zmienną, która się odwołuje do tego obiektu. Przy czym nie zmieniasz samego obiektu, tylko tworzysz nowy. Listy i słowniki są modyfikowalne, co oznacza, że ich zawartość można zmienić.