Mutabilitate și Referințe în Python
Tipuri Mutabile vs Imutabile
Imutabile (nu pot fi modificate în loc)
int,float,boolstrtuplefrozenset
Mutabile (pot fi modificate în loc)
listdictset
Cum Funcționează Referințele
În Python, variabilele sunt referințe la obiecte, nu containere.
a = [1, 2, 3]
b = a # b referă ACELAȘI obiect ca a
# Verificare cu id()
print(id(a) == id(b)) # True - același obiect
# Modificarea prin b afectează și a
b.append(4)
print(a) # [1, 2, 3, 4]
Aliasing și Efecte Secundare
Problema
def adauga_element(lista):
lista.append(99)
numere = [1, 2, 3]
adauga_element(numere)
print(numere) # [1, 2, 3, 99] - lista originală s-a modificat!
Soluții
# Soluția 1: Copiere în funcție
def adauga_element_sigur(lista):
noua_lista = lista.copy()
noua_lista.append(99)
return noua_lista
# Soluția 2: Copiere la apel
numere = [1, 2, 3]
adauga_element(numere.copy())
print(numere) # [1, 2, 3] - neschimbată
Copiere Superficială vs Profundă
Copiere Superficială (Shallow Copy)
original = [[1, 2], [3, 4]]
# Metodele de copiere superficială
copie1 = original.copy()
copie2 = original[:]
copie3 = list(original)
# Problema: listele interioare sunt încă partajate
copie1[0].append(99)
print(original) # [[1, 2, 99], [3, 4]] - afectat!
Copiere Profundă (Deep Copy)
import copy
original = [[1, 2], [3, 4]]
copie = copy.deepcopy(original)
copie[0].append(99)
print(original) # [[1, 2], [3, 4]] - neschimbat!
print(copie) # [[1, 2, 99], [3, 4]]
Comportament cu Funcții
Reatribuire vs Modificare în Loc
def reatribuie(L):
L = [10, 20, 30] # Creează obiect nou
return L
def modifica(L):
L.append(99) # Modifică obiectul existent
return L
lista = [1, 2, 3]
reatribuie(lista)
print(lista) # [1, 2, 3] - neschimbată!
modifica(lista)
print(lista) # [1, 2, 3, 99] - modificată!
Exemplu cu set()
def f(L):
L = list(set(L)) # Reatribuire - nou obiect
L.sort()
return L
T = [3, 1, 2, 1, 3]
r = f(T)
print(r) # [1, 2, 3] - valorile distincte, sortate
print(T) # [3, 1, 2, 1, 3] - neschimbată!
Operatorul is vs ==
a = [1, 2, 3]
b = [1, 2, 3]
c = a
a == b # True - aceleași valori
a is b # False - obiecte diferite
a == c # True - aceleași valori
a is c # True - același obiect
Valori Implicite Mutabile - Capcană!
# GREȘIT - parametru implicit mutabil
def adauga(element, lista=[]):
lista.append(element)
return lista
print(adauga(1)) # [1]
print(adauga(2)) # [1, 2] - NU [2]!
print(adauga(3)) # [1, 2, 3] - NU [3]!
# CORECT
def adauga_corect(element, lista=None):
if lista is None:
lista = []
lista.append(element)
return lista
De Reținut
În Python, variabilele sunt etichete atașate la obiecte. Când pasezi un obiect mutabil unei funcții și îl modifici, modifici originalul. Folosește
.copy()saucopy.deepcopy()când vrei independență.
Întrebări de Verificare
- Ce se întâmplă când faci
b = aundeaeste o listă? - Care este diferența dintre copiere superficială și profundă?
- De ce nu trebuie să folosești liste ca valori implicite?
- Ce diferență este între
isși==?