VARIÁVEIS, VALORES E REFERÊNCIAS
Considere o exemplo abaixo:
>>> x = [1, 2, 3]
>>> y = x
>>> x.append(4)
>>> print(y)
Qual o resultado esperado pela execução da última linha (print y)? Se você ficou na dúvida, mesmo que por um curto período de tempo, leia este post até o fim, que você irá entender melhor.
Grave o seguinte:
Em Python, uma variável é apenas um NOME que REFERENCIA a um OBJETO.
Veja o exemplo abaixo:
>>> x = 42
O código acima é muitas vezes lido como “atribui o valor 42 à variável x”. Mas, o que Python faz é o seguinte: cria um objeto do tipo int que possui 42 como valor, cria o nome x e faz com que o nome x referencie o objeto (do tipo int) 42. Assim, toda vez que o nome x for usado em seu código, ele será automaticamente substituído pelo valor do objeto que este nome referencia (42). A imagem abaixo ilustra melhor a relação entre x e 42.
Continuando o exemplo anterior, o que acontece se fizermos o seguinte?
>>> x = x + 1
É simples, o nome x passa a fazer referência a um novo objeto do tipo int, cujo valor é 43.
A imagem a seguir dá uma ideia melhor sobre o que acontece.
Objetos do tipo int são imutáveis. x = x + 1 cria um novo objeto do tipo int (cujo valor é determinado pela soma de x com 1) e faz com que x passe a referenciar esse novo objeto. Se você observar a imagem acima, verá que não há mais seta alguma apontando para o valor 42, isto é, não há mais nenhum nome fazendo referência àquele objeto. Normalmente, um objeto que não possui nome algum o referenciando vira candidato a coleta de lixo, que é um mecanismo que elimina da memória objetos que não são mais necessários. Mas, o interpretador Python não realiza esse processo em objetos do tipo int e do tipo str (quando pequenos). Ao invés disso, ele mantém esses objetos em uma espécie de cache, para não ter que recriá-los em um futuro próximo e a todo momento em que forem necessários. Se quiser confirmar isso:
>>> 42 is 42 # ambos são o mesmo objeto
True
>>> 'ola' is 'ola'
True
>>> [] is [] # o mesmo já não vale para listas
False
Como comentei anteriormente, toda vez que um nome de variável aparece em uma expressão, esse nome é substituído pelo valor do objeto ao qual ele faz referência. Sabendo disso, considere a expressão abaixo:
>>> y = x
O interpretador cria um novo nome y e faz com que ele referencie o objeto referenciado por x.
Agora, o que acontece se fizermos o seguinte?
>>> x = 10
É criado um objeto int com valor 10, e x então passa a referenciar a esse novo objeto.
Tá, e daí?
E daí que entendendo isso tudo, você achará mais natural alguns comportamentos em Python. Por exemplo, teste o seguinte código e tente entender o que acontece:
>>> x = [1, 2, 3]
>>> y = x
>>> x.append(4)
>>> print x
[1, 2, 3, 4]
>>> print y
[1, 2, 3, 4]
Como mostra a imagem abaixo, y = x faz com que y passe a referenciar o mesmo objeto que x referencia.
Isso ocorre porque listas, em Python, são objetos mutáveis. O método append() modifica a lista de modo in-place, isto é, as modificações são feitas no próprio objeto, sem a necessidade de criação de uma nova lista, como ocorreria com objetos imutáveis, como strings ou ints, por exemplo.
Mutável vs Imutável
Vamos ver agora um exemplo da diferença entre um objeto mutável (lista) e um objeto imutável (string). Temos dois objetos, l e s:
>>> l = [1, 2, 3]
>>> s = 'abc'
Queremos adicionar um novo elemento ao fim de cada um deles. Com a lista podemos usar o método append():
>>> l.append(4)
Que adiciona o valor 4 ao final de l, modificando-a. Com a string, não temos esse método disponível, então vamos usar o operador de concatenação:
>>> s = s + 'd'
O lado direito da expressão acima cria uma nova string com o conteúdo de s acrescido do caractere 'd' e faz com que o nome s passe a referenciar essa nova string. Ou seja, ao invés de modificar, foi criado um novo objeto. O antigo valor de s ('abc') passa então a ficar sem referência alguma a ele.
Quem é quem?
Para confirmar se duas variáveis referenciam o mesmo objeto, podemos usar o operador de identidade is que verifica se duas variáveis possuem como valor o mesmo objeto.
>>> x = [1, 2, 3]
>>> y = x
>>> x is y
True
CONTINUA...