Capítulo 22, Básico
Mutabilidade e identidade
Este é o capítulo que separa quem decorou a sintaxe de quem entende o modelo de objetos de Python. Quase todo bug estranho com listas e funções nasce aqui.
Código deste capítulo: basico/cap22_mutabilidade.py
Nomes, objetos e id
Lembra da etiqueta do primeiro capítulo? Cada objeto tem uma identidade (o id), e dois nomes podem apontar para o mesmo objeto. O operador == compara valores. O operador is compara identidades:
a = [1, 2]
b = [1, 2]
c = a
print(a == b, a is b, a is c)
print(id(a) == id(c))
True False True
True
a e b têm o mesmo conteúdo, mas são objetos diferentes. c é só outro nome para a.
Mutável e imutável
| Imutáveis (o objeto nunca muda) | Mutáveis (o objeto pode mudar) |
|---|---|
int, float, bool, complex | list |
str, bytes | dict |
tuple, frozenset | set, bytearray |
None | A maioria dos objetos que você define |
Quando você "altera" um imutável, na verdade cria um novo objeto e aponta o nome para ele. Quando altera um mutável, o objeto muda, e todos os nomes que apontam para ele enxergam a mudança.
O que acontece nas funções
O Python passa o nome do objeto, não uma cópia. Se a função altera o objeto, quem chamou vê. Se a função apenas aponta o nome local para outro objeto, quem chamou não vê:
def anexar(lista):
lista.append(99)
def reatribuir(lista):
lista = [0]
dados = [1, 2]
anexar(dados)
print(dados)
reatribuir(dados)
print(dados)
[1, 2, 99]
[1, 2, 99]
A armadilha da matriz
Multiplicar uma lista por um número repete a referência, não o objeto. Por isso a "matriz" abaixo tem três linhas que são, na verdade, a mesma lista:
errada = [[0] * 3] * 3
errada[0][0] = 1
print(errada)
certa = [[0] * 3 for _ in range(3)]
certa[0][0] = 1
print(certa)
[[1, 0, 0], [1, 0, 0], [1, 0, 0]]
[[1, 0, 0], [0, 0, 0], [0, 0, 0]]
A segunda forma usa uma compreensão de lista, que eu apresento no nível intermediário. Ela cria uma lista nova a cada volta.
Quando usar is
Use
iscomNone,TrueeFalsee com valores sentinela que você mesmo criou. Para todo o resto, use==. Comparar números ou strings comispode funcionar por acaso, por causa de otimizações do interpretador, e quebrar em outro momento.
Exercício 1
Copiar uma matriz de verdade
Escreva copiar_matriz(matriz) de modo que alterar a cópia não altere o original.