Iteradores e listas

1. Introdução

No Módulo 2 do curso, você aprendeu especialmente sobre as variáveis string, com operações simples, realizadas dentro do console. Neste módulo, passaremos ao espaço em que você efetivamente desenvolverá seus programas: o Editor.

Somente nesse espaço é que você conseguirá criar algoritmos: sequências de comandos, que devidamente executados, podem oferecer os resultados que você busca por meio desse encadeamento de funções e variáveis.

2. Do Console ao Editor

O Editor é a parte mais importante do Spyder, tanto que ele fica no ponto que mais se destaca ao nosso olhar: o canto superior direito. No primeiro momento, o Spyder apresenta no Editor uma propaganda do Kite, que é uma ferramenta que auxilia o desenvolvimento de softwares.

Trata-se de uma ferramenta interessante, que oferece um auto-completar mais robusto, mas que escapa aos objetivos deste curso (se você tiver interesse, existe nessa tela o link para o help desse aplicativo). Então, nosso primeiro passo será fechar as duas janelas que estão em aberto (temp.py e kite_tutorial.py) e abrir um novo arquivo, para conter o seu programa.

Fechando as duas janelas, o Spyder abre automaticamente um documento novo: untitled.py. Esse é um documento em branco, apenas com uma indicação da autoria e da data de criação (em verde, entre aspas triplas) e um comentário na primeira linha indicando que o encoding padrão é UTF-8.

Encoding indica a forma como os dados são gravados. Quando você grava um arquivo, cada caractere é representado por um código. Um encoding é um conjunto específico desses códigos que designam um caractere específico. Se você grava um arquivo com um encoding, é preciso abri-lo com o mesmo encoding, sob pena de haver leituras erradas.  No nosso caso, devemos usar exatamente o UTF-8, que é o encoding padrão da internet, utilizado inclusive nas páginas dos tribunais brasileiros.

Comentários são trechos de código introduzidos por um #, que indica que essa parte do texto não deve ser executada. Usamos os comentários para o que se chama de documentação, que é a explicação do que faz cada parte do nosso programa, para facilitar a sua compreensão posterior (inclusive por nós mesmos, já que com o tempo nos esquecemos do sentido específico de cada uma das linhas que escrevemos).

Se você quiser, pode alterar esse texto incial dos seus códigos no menu Tools: Prefereces: Editor: Advanced Settings: Edit Template for new files. Isso abrirá o arquivo template.py, que em que você pode definir o que você quer que apareça no início de cada um dos seus programas.

No menu Tools: Preferences: General: Advanced Settings você também pode alterar a linguagem do Spyder para português, se você preferir. Mas vamos continuar usando o inglês, pois a maior parte dos recursos de auxílio à programação está em inglês e, por isso, dominar a terminologia em inglês facilita o seu desenvolvimento posterior.

Agora que você tem o seu Editor aberto, podemos fazer nosso primeiro exercício: retome o ponto 4.4 do texto Funções e Variáveis, em que criamos um mecanismo para extrair o nome do relator de uma string. Como usamos o console, você precisou fazer cada passo. Agora, o desafio é criar uma sequência de passos a serem seguidos de uma vez, para alcançar o resultado. Sempre é possível escrever resolver um problema de várias formas e uma delas é:

string = 'ADI 333, Relator: Marco Aurélio, Resultado: Procedente'
inicio = string.find('Relator: ')+len('Relator: ')
fim = string.find(',',inicio)
print (string[inicio:fim])

Não usaremos mais as capturas de tela do console porque você não tem como copiar os textos a partir das imagens. Usando a caixa de texto de programação, você pode copiar facilmente os textos para o seu Editor, sem ter de digitar tudo novamente.

Se você colar esse pequeno programa no seu Editor, não ocorrerá nada imediatamente. No console, o texto que você colar pode ser executado por meio de um Enter. No Editor, para executar o programa, é preciso dar o comando Run (atalho F5), o que vai fazer com que no seu console apareça o resultado do input do seu programa: o output Marco Aurélio.

Outra grande vantagem do Editor é que, ao contrário do que ocorre no Console, você pode gravar (usando o Save do Spyder) os códigos que você desenvolve, gerando arquivos com a extensão .py. Esses arquivos podem ser depois abertos e executados no ambiente do Spyder, mas também podem ser executados pelo seu sistema operacional.

3. Listas

Agora é hora de inserir um novo tipo de variável, que também usaremos exaustivamentes: as listas. Enquanto as strings são sequências de caracteres, as listas são sequências de objetos.

