Por que “for i in range(x, y): … “?

Quem aprendeu a programar em uma linguagem diferente de Python, pode achar meio estranha a forma que usamos tradicionalmente para fazer uma iteração sobre um conjunto de números. Em linguagem C, por exemplo, se quisermos realizar  10 repetições de algo, poderíamos fazer:

int i;
for (i = 0; i < 10; i++) {
        // código a ser repetido
}

O código é bastante claro:

Para i, cujo valor inicial é 0 (i = 0), repita a execução do código que está entre { e } enquanto o valor de i for menor que 10 (i < 10), e ao final de cada execução do código entre { e } incremente o valor de i em uma unidade (i++).

Temos três declarações bem explícitas em nosso for:

  1. O que vai ser executado inicialmente, antes de começarmos a execução da repetição em si (setup);
  2. O que vai ser verificado antes de cada repetição, para decidir se o código fará ou não mais uma repetição (condição);
  3. O que vai ser executado ao final de cada uma das repetições que forem executadas.

Em Python, como usamos o for?

for i in range(0, 10):
        # código a ser repetido

E aí? Cadê o valor inicial de i? Cadê a condição? Cadê a instrução que altera o valor de i ao final de cada repetição?

Antes de mais nada, precisamos entender o que faz a função range() isoladamente. Abra um console Python e faça o teste:

>>> range(0, 10)
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>>

Isso mesmo, range(x, y) gera e retorna uma lista de números de x até y, sem incluir o y. Vamos confirmar então:

>>> l = range(0, 10)
>>> type(l)
<type 'list'>

Agora que sabemos que range() gera e retorna uma lista de números, vamos voltar à questão do for. Poderíamos então reescrever o for da seguinte forma:

for i in [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]:
    # código a ser repetido

Esse código poderia ser lido como:

Para cada elemento da lista de números, faça algo (o código a ser repetido).

Assim, em um primeiro momento, o valor de i será o valor do primeiro elemento da lista (0). Então, o código a ser repetido é executado e o valor de i passa a ser o valor do próximo elemento da lista, se houver próximo, caso contrário, encerra a repetição. No caso do exemplo, i passa a ter o valor 1. Então o código a ser repetido é executado e os passos anteriores são repetidos até que não existam mais elementos na lista.

A sequẽncia de passos também poderia ser descrita como:

  1. O valor de i é setado para o valor do primeiro elemento da lista (valor 0).
  2. O código a ser repetido é executado.
  3. O valor de i passa a se o valor do elemento seguinte da lista, se houver um próximo elemento. Se não houver, encerra a execução do for. Se houver, volta ao passo 2, com o valor de i já atualizado.

Tudo parece meio automágico, não? Mas não é. Só podemos fazer isso com as listas porque elas são iteráveis (iterables). Objetos desse tipo retornam um elemento seu de cada vez, permitindo esse mecanismo automático do for. Veja o que o glossário da documentação Python [1] fala sobre Iterable:

iterable

An object capable of returning its members one at a time. Examples of iterables include all sequence types (such as list, str, and tuple) and some non-sequence types like dict and file and objects of any classes you define with an __iter__() or __getitem__() method. Iterables can be used in a for loop and in many other places where a sequence is needed (zip(), map(), …). When an iterable object is passed as an argument to the built-in function iter(), it returns an iterator for the object. This iterator is good for one pass over the set of values. When using iterables, it is usually not necessary to call iter() or deal with iterator objects yourself. The for statement does that automatically for you, creating a temporary unnamed variable to hold the iterator for the duration of the loop. See also iterator, sequence, and generator.

Espero que o “for i in range(x, y):” tenha ficado mais claro, principalmente para aqueles que, assim como eu, aprenderam programação com uma linguagem na qual a estrutura do for é diferente.

[1] http://docs.python.org/glossary.html

Anúncios