Este artigo é a parte 3 de 10 na série Python3

Neste texto, trago uma descrição das estruturas de controle de fluxo de programa, como a instrução if e as sentenças de laço de repetição for e while. Este texto acabou por ser o sexto a ser escrito desta série de Python 3 mas, devido à sua necessidade para uma melhor apresentação das estruturas de dados mais sofisticadas do Python, enriquecendo a experiência, achei conveniente trazê-lo para esta posição.

1. Estruturas de Controle de Fluxo

O Python reconhece as estruturas de controle de fluxo convencionais, mas com algumas pequenas diferenciações. A primeira, e possivelmente a mais chamativa, é o fato de que as sentenças de controle de fluxo no Python não possuem delimitadores de final de bloco.

A limitação de um bloco é feita pelo nível de indentação do código, ou seja, usar dois espaços à frente do primeiro comando na linha seguinte à sentença de controle de fluxo. Esta indentação deverá ser respeitada em todas as linhas seguintes, ou gerará um erro IndentationError. O interpretador entenderá que todos os comandos dentro desta indentação pertencem a sentença de controle de fluxo que a precede.

Na figura acima, a seta amarela indica o bloco de comandos da definição da função order, que inicia no def order e vai até o comando return. A seta vermelha indica o bloco de comandos do primeiro if o qual termina na linha count = count .... A seta azul, o código do if interno, seguido pelo código do while, na seta verde, com apenas duas linhas de comandos.

Além da indentação com delimitador de bloco, o Python ainda faz uso de algumas clausulas especiais para laços de repetição que enriquecem as estruturas de controle.

1.1. Sentença if

A sintaxe da sentença if segue o formato:

if :
    [código]
elif :
    [código]
elif :
    [código]
    ...
else:
    [código]

A indentação fica à escolha do programador. Normalmente, utilizo 4 espaços para uma melhor compreensão do código.
No entanto, como todas as apresentações de código feitas neste texto foram realizadas no prompt interativo do Python, achei mais conveniente utilizar apenas 2 espaços como indentação.

Esta estrutura do if substitui as sentenças tradicionais switch ou case encontradas em outras linguagens e, por isso, estas sentenças não são implementadas no Python. Seguem alguns exemplos:

[xterm color=’true’ py=’true’]
>>> if a >= 1:
… a += 1
… print(a)

14
[/xterm]

Observe que utilizei dois espaços como indentação para o código. Se, por algum motivo, ocorrer uma indentação diferente nos próximos comandos, isto gerará um erro IndentationError, mencionado anteriormente.

[xterm color=’true’ py=’true’]
>>> if a >= 1:
… a += 1
… print(a)
File “<stdin>”, line 3
print(a)
^
IndentationError: unexpected indent
[/xterm]

Se retornar o código à indentação anterior, o interpretador vai entender que você fechou o bloco da sentença, retornando a execução do código na sentença da indentação continuada. Veja o código abaixo:

[xterm color=’true’ py=’true’]
>>> if a >= 1:
… if b > 5:
… print(a + b)
… a += 1
… print(a)

22
16
[/xterm]

No entanto, há um pequeno detalhe sobre o modo interativo do Python: neste modo, é necessário inserir uma linha em branco para fechar a sentença na indentação mais baixa:

[xterm color=’true’ py=’true’]
>>> if a >= 1:
… a += 1
… if b > 5:
File “<stdin>”, line 3
if b > 5:
^
SyntaxError: invalid syntax
[/xterm]

Isto é uma limitação específica da implementação do modo interativo, não ocorrendo em um programa Python. No modo interativo, este código deveria ser passado assim:

[xterm color=’true’ py=’true’]
>>> if a >= 1:
… a += 1

>>> if b > 5:
… b -= a

>>> print(a, b)
17 -10
[/xterm]

1.2. Sentença for

A sentença for no Python difere das equivalentes em outras linguagens tradicionais pois, ao invés de executar um laço de repetição sobre uma progressão aritmética com intervalos controlados, em Python o for executa seu laço de repetição sobre os elementos de um iterável, os quais podem ser sequências como strings, listas, tuplas sets (conjuntos) ou mesmo geradores. Estas sequências são discutidas detalhadamente nos próximos textos. Sua sintaxe é apresentada abaixo:

for  in :
    [código]

Sempre usando indentação como controle de bloco. Para este ponto, entenda listas e tuplas apenas como sequências de objetos quaisquer e conjuntos como o mesmo tipo de sequência anterior, mas sem repetição dos objetos. Sequências são um tanto mais complexas que isto, mas deixarei esta discussão para os próximos textos. Seguem abaixo alguns exemplos:

