Imutabilidade de Strings no Python

Imutabilidade de Strings no Python

Você provavelmente já ouviu a seguinte frase:

Strings no Python são objetos imutáveis!

E foi correndo para o seu terminal escrever o seguinte código:

palavra = "abc"
palavra = "def" 
print(palavra)  # Imprime "def"

Talvez tenha se perguntado por que esse programa funcionou... Afinal, se strings são objetos imutáveis no Python, eu não estou alterando a variável palavra de "abc" para "def"? Ou seja, "mutando" esse valor?

Mais ou menos... Na verdade, estamos alterando a variável – que antes referenciava a string "abc" e passou a referenciar a string "def" – mas o valor "abc" não foi alterado!

Mudando a referência da variável "palavra"

Para alterar o valor, ou seja, alterar a string imutável "abc" deveríamos fazer o seguinte:

palavra = "abc"
print(palavra[0])  # Imprime o primeiro caractere, no caso "a "
palavra[0] = "x"  # Tenta alterar o primeiro caractere de "abc" para "x"

Ao executar esse exemplo, você vai obter o seguinte erro:

TypeError: 'str' object does not support item assignment

Já que strings no Python são imutáveis, não podemos atribuir um novo valor a uma string depois de criada – como tentamos fazer com palavra[0] = "x". Note que escrever palavra = alguma_coisa e depois palavra = outra_coisa é alterar qual objeto nossa variável referencia, mas não o valor do objeto em si ("abc").

Mutável vs Imutável

Talvez seja mais fácil entender se compararmos com o exemplo de algum objeto mutável. Para isso, vamos utilizar a Lista (list):

lista = ["a", "b", "c"]  # Cria uma lista com 3 elementos onde cada elemento da lista é um caractere
palavra = "abc"  # Cria uma string com 3 caracteres

lista[0] = "x"
print(lista)  # Imprime ['x', 'b', 'c']

palavra[0] = "x"  # TypeError!

Como listas são objetos mutáveis em Python, a gente pode alterar o seu valor depois de criada. No caso, alteramos o valor do primeiro elemento da lista de "a" para "x".

Imutabilidade e economia de memória

Uma consequência interessante de objetos imutáveis é a economia de memória. Já que a string é imutável, significa que não importa quantas variáveis referenciem esta string, não precisamos nos preocupar em alocar memória múltiplas vezes (uma vez para cada variável), pois não existe o risco de o valor ser alterado.

x = "abc"  # Reserva um espaço de memória para armazenar o valor "abc"
y = "abc"  # Referencia o mesmo espaço de memória reservdo para "abc"

print(id(x) == id(y))  # Vai imprimir True!

Podemos verificar o endereço de memória de um objeto utilizando o método id(obj). No exemplo acima, declaramos duas variáveis diferentes com o valor "abc" em cada uma delas. Porém, pelo fato de "abc" ser um valor imutável, o Python otimizou a utilização de memória e fez com que ambas variáveis (x e y) apontassem (ou referenciassem) para o mesmo endereço de memória onde "abc" está armazenado.

Mais uma vez, vamos utilizar um exemplo utilizando listas (objeto mutável) para entender melhor:

x = ["a", "b", "c"]
y = ["a", "b", "c"]

print(id(x) == id(y))  # Vai imprimir False!

O exemplo acima vai imprimir False pois, apesar das listas x e y armazenarem os mesmos valores (3 elementos, onde cada elemento é um caractere), o interpretador Python vai reservar o espaço de memória necessário para as duas listas, pois listas são objetos mutáveis!