🐍

Mutabilitate și Referințe în Python

Programare Python Avansat 1 min citire 0 cuvinte

Mutabilitate și Referințe în Python

Tipuri Mutabile vs Imutabile

Imutabile (nu pot fi modificate în loc)

  • int, float, bool
  • str
  • tuple
  • frozenset

Mutabile (pot fi modificate în loc)

  • list
  • dict
  • set

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() sau copy.deepcopy() când vrei independență.

Întrebări de Verificare

  1. Ce se întâmplă când faci b = a unde a este o listă?
  2. Care este diferența dintre copiere superficială și profundă?
  3. De ce nu trebuie să folosești liste ca valori implicite?
  4. Ce diferență este între is și ==?

📚 Articole Corelate