[xterm color=’true’ py=’true’]
>>> for a in ‘drª Annie J Cannon’:
… print(a)

d
r
ª

A
n
n
i
e

J

C
a
n
n
o
n
[/xterm]

Uma singela homenagem a uma das brilhantes mulheres “calculadoras” do grupo de Pickering. Neste exemplo, foi empregada uma string como o interador.

[xterm color=’true’ py=’true’]
>>> for i in (1, ‘dois’, 3.0, 4j):
… print(i*2)

2
doisdois
6.0
8j
[/xterm]

Aqui, uma tupla com elementos de diferentes tipos de dados: inteiro, string, float e complexo. Agora, para um laço de repetição mais tradicional:

[xterm color=’true’ py=’true’]
>>> for i in range(1, 10, 2):
… print(i)

1
3
5
7
9
[/xterm]

Um laço de repetição sobre os números ímpares de 1 a 10, usando um step de 2, usando o comando range para gerar os índices. Darei uma atenção especial ao comando range posteriormente.

1.3. Sentença while

A sentença while é bem padrão, repetindo a execução do código até que a sua condição seja falsa. Sua sintaxe é apresentada a seguir:

while :
    [código]

Seguem alguns exemplos simples:

[xterm color=’true’ py=’true’]
>>> a = 10
>>> while a > 0:
… a -=2
… print(a)

8
6
4
2
0
[/xterm]

Os pares menores que 10 em ordem regressiva.

[xterm color=’true’ py=’true’]
>>> a, b = 0, 1
>>> while b < 10:
… print(b)
… a, b = b, a + b

1
1
2
3
5
8
[/xterm]

Um código simples e elegante para gerar a série de Fibonacci até 50.

1.4. Sentenças break e continue, e cláusula else em laços de repetição

Os laços de repetição for e while podem ser acrescidos das funcionalidades das sentenças break e continue, além de poderem possuir uma cláusula else.

1.4.1. Break

Assim como na linguagem C, a sentença break faz com que o interpretador saia do laço de repetição mais interno, onde foi chamada. Veja o exemplo a seguir:

[xterm color=’true’ py=’true’]
>>> a, b = 0, 1
>>> while True:
… print(b)
… a, b = b, a + b
… if b > 10:
… break

1
1
2
3
5
8
[/xterm]

Obviamente, a Fibonacci estava melhor como estava antes, mas serve para ilustrar a sentença break.

1.4.2. Continue

Assim como na linguagem C, o continue interrompe a execução do ciclo sem interromper a execução do laço de repetição.

[xterm color=’true’ py=’true’]
>>> i = 0
>>> while(i < 10):
… i += 1
… if i % 2 == 0:
… continue
… print(i)

1
3
5
7
9
[/xterm]

No código acima, sempre que o resto da divisão de i por 2 for nulo (pares), o ciclo é interrompido, não executando o print(i). O mesmo poderia ser feito com um for:

[xterm color=’true’ py=’true’]
>>> for i in range(1, 10):
… if i % 2 == 0:
… continue
… print(i)

1
3
5
7
9
[/xterm]

1.4.3. Else

A cláusula else é executada sempre que o laço de repetição termina sem sair por um break. O código abaixo utiliza um else no for interno (o for no identificador j) para imprimir, se o número testado em i for um primo. O teste é feito verificando os restos das divisões de todos os inteiros positivos inferiores a i, pelo comando if.

[xterm color=’true’ py=’true’]
>>> for i in range(2, 100):
… for j in range(2, i):
… if i % j == 0:
… break
… else:
… print(i)

2
3
5
7
11
13
. . .
83
89
97
[/xterm]

2. Funções

Funções são definidas em Python com a palavra chave def, com a sintaxe abaixo:

def :
    [código]
    return 

Caso seja omitido o return <Valor>, a função se torna uma sub-rotina 1. A função abaixo testa se um número passado é primo:

[xterm color=’true’ py=’true’]
>>> def eh_primo(n):
… if n in (1, 2):
… return True
… for i in range(2, n):
… if n % i == 0:
… return False
… return True

>>> eh_primo(12)
False
>>> eh_primo(13)
True
>>> eh_primo(15)
False
>>> eh_primo(17)
True
[/xterm]

2.1. Iniciando os Argumentos da Função

Em alguns casos, pode ser conveniente passar valores padrões para os argumentos da função. Isto é feito apenas iniciando-as da definição. Veja a sintaxe abaixo:

def funcao(var1 = valor1, var2=valor2, ...):
    [código da função]
    return <resultado>

Apenas com ilustração, segue uma função sobre o fatiamento de uma string:

[xterm color=’true’ py=’true’]
>>> def slicing(string, inicio=0, fim=-1, step=1):
… out = “”
… fim = fim if fim > 0 else len(string)
… i = inicio
… while i < fim:
… out += string[i]
… i += step
… return out

[/xterm]

É uma função bem simples, com algumas limitações como não trabalhar com endereçamento reverso e não suportar índices início e fim fora do intervalo de comprimento da string. A construção poderia ser bem mais simples com o uso de um for e uma função range(início, fim, step), mas perderia o objetivo, mascarando os detalhes na função range.

[xterm color=’true’ py=’true’]
>>> nome = ‘Albert Einstein’
>>> slicing(nome, 1, 5, 2)
‘le’
>>> slicing(nome, 1, 5)
‘lber’
>>> slicing(nome, 1)
‘lbert Einstein’
>>> slicing(nome, fim=5)
‘Alber’
>>>
[/xterm]

Na última aplicação da função slicing foi passado o argumento fim=5, fora da ordem definida na função. Isto não é uma exclusividade do Python, mas apenas para salientar o seu suporte.

Como uma última observação, entenda que esta função de fatiamento é meramente ilustrativa. Fatiamento de string é feito diretamente sem a necessidade de qualquer função, o que será mostrado nos próximos textos sobre Estruturas de Dados Sequenciais.

2.2. Quantidade de Argumentos Indefinido

As funções em Python também suportam uma quantidade de argumentos indefinida na entrada. A função abaixo replica a função sum(), apenas somando os argumentos passados.

[xterm color=’true’ py=’true’]
>>> def soma(*num):
… s = 0
… for n in num:
… s += n
… return s

>>> soma(1, 2, 3, 4, 5, 6, 7, 8, 9)
45
[/xterm]

O interpretador passa a sequência de números (1, 2, ..., 9) para a tupla num, os quais são somados no laço de repetição for.

Estas entradas múltiplas também podem ser combinadas com entradas convencionais, como no exemplo abaixo.

[xterm color=’true’ py=’true’]
>>> def tosco(s, *num):
… return (num, s)

>>> tosco(‘Alves’, 1, 2, 3, 4)
((1, 2, 3, 4), ‘Alves’)
>>>
[/xterm]

Embora seja possível alternar a ordem de entrada dos argumentos, como (*num, s = ''), é aconselhável manter o argumento de comprimento indefinido ao final de lista de argumentos da função, tanto para simplificar a alimentação da função como para deixar mais claro a entrada.

2.3. Funções são Objetos

Para compreender um pouco mais do Python, execute os comandos a seguir:

[xterm color=’true’ py=’true’]
>>> type(eh_primo)
<class ‘function’>
>>> dir(eh_primo)
[‘__annotations__’, ‘__call__’, ‘__class__’, ‘__closure__’, ‘__code__’, ‘__defaults__’, ‘__delattr__’, ‘__dict__’, ‘__dir__’, ‘__doc__’, ‘__eq__’, ‘__format__’, ‘__ge__’, ‘__get__’, ‘__getattribute__’, ‘__globals__’, ‘__gt__’, ‘__hash__’, ‘__init__’, ‘__init_subclass__’, ‘__kwdefaults__’, ‘__le__’, ‘__lt__’, ‘__module__’, ‘__name__’, ‘__ne__’, ‘__new__’, ‘__qualname__’, ‘__reduce__’, ‘__reduce_ex__’, ‘__repr__’, ‘__setattr__’, ‘__sizeof__’, ‘__str__’, ‘__subclasshook__’]
[/xterm]

No Python, toda função é um objeto do tipo function que pode ser invocado, Callable Objects, e, por isto, possuem o método __call__(). Como se pode observar, no Python tudo é um objeto, mas isto fica para outro artigo.

3. Considerações

Embora ainda exista muito o que explorar sobre as estruturas de controle e funções, as demais flexões ficam melhor debatidas com mais algum conhecimento da linguagem. Por isto, vou deixar alguns pontos em aberto para explorá-los em outros tópicos adiante. Caso ache conveniente, retorno aos textos iniciais e adiciono mais informações.

Na sequência, vou apresentar mais detalhadamente as estruturas de dados de sequências, explorando um pouco mais os métodos e atributos destes novos objetos.

  1. Embora alguns altores utilizem o termo “método“, preferi empregar o termo “sub-rotina” aqui e deixei o termo “método” para utilizar com classes e objetos, o que aparecerá muito ao longo dos textos, visto que no Python quase tudo acaba na instância de alguma classe, ou seja, em um objeto.