Otimização de códigos Python

Como desenvolvedor Python, você provavelmente sabe bem que o desempenho em seus projetos é fundamental. Mas você já se perguntou quanto tempo está sendo desperdiçado em tarefas simples que podem ser otimizadas? Neste post, exploraremos uma ferramenta poderosa para melhorar o desempenho do Python: o módulo timeit e sua classe Timer. Através deles, você consegue cronometrar a execução de diferentes elementos de seus códigos e identifica gargalos facilmente.
Ao escrevermos códigos Python, é fácil ficarmos presos usando recursos e funcionalidades que podem ser limitantes de desempenho. Por isso, entender como seus códigos são executados auxilia na identificação de gargalos e permite tomadas de decisões baseadas em dados para otimização.
Aprenda a usar timeit
O módulo timeit é uma biblioteca Python integrada (não precisa ser instalada). Ele fornece uma maneira simples de medir o tempo de execução de códigos Python. Consequentemente, ele é perfeito para identificar pontos de gargalo de desempenho em seus códigos. Veja um exemplo de como usá-lo:
import timeit
def minha_func():
# O código que você deseja testar vai aqui
# código de exemplo puramente ilustrativo:
for i in range(1000):
i**2
tempo_execucao = timeit.timeit(minha_func, number=1000)
print(f"Tempo de execução: {tempo_execucao:.6f} segundos")
# resultado: Tempo de execução: 0.158737 segundos
Este código define uma função simples minha_func e usa o método timeit.timeit() para executá-la 1000 vezes. O resultado obtido mostra o tempo médio de execução em segundos.
O método timeit() não se restringe a verificar o tempo de execução de funções, podemos usá-lo para cronometrar qualquer trecho de código. Veja outro exemplo no qual ele verifica o tempo de execução de um for loop definido diretamente nele:
tempo_execucao = timeit.timeit('"-".join(str(n) for n in range(100))', number=10000)
print(f"Tempo de execução: {tempo_execucao:.6f} segundos")
# resultado: Tempo de execução: 0.089020 segundos
A classe Timer
O método timeit() mostrado acima fornece uma maneira rápida de cronometrar a execução do código com uma única chamada de função. No entanto, a classe Timer do módulo timeit possui recursos avançados e bem interessantes. No geral, ela oferece mais flexibilidade, permitindo a criação de objetos reutilizáveis, além de possuir métodos adicionais como repeat(). Com isso, a classe Timer permite verificar o desempenho de um trecho de código através de seu tempo de execução sob várias condições. Veja um exemplo ilustrativo abaixo:
from timeit import Timer
t = Timer('"-".join(str(n) for n in range(100))') # inicia a classe Timer com um trecho que deve ser verificado
tempo_execucao_repetido = t.repeat(repeat=3, number=10000) # verifica tempo de execução com repetição
print(tempo_execucao_repetido)
# resultados: [0.08833921500263386, 0.08780984800250735, 0.09082353499979945]
Neste exemplo, o tempo médio para executar 10000 vezes um for loop foi verificado com 3 repetições.
A classe Timer também permite testar a instanciação de classes e as chamadas de métodos:
Timer('obj.method()', setup='from meu_modulo import MinhaClasse; obj = MinhaClasse()').timeit() # exemplo ilustrativo
Neste trecho, o método setup permite separar comandos de importação do trecho que precisa ser cronometrado. Você pode usar o mesmo procedimento para testar códigos que usam gerenciadores de contexto:
Timer('with open("arquivo.txt", "r") as f: content = f.read()',
setup='import io; open = lambda *args: io.StringIO("meu conteúdo")').timeit()
Com isso, fica fácil medir o tempo de execução de diferentes trechos de códigos e identificar suas contribuições para o desempenho de programas escritos em Python.
Para terminar
O modulo timeit auxilia bastante na identificação de gargalos. Idealmente, ele deve ser parte de um conjunto de estratégias de otimização. Entre elas, lembre-se de usar ferramentas de profiling. Implemente mecanismos de cache como dicionários ou bibliotecas de memoização para evitar cálculos redundantes. Simplifique cálculos complexos e reduza o número de iterações de loops sempre que possível com vetorização.
Veja também:
Concatenações com join() para strings em Python
O que é operador ternário em Python?
F-strings em Strings Multilinhas
Decodificação de strings em Python com decode()
Métodos para Manipular Strings em Python
Módulo Getpass para Prompts de Senhas
Aprenda a comparar textos com Python com Difflib
Módulo textwrap para formatação de textos
Manipulação de arquivos com Python
os.environ: gerenciamento de variáveis de ambiente com Python
Métodos Avançados Do Módulo os
Aprenda a criar documentos do Word com Python
Três dicas simples para escrever códigos Python mais robustos
Encontrou algum erro ou quer fazer uma sugestão? Por favor, entre em contato usando nosso formulário de contatos.