Indentação Python


Tradução de:
How does the compiler parse the indentation?, por Oliver Fromme.

A leitura (parse) é bem definida e muito simples. Basicamente, mudanças no nível de indentação são inseridas como tokens no fluxo de tokens.

O analisador léxico (tokenizador) usa uma pilha para armazenar os níveis de indentação. No começo, a pilha contém apenas o valor 0, que é a posição mais à esquerda. Sempre que um bloco aninhado inicia, o novo nível de indentação é empilhado e um token "INDENT" é inserido no fluxo de tokens que são passados para o parser. Nunca pode haver mais um token "INDENT" de uma vez.

Quando uma linha é encontrada com um nível de indentação menor, os valores são desempilhados até que o valor no topo da pilha seja igual ao novo nível de indentação (se nenhum for encontrado, um erro de sintaxe ocorre). Para cada valor desempilhado, um token "DEDENT" é gerado. Obviamente, pode-se ter múltiplos tokens "DEDENT" seguidos.

No final do código fonte, tokens "DEDENT" são gerados para cada nível de indentação que sobrou na pilha, até que só permaneça o valor 0.

Veja o seguinte trecho de código por exemplo:

>>> if foo:
...     if bar:
...         x = 42
... else:
...   print foo
... 

Na tabela abaixo, você pode ver os tokens produzidos na esquerda, e a pilha de indentação na direita.

<if> <foo> <:>                    [0]
<INDENT> <if> <bar> <:>           [0, 4]
<INDENT> <x> <=> <42>             [0, 4, 8]
<DEDENT> <DEDENT> <else> <:>      [0]
<INDENT> <print> <foo>            [0, 2]
<DEDENT>                          [0]

Note que após a análise léxica (antes de iniciar o parsing), não há espaços em brancos deixados na lista de tokens (exceto possíveis literais string, claro). Em outras palavras, a indentação é gerenciada pelo léxico, não pelo sintático (parser).

O analisador sintático então simplesmente cuida de tokens "INDENT" e "DEDENT" como sendo delimitadores de blocos - exatamente como chaves são manuseadas pelo compilador C.

O exemplo acima é intencionalmente simples. Há mais que isso, como por exemplo linhas continuadas. Elas são bem definidas também, e você pode ler sobre elas no Guia de Referência da Linguagem Python se você estiver interessado, que inclui uma gramática formal completa da linguagem.