Imutabilidade com Python

Nícolas Zein
4 min readDec 22, 2020

--

Atualmente em desenvolvimento de software a imutabilidade está muito presente e cada vez mais sendo usada.

Novas linguagens como Clojure, Rust e Kotlin já foram criadas suportando imutabilidade de um jeito incrível. E até linguagens mais velhas como o Python também estão melhorando esse suporte em seus releases mais recentes.

Mas o que é imutabilidade, quais são os prós e contras e como aplicar em Python? Vamos tentar abordar todos esse tópicos nesse artigo! :)

O que é imutabilidade?

Imutabilidade é quando uma estrutura de dados ou objeto não pode ser alterado após ser inicializado. Isso quer dizer que, após ser instanciado, um objeto terá o mesmo estado do começo ao fim.

Em Python, por exemplo, toda string é imutável:

Como podemos ver na imagem acima, quando transformamos uma string em maiúscula é retornado uma nova instancia de string sem mudarmos o valor da antiga.

Mas por que usar imutabilidade? Quais são os prós e contras de se usar imutabilidade?

Prós

  • Não há efeitos colaterais: toda vez que um objeto mutável é alterado ele sofre um efeito colateral (side effect), ou seja, um objeto pode sofrer alterações indesejadas durante sua existência e consequentemente causar problemas. Quando utilizamos objetos imutáveis isso não acontece pois sabemos que após inicializado os valores nunca mudarão.
  • Thread Safety: quando usamos imutabilidade não precisamos nos preocupar com estados inconsistentes de objetos sendo compartilhados entre threads. Na programação concorrente o uso da imutabilidade é um grande benefício, pois sabemos que ao ser inicializado um objeto não será alterado. Dessa forma, evitamos a introdução de código complexos de funcionalidades de lock e/ou sincronização para garantir esse comportamento.
  • Funções Puras: uma função pura é uma função que retorna o mesmo resultado para o mesmo input toda vez que chamado sem nenhum efeito colateral. Um exemplo básico é uma função de soma, que recebe dois números e retorna um novo número.
    O benefício de se usar funções puras é que sempre será retornado uma nova instância, nunca alterando as instancias passadas como argumentos, evitando assim confusões.
  • Testabilidade: como não há efeitos colaterais, fica mais fácil de se testar e garantir a qualidade do seu código.

Contras

  • Alocação de memória: ao usar imutabilidade consequentemente acabamos utilizando mais memória, pois estamos criando mais instancias. É claro que muitas linguagens e frameworks já cuidam disso com algum tipo de garbage collector, porém é sempre necessário ficar atento a isso pois a longo prazo pode ser um problema.
  • Custos de implementação: em muitas linguagens e frameworks não há um grande suporte para lidar com imutabilidade, exigindo assim mais linhas de código e isso muitas vezes gera boilerplate.

Imutabilidade com Python

Como dito no começo do artigo as novas releases do Python nos ajudam a trabalhar com imutabilidade de um jeito bem fácil. Isso é possível usando os dataclasses a partir da versão 3.7.

Para criar um objeto imutável basta seguir esse exemplo:

Reparem no parâmetro frozen que está como True, isso faz com que essa classe fique imutável. Por padrão esse parâmetro é False, então toda vez que desejar criar uma classe imutável será necessário passar esse parâmetro como True.

Vamos testar? Caso a gente instancie essa classe e depois tentarmos mudar algum atributo o que irá acontecer?

Se observarmos, na linha 3, ao tentarmos alterar o sobrenome, a exceção FrozenInstanceError foi levantada. Com isso conseguimos garantir que a nossa instancia nunca será alterada após inicializada.

Mas se em nossa aplicação um dia for necessário alterar o sobrenome, como fazemos? Como vimos, podemos criar funções puras que retornem uma nova instancia de usuário.

Nesse simples caso, fazer isso não é tão ruim, porém imagine uma classe com mais atributos e/ou com mais métodos de alteração? Teríamos muito código repetido, o ideal seria “copiar” todos os atributos e só mudarmos os atributos que queremos mudar. Para isso, podemos utilizar uma função chamada replace do módulo de dataclasses.

Desse jeito o nosso método retornará uma nova instancia da classe alterando apenas o sobrenome. Outro benefício que ganhamos, é que, se colocarmos novos atributos e novos métodos na nossa classe, o método altera_sobrenome não será alterado.

Esse é um simples exemplo de como implementar imutabilidade com Python nas versões mais novas. Porém também conseguimos pegar os conceitos de imutabilidade e com um pouquinho a mais de código conseguimos aplicar nas versões mais antigas.

Conclusão

Por fim, podemos concluir que imutabilidade está sendo cada vez mais utilizado no dia a dia. Hoje já conseguimos ter grandes benefícios de um jeito muito abstraído onde o Python já nos fornece.

Porém, vale lembrar que nem sempre imutabilidade é a resposta certa. É sempre bom analisarmos os nossos problemas e vermos qual a melhor solução.

E você? Já utiliza ou deseja utilizar imutabilidade?
Deixe nos comentários suas opiniões! :)

--

--