Python tipado? Introdução `às “Type Hints”

Código em Python do MyPy.
Código em Python do MyPy.

Tipagem Estática vs Tipagem Dinâmica

Código em Python do MyPy.
Código em Python do MyPy.

O termo “linguagem tipada” vem de linguagens que possuem Tipagem Estática, ou seja, que ao declararmos a variável, devemos também definir o seu tipo – se ela é uma string, um número inteiro (int) ou ponto flutuante (float), por exemplo. E se você conhece Python, sabe que não é o caso.

C++ é um exemplo clássico de uma linguagem com tipagem estática, e para declarar uma variável em C++ precisamos dizer para o compilador qual tipo de dados esta variável irá receber. Por exemplo.

int meuNumero = 7; // Ok
double meuValor = 17.99; // Ok
string meuNome = "André Lopes"; // Ok

int meuOutroNumero = 7.5; // Erro
int outroNumero = "22"; // Erro

Há algumas linguagens estaticamente tipadas que oferecem inferência de tipo, ou seja, não é necessário explicitamente dizer o tipo da variável, mas uma vez esse tipo sendo definido, ele deverá ser mantido por todo o código. E vale ressaltar também que a tipagem estática se aplica também a parâmetros, retornos de funções, etc.

Essas características do C++, e de outras linguagens com tipagem estática, dá aos desenvolvedores um pouco menos de liberdade. Porém, fornecem uma performance muito superior. Ao saber o tipo de dados que a variável irá receber, o compilador sabe a quantidade de memória a ser alocada, por exemplo. Além disso, há outras vantagens como uma melhor manutenibilidade do código. Pois, de certa, forma as próprias assinaturas dos tipos das variáveis acabam servindo como documentação.

Por outro lado, como sabemos, Python é uma linguagem com Tipagem Dinâmica, ou apenas uma “linguagem dinâmica”. Isso quer dizer que podemos declarar variáveis sem definir o seu tipo, e que uma mesma variável pode assumir tipos diferentes ao longo do código.

meu_numero = 7 # Ok
meu_numero = 7.5 # Ok
meu_numero = "André Lopes" # Ok
meu_nome = 5 > 10 # Ok (booleano False)

Esta flexibilidade nos dá mais liberdade e talvez seja interessante para quem está iniciando na programação, pela sua simplicidade, e também para protótipos de sistemas, onde as coisas podem mudar com uma velocidade impressionante, ou para interagir com outros sistemas que podem mudar sem aviso prévio.

Afinal de contas, qual é melhor?

Como (quase) tudo no mundo da tecnologia, a resposta para essa pergunta é: depende.

“Tipagem estática onde possível, tipagem dinâmica quando necessário.”

Artigo Static Typing Where Possible, Dynamic Typing When Needed: The End of the Cold War Between Programming Languages. Por Erik Meijer e Peter Drayton, Microsoft (2004).
Fonte: https://www.ics.uci.edu/~lopes/teaching/inf212W12/readings/rdl04meijer.pdf

Para lidar com dados, como o nosso caso, o dinamismo do Python é de fato muito importante. Devido a quantidade de dados que lidamos, de diferentes fontes, as quais na maioria esmagadora das vezes não temos controle sobre, a falta de estruturação e padrão nos dados é um fator que pesa muito a favor dos benefícios da tipagem dinâmica.

Porém, essa flexibilidade pode trazer problemas inesperados e muitos, mas muitos mesmo, erros em tempo de execução. Erros esses que se não tratados e não testados, podem levar o nosso modelo (ou aplicação, ou API) a quebrar em produção.

O seguinte simples código irá nos trazer um erro em tempo de execução.

idade = input("Qual a sua idade? ")
print(f"Ano que vem você vai fazer {idade + 1} anos!")

Vamos testar?

Erro em tempo de execução.

Além disso, quando trabalhando em equipe, o dinamismo do Python pode acabar virando confusão e trazer bugs difíceis de se detectar e corrigir. Com tipos bem definidos, podemos ter um código mais autoexplicativo, conciso, mais clean code.

Uma outra vantagem é que a sua IDE vai saber qual o tipo de variável. Assim, vai poder tanto sugerir métodos úteis em formato de dicas, quanto nos comunicar com antecedência possíveis erros que podemos ter em tempo de execução do código.

Mas não vamos perder o foco, vamos voltar ao início dessa discussão. Afinal de contas…

Python (pode ser estaticamente) tipado? Introdução às “Type Hints

A PEP 484 e o Python 3.5 trazem o conceito de Type Hints (ou “dicas de tipos”, em tradução livre), que nos ajudam a trazer diversas vantagens das linguagens estaticamente tipadas para o Python. Vamos ver?

Por exemplo, vamos ver uma simples função. Suponhamos que fazemos uma query em uma base de dados. Pegamos o nome da rua e o número da casa, mas precisamos retornar o endereço completo na forma de texto.

def endereco_completo(rua, numero):
    endereco = rua.title() + ", " + str(numero)
    return endereco

print(endereco_completo("rua sete de setembro", 511))

Vamos ver a saída desse código?

Saída do código acima.

Muito bem! Nossa função funciona bem, e imprime o nome da rua com todas as Primeiras Letras Em Maiúsculo, como deve ser, seguido por uma vírgula, um espaço e o número da casa. Mas vamos supor que estamos escrevendo esse mesmo código do zero no VSCode e… qual será que é o método para deixar as primeiras letras das palavras em maiúsculo? Será que é .title(), ou .to_title(), ou .capitalize() talvez? Meu Deus, não lembro!

Podemos sempre perguntar ao Google, claro. Porém, o próprio VSCode nos traz como dicas os métodos mais comuns para cada um dos seus objetos durante a sua digitação, dicas essas que podem ser acessadas pelo atalho Control + Espaço no Windows, ou Option + Esc no MacOS. Vamos ver que dica o VSCode nos dá?

Sem sugestões.

Que pena! Sem sugestões. 🙁

Iremos introduzir nossas Type Hints nessa função e ver a diferença. Vamos inseri-las por meio de Anotações de Funções (PEP 3107 – Function Annotations), que são uma sintaxe que nos permite adicionar anotações de metadados arbitrários às funções do Python.

Para saber mais sobre as Function Annotations, você pode ver nosso post: Python tipado? “Type Hints” e “Function Annotations”.

O código irá ficar assim agora.

def endereco_completo(rua: str, numero: int):
    endereco = f"{rua.title()}, {str(numero)}"
    return endereco

print(endereco_completo("rua sete de setembro", 511))

Vamos ver o resultado no VSCode agora.

Sugestão dos métodos para o tipo string.

O VSCode traz agora como sugestão todos os métodos disponíveis para objetos/variáveis do tipo string e também as suas docstrings. Muito bom, não é? E não é só isso. Se imagine em um projeto super complexo, com diferentes módulos e pacotes Python, e precisamos saber qual o tipo esperado para uma variável que tem um nome nada sugestivo, tipo foo. Temos que varrer toda a code base para tentar entender qual o tipo de valor esperado e assim evitar um erro em tempo de execução? Não se usarmos as Type Hints! Basta posicionar o mouse sobre o objeto que iremos saber o tipo dele.

Tipo da variável sendo exibida.

Vamos imaginar um outro cenário, onde esquecemos de converter a variável numero, que é um inteiro, para string para podermos concatenar no resultado final. Isso traria aquele mesmo erro lá do início. Porém vamos ver o que acontece no VSCode.

Erro previsto no VSCode.

Agora o VSCode consegue prever o erro e nos alertar, isso antes de o código quebrar em tempo de execução (ou pior, em produção). Ok, essa funcionalidade não é nativa do VSCode, é necessário habilitar a função de Linting no Visual Studio Code. Em conjunto, usamos uma biblioteca chamada mypy, que é um verificador de tipos estáticos para o Python, que atua como um Linter. Iremos falar mais sobre o mypy em breve!

Mas para adiantar um pouco mais sobre o mypy, podemos executar também ele no terminal e fazer com que verifique um determinado arquivo. Vamos rodar sobre esse nosso código de exemplo?

Erro reportado pelo mypy.

Ele nos diz aqui que temos esse erro na linha 2. Incrível, não é? Agora imagine isso para objetos e códigos mais complexos. Ajuda muito!

É importante ressaltar que as Type Hints e os alertas de erros do mypy não nos impedem de executar o nosso código. Ainda que um parâmetro esteja anotado como float, ele poderá receber um valor int e possivelmente isso não causará um erro em tempo de execução. Ou talvez, caso essa nossa função de endereço completo estivesse dentro de uma condicional que não fosse executada, o código rodaria normalmente.

Logo, as Type Hints servem, como o próprio nome já diz, como dicas. Não é porque você anotou que um parâmetro ou variável é do tipo ponto flutuante que ela não pode receber um valor inteiro, ou até mesmo uma string. Ela pode e vai receber esse valor caso o desenvolvedor, ou usuário, passe um valor inteiro.

A Tipagem Gradual é uma metodologia introduzida por Jeremy Siek e Walid Taha em 2006, que consiste em ter partes dos nossos programas com tipagem dinâmica e outras partes com tipagem estática. Vamos abordar a Tipagem Gradual em breve também. Quem quiser se adiantar e dar uma olhada no artigo original, ele pode ser encontrado aqui (Inglês).

Conclusão

Espero que com essa breve introdução a curiosidade de vocês sobre as Type Hints tenha sido atiçada. Espero também que tenha sido possível entender um pouco das vantagens de usá-las.

Se você trabalha em um time grande, com códigos complexos, ou já usa as Type Hints ou provavelmente logo percebeu o quanto são importantes. Porém, se você ainda está apenas estudando e desenvolve seus códigos sozinho, talvez tenha achado que isso tudo é uma complexidade desnecessária. Confie, isso faz uma enorme diferença, ajuda a tornar o seu código reutilizável, fácil de entender, fácil de dar manutenção, enfim, contribui para que o seu código seja um código de qualidade.

Vale a pena começar a praticar desde já. Ter os seus projetos no GitHub com as anotações irá sem dúvidas despertar a admiração em pessoas mais experientes que lerem o seu código. Além disso, irá ajudar muito a entender melhor códigos de outros desenvolvedores e irá te permitir evoluir muito mais rápido no uso de frameworks Python.

Caso queira saber um pouco mais sobre a mypy, pode ver o nosso post Python tipado? “Type Hints” e “Function Annotations”. E para não deixar nenhuma dúvida na hora de usar as Type Hints, visite a Cheat Sheet: “Type Hints” e mypy.

Conheça um pouco mais sobre a nossa comunidade, BRAINS – Brazilian AI Networks

#NoBrains #NoGains 🧠

0 Shares:
2 comentários
Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *

Você também pode gostar