animais = ['cachorro', 'bem-te-vi', 'jacaré']
numeros = [1, 2, 3, 100, 2165]
listas = [animais, numeros]
tudomisturado = [1, 2, 'cachorro', numeros]

Uma das coisas interessantes do Pythone é que não importa o que você coloca em uma lista. Tudo cabe nelas e cada um desses objetos é identificado pela sua posição, exatamente como nas strings. As únicas peculiaridades das listas são bastante intuitivas:

  1. elas ocorrem sempre entre colchetes. Se você usar parênteses, o que  terá será uma lista imutável (que não pode ter sua composição alterada por funções), que se chama tupla.
  2. os objetos são separados por vírgulas.

Com o que você já sabe de posição nas strings, você pode compreender as expressões abaixo. Caso não entenda, convém voltar ao texto do Módulo 2 e reler o texto sobre posição nas strings).

Não é demais lembrar que a primeira posição é a 0 e não a 1.

Você pode ler elementos de uma lista usando a mesma lógica das strings, com os marcadores de posição. Mas como você pode fazer para ler o último valor de uma lista?

Primeiro, vamos construir uma lista com os números inteiros de 0 a 9, o que podemos fazer aplicando a função list ao comando range(10), que você já conhece.

Para extrair o último elemento da lista, usaremos posições negativas. Até agora, somente trabalhamos com posições positivas, mas também podemos usar posições negativas, baseadas no fato de que o Python trata a última posição como sendo também a primeira posição negativa: -1. Assim, se você quiser somente os dois últimos números de uma lista com 10 números, você pode usar o comando:

lista = list(range(10))
print(lista[-2:])

Outra característica interessante das listas é que elas são concatenáveis, como as strings. Veja o resultado do código:

lista = list(range(10))
print (lista + lista)

Uma vez que você entenda como funciona uma lista, você entenderá facilmente o que é um iterador, pois o iterador que utilizamos (for) é normalmente baseado em listas.

4. Iterador for

O iterador for é uma forma de executar uma função com relação a cada um dos objetos de uma lista. Por exemplo:

for item in animais:
	print (item)

Se você acrescentar essas duas linhas ao seu editor e executar (run), o resultado será:

Portanto, o que o comando anterior realizou foi:

  1. processar a função print uma vez para cada uma das posições contidas na lista animais;
  2. em cada execução da função, atribuir à variável item o valor correspondente ao objeto contido na lista.

Como a lista tem 3 itens, são 3 execuções de print, cada uma imprimindo o valor contido na respectiva posição.

No âmbito do direito, podemos ter uma lista composta pelos numeros das adis a serem buscadas e uma string com o formato geral dos endereços em que eles estão gravados, como já vimos no texto Funções e Variáveis. Se usarmos o iterador for, podemos gerar os endereços que devem ser buscados no STF.

adi = ('333','444', '555', '666')
url = 'http://www.stf.jus.br/portal/peticaoInicial/verPeticaoInicial.asp?base=ADI&documento=&s1=0&numProcesso='

for item in adi:
    print (url + item)

Se você observar com cuidado, verá que o formato geral do for é:

for variável in lista:
   função a ser repetida

Dois detalhes importantes sobre esse formato:

  1. É essencial que a primeira linha seja encerrada por um ':', que indica que depois disso virá a função a ser repetida.
  2. É necessário um marcador para que o Python saiba exatamente qual é a função a ser iterada. Há linguagens que marcam com parênteses ou com chaves essa funções. Em Python não: a única marcação exigida é um recuo, que chamamos tipicamente de indentação (um anglicismo que vem de indentation, palavra inglesa para recuo).

Não importa quantos espaços você coloque antes do print, desde que haja um espaço que o deixe mais à direita que o for. Porém, há um costume entre os desenvolvedores em Python de deixar 4 espaços, que é o recuo padrão, ou usar um símbolo de tabulação.

Parece que dois espaços é pouco, pois pode dar destaque suficiente na leitura, mas isso é só uma questão de legibilidade. Se você colocar 1, 2 ou 10 espaços, seu programa rodará da mesma forma. Porém, uma vez que você definir uma indentação, o Python só vai entender como ligado ao for outras linhas de comando que tenham o mesmo recuo.

Inclusive, se você usar uma indentação de 1 tabulação e outra de 4 espaços, elas não serão entendidas como recuos idênticos. Uma vez que você defina o recuo usado na linha seguinte ao for, ele precisa ser mantido, para que o Python entenda que funções nas linhas seguintes fazem parte do loop (código a ser iterado) estabelecido pelo for.
for item in adi:
    print ('endereço da ADI' + item + ':')
    print (url + item)

Outro detalhe: não importa o nome que você dá à variável iterada. Usamos aqui o nome item, mas podemos usar n, vez, abacate ou qualquer outro nome válido para variáveis (tópico que também estudamos no texto passado). As expressões seguintes vão gerar exatamente o mesmo output do comando anterior.

for n in adi:
    print ('endereço da ADI' + n + ':')
    print (url + n)
    
for vez in adi:
    print ('endereço da ADI' + vez + ':')
    print (url + vez)

Atente a dois erros muito comuns que cometemos ao definir iteradores:

  1. Esquecer os dois pontos. Várias vezes eu esqueço e o resultado é um erro de invalid syntax, pois os ':' são necessários para a devida construção do iterador.
  2. Usar recuos diferentes, o que tipicamente gera como resultado um IndentationError.

Tomados esses cuidados básicos, você conseguirá dominar facilmente esse instrumento muito poderoso de iteração.

Desafio: tente descobrir qual é a interessante coincidência que ocorrerá quando você usa um for iterando a lista:

lista = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
lista = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

for n in lista:
    print (n)

Trata-se de um caso bem particular, em que o valor do objeto contido na lista é idêntico a sua posição. O número 0 ocupa a posição 0, o número 1 ocupa a posição 1 e assim por diante. Por isso, a iteração acima vai gerar um curioso resultado:

Essa é uma  ferramenta importante para nós porque se trata de uma forma simples de gerar uma lista ordenada de números inteiros, que se inicia em 0 (como as posições de sequências em Python).

E se eu quisesse uma lista de 1000 números? Não seria aconselhável escrever uma lista assim, mas você pode gerá-las trocando a sua lista escrita a mão pela expressão range(1000):

for n in range(1000):
    print (n)

Em menos de um segundo, seu computador deve ser capaz de imprimir esses 1000 números na tela. No meu, ele demorou algo em torno de 2 segundos para produzir uma sequência de 10.000 números.

Desafio: agora que você consegue produzir listas quase infinitas de números, você pode fazer algo muito útil para os nossos extratores: gerar listas com os endereços de todas as ADIs em um determinado intervalo: entre 5000 e 6000, por exemplo.
for n in range(1001):
    print ('ADI'+str(5000+n))

Repare neste código dois detalhes dos quais já havíamos falado antes:

  1. O intervalo entre a ação 5000 e a 6000 tem 1001 objetos;
  2. Só podemos concatenar strings com outras strings, nunca strings com números. Por isso, como você já vez na Atividade 1, é preciso converter a variável numérica n em uma string, o que se consegue pelo comando str(n). No caso, str(5000+n) porque 5.000 é o número inicial de nossa sequência.

A esta altura, você já deve ter imaginado que o problema que colocaremos no final desta unidade seja produzir a lista das urls que deverão ser buscadas para podermos colher as informações sobre esses processos. E você imaginou bem.

4.1 Combinando listas e iteradores

No último código, você aprendeu a gerar uma sequência de nomes de ADIs. Mas como é possível armazená-las em uma lista?

Basta usar, no lugar do print (que envia para a tela) o comando nomedalista.append, que armazena os dados na última posição de uma lista anteriormente definida.

Esse anteriormente definida é importante porque, antes de acrescentar elementos a uma lista, ela precisa ser criada, mesmo que esteja em branco, como ocorre no seguinte caso:

adi = []
for n in range(1001):
    adi.append ('ADI'+str(5000+n))
    
print (adi)

Com esse código, você consegue gerar uma lista com os nomes de todas as ADIs de 5000 a 6000. Esse é um tipo muito importante de construção porque nós o usaremos depois de extrairmos os dados de um processo, pois é com um comando derivado dessa construção que poderemos gravar os dados de cada processo em uma lista que segue uma ordem bem definida.

Quando construirmos nossos geradores de bancos de dados, você aprenderá a  'empilhar' essas listas, visto que uma 'pilha' de listas bem organizadas tem a mesma estrutura de uma tabela. Mas a geração dessas tabelas pode esperar um  pouco porque, antes disso, você precisa aprender mais algumas funções.

5. Resumo

Neste texto, você deve ter aprendido:

  1. A criar programas no editor e salvá-los.
  2. Trabalhar com listas, extraindo os valores de certas posições.
  3. Criar loops com o for, executando comandos de forma iterada.
  4. Utilizar o iterador for para gerar sequências de números inteiros.