Criando indicador de progresso giratório no console (Python)

Uma das grandes vantagens do Python é a facilidade para criar scripts de automatização de tarefas repetitivas. É comum estes scripts possuírem um indicador de progresso  (exemplo: Processando registro n de 1000). O problema disso é que você pode cair no efeito Pacman e ficar colocando . (pontos) para indicar que algo está sendo feito. Isso fica visualmente feio, alem de atrapalhar a visualização das mensagens, caso o processamento seja longo.

Para resolver isso, vou mostrar como fazer um cursor que fica girando, indicando que algo está sendo processado.

Para exemplificar o efeito pacman, segue um gif

Este é o efeito pacman: Você vai acumulando os pontos e isso vai ficando cada vez mais confuso na hora de ler…

 

O objeto deste post é mostrar como criar um cursors que fique girando, exemplo:

 

 

Fica bem mais limpo, certo?

O exemplo é bem simples e vai ser uma função que você vai chamando em um loop e ela se encarrega de atualizar o cursor e a mensagem.

Pode até ser que já exista uma biblioteca/pacote que faça isso, mas desconheço. De toda forma, é bom aprender como este tipo de abordagem funciona. O desenvolvimento desta função utilizará o pacote sys, então não precisamos instalar nada de novo.

Vamos começar pelo “segredo” do processo. No exemplo:

O resultado no console será:

Onde foram parar as outras mensagens (‘Hi’ e ‘There’)? Bom, elas foram exibidas no console, mas foram imediatamente substituídas por causa do caractere especial \r, que é o return carriage, responsável por voltar o cursor para o início da linha.

No exemplo, utilizei a função print com o argumento end=””,  indicando que uma string vazia será adicionada ao final de cada mensagem, ao invés da quebra de linha (que é o padrão da função). Para explicar o código de exemplo:

  1. A mensagem “Hi” foi exibida no console sem quebra de linha;
  2. O cursor retornou para o inicio da linha (\r) e a mensagem “There” foi exibida (também sem quebra de linha);
  3. Novamente, o caractere \r foi utilizado e o cursor retornou para o inicio da linha.
  4. A mensagem “Bacon” foi exibida. (Como foi o último print, não coloquei o end=””, pois não faria diferença)

Bem simples, certo?

 

Para fazer cursor que fica girando, vou assumir o mesmo padrão de mensagens que está no gif: [<cursor>] mensagem.

A primeira coisa que precisamos é da sequencia de caracteres que serão utilizados:

 

Agora, para facilitar a vida, precisamos de uma função que, sempre que acionada, vai retornar a próxima posição do cursor:

Esta função tenta retornar a próxima posição do tuple criado com os caracteres (CURSOR_POSITIONS). Um exception é indicação de que o cursor está na última posição, então a variável CURRENT_CURSOR_POS, que armazena a posição atual do cursor, é definida para zero, retornando a ‘animação’ para o início.

 

O próximo (e último) passo é criar a função que mostra o cursor girando + mensagem:

Explicando o funcionamento dela:

  1. A mensagem que será exibida é formatada, colocando na primeira posição (primeiro {}) o caractere referente ao cursor e na segunda posição, a mensagem;
  2. É feita uma chamada para a função write (stdout.write), informando a mensagem que será exibida. Note que ela começa com um \r, ou seja, antes de exibir a mensagem, o cursor sempre vai retornar para o inicio da linha;
  3. A função flush (stdout.flush) é chamada para forçar o  buffer que guarda as mensagens a exibi-las na tela;

Qual a diferença entre o print e o stdout.write? A grosso modo, o print é um encapsulamento da função stdout.write.

 

Pronto. Você tem um cursor que gira e não precisa mais cair no efeito pacman!

Para fazer o exemplo exibido no gif:

Este exemplo está no meu Github.

 

Espero ter ajudado!

The following two tabs change content below.
Breno RdV
Ex-Psicólogo, com quase uma década de experiência em Recursos Humanos e Gestão de Pessoas, atual desenvolvedor e Analista de Sistemas, trabalhando com PowerBuilder, C#, PowerShell e expandindo horizontes para Python, Xamarin, PHP, Angular e (por que não?) Unity.

Comments

comments

Posted in Dev, Python and tagged , , , , , .