6. Fluxo de Controle

6.1. Básico

Para um dado arquivo com um programa Python, o interpretador Python começará no topo e depois processará o arquivo. Demonstramos isso com um programa simples. Por exemplo:

def f(x):
    """funcao que computa e retorna x*x"""
    return x * x

print("O Programa principal comeca aqui")
print("4 * 4 = %s" % f(4))
print("Ultima linha do programa -- adeus")
O Programa principal comeca aqui
4 * 4 = 16
Ultima linha do programa -- adeus

A regra básica é que os comandos em um arquivo (ou função ou qualquer sequência de comandos) são processados de cima para baixo. Se vários comandos forem dados na mesma linha (separados por ;), eles serão processados da esquerda para a direita (embora seja desencorajado ter múltiplas declarações por linha a fim de manter boa legibilidade de código.)

Neste exemplo, o interpretador começa no topo (linha 1). Ele encontra a palavra-chave def e lembra para o futuro que a função f está definida aqui. (Ainda não executará o corpo da função, ou seja, a linha 3 - isso só acontece quando chamamos a função). O interpretador pode ver a partir do recuo onde o corpo da função acaba: o recuo na linha 5 é diferente do da primeira linha no corpo da função (linha 2), e assim o corpo da função terminou, e a execução deve continuar com essa linha. (Linhas vazias não são importantes para essa análise).

Na linha 5, o intérprete imprimirá a saída O programa principal comeca aqui. Então, a linha 6 é executada. Esta linha contém a expressão f(4), a qual chamará a função f(x), definida na linha 1, em que x tomará o valor 4. [Atualmente x é uma referência ao objeto 4.] A função f é então executada, retornando 4*4 na linha 3. Este valor 16 é usado na linha 6 para substituir f(4). Por fim, a representação string %s do objeto 16 é impressa como parte do comando de impressão na linha 6. O interpretador então passa para a linha 7 antes de o programa terminar.

Agora vamos aprender sobre diferentes possibilidades para direcionar esse fluxo de controle ainda mais.

6.1.1. Condicionais

Os valores True e False são objetos predefinidos especiais:

a = True
print(a)
True
type(a)
bool
b = False
print(b)
False
type(b)
bool

Podemos operar com esses dois valores lógicos usando a lógica booleana, por exemplo, a lógica e a operação (and):

True and True          # lógica e operação
True
True and False
False
False and True
False
True and True
True
c = a and b
print(c)
False

Há também o ou lógico (or) e a negação (not</ span>):

True or False
True
not True
False
not False
True
True and not False
True

Em códigos computacionais, muitas vezes precisamos avaliar alguma expressão que seja verdadeira ou falsa (às vezes chamada de “predicado”). Por exemplo:

x = 30          # atribui 30 a x
x > 15          # x é maior do que 15?
True
x > 42
False
x == 30         # x é igual a 30?
True
x == 42
False
not x == 42     # x não é o mesmo que 42?
True
x != 42         # x não é o mesmo que 42?
True
x > 30          # x é maior do que 30?
False
x >= 30         # x é maior do que ou igual a 30?
True

6.2. Se-então-senão

6.2.1. Informação adicional

A declaração if permite execução condicional de código. Por exemplo:

a = 34
if a > 0:
    print("a é positivo")
a é positivo

A declaração if também pode ter uma ramificação else que é executada se a condição estiver errada:

a = 34
if a > 0:
    print("a é positivo")
else:
    print("a é nao-positivo (i.e. negativo ou zero)")
a é positivo

Finalmente, existe a palavra-chave elif (leia como “else if”) que permite verificar várias possibilidades (exclusivas):

a = 17
if a == 0:
    print("a é zero")
elif a < 0:
    print("a é negativo")
else:
    print("a é positivo")
a é positivo

6.3. Laço for

6.3.1. Informação adicional

O laço for permite-nos iterar sobre uma sequencia (isto poderia ser uma string ou lista, por exemplo). Aqui está um exemplo:

for animal in ['cão','gato','rato']:
    print(animal, animal.upper())
cão CÃO
gato GATO
rato RATO

Juntamente com o comando range(), pode-se iterar sobre inteiros crescentes:

for i in range(5,10):
    print(i)
5
6
7
8
9

6.4. Laço while

A palavra-chave while permite-nos repetir uma operação enquanto uma condição é verdadeira. Suponha que quiséssemos saber por quantos anos teremos que guardar 100 reais em uma poupança para alcançar 200 reais simplesmente por uma taxa de juros de 5% ao ano. Aqui está um programa para computar isso:

montante = 100        # em BRL
taxa = 1.05           # 5% a.a. juros
anos = 0
while montante < 200:  # repita até que 200 seja alcancado
    montante = montante * taxa
    anos = anos + 1
print('Preciso de', anos, 'anos para alcançar', montante, 'reais.')
Preciso de 15 anos para alcançar 207.89281794113688 reais.

Operadores relacionais (comparações) nas declarações if e while


A forma geral de if e while é a mesma: seguindo a palavra-chave if ou while, existe uma condição seguida de dois pontos. Na próxima linha, um novo (e, portanto, indentado!) bloco de comandos começa a ser executado se a condição for True).

Por exemplo, a condição pode ser a igualdade de duas variáveis a1 e a2, expressa como a1 == a2:

a1 = 42
a2 = 42
if a1 == a2:
    print("a1 e a2 são iguais")
a1 e a2 são iguais

Outro exemplo é testar se a1 e a2 não são os mesmos. Para isso, temos duas possibilidades. A opção número 1 usa o operador de desigualdade !=:

if a1 != a2:
    print("a1 e a2 são diferentes")

A opção 2 usa a palavra-chave not à frente da condição:

if not a1 == a2:
    print("a1 e a2 são diferentes")

Comparações para “maior” (>), “menor” (<) e “maior ou igual a” (>=) e “menor ou igual a” (<=) são diretos.

Finalmente, podemos usar os operadores lógicos “and” e “or” para combinar condições:

a = 11
b = -3
if a > 10 and b > 20:
    print("A é maior do que 10 e b é maior do que 20")
if a > 10 or b < -5:
    print("Ou a é maior do que 10, ou "
          "b é menor do que -5, ou ambos.")
Ou a é maior do que 10, ou b é menor do que -5, ou ambos.

Use o prompt do Python para experimentar estas comparações e expressões lógicas. Por exemplo:

T = -12.5
if T < -20:
    print("muito frio")

if T < -10:
    print("bastante frio")
bastante frio
T < -20
False
T < -10
True

6.5. Exceções

Mesmo que uma declaração ou expressão seja sintaticamente correta, ela pode causar um erro quando uma tentativa é feita para executá-la. Os erros detectados durante a execução são chamados exceções e não são necessariamente fatais: exceções podem ser capturadas e tratadas no programa. A maioria das exceções não são tratadas pelos programas, no entanto, e resultam em mensagens de erro como as mostradas aqui:

10 * (1/0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-36-9ce172bd90a7> in <module>()
----> 1 10 * (1/0)

ZeroDivisionError: division by zero
4 + spam*3
---------------------------------------------------------------------------
NameError                                 Traceback (most recent call last)
<ipython-input-37-6b1dfe582d2e> in <module>()
----> 1 4 + spam*3

NameError: name 'spam' is not defined
'2' + 2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-38-4c6dd5170204> in <module>()
----> 1 '2' + 2

TypeError: must be str, not int

Excepção esquemática capturando todas as opções

try:
   # corpo de código
except ArithmeticError:
   # o que fazer se houver erro de aritmética
except IndexError, the_exception:
   # the_exception refere-se à exceção neste bloco
except:
   # o que fazer para qualquer outra exceção
else:  # opcional
   # o que fazer se nenhuma exceção for lançada

try:
   # corpo de código
finally:
   # o que fazer SEMPRE
  File "<ipython-input-39-1f62ec36e0ce>", line 3
    except ArithmeticError:
         ^
IndentationError: expected an indented block

A partir do Python 2.5, você pode usar a instrução with para simplificar a escrita do código para algumas funções predefinidas, em particular a função open para abrir arquivos: veja http://docs.python.org/tutorial/errors.html#predefined-clean-up-actions.

Exemplo: tentaremos abrir um arquivo que não existe e o Python criará uma exceção do tipo IOError, que significa erro de entrada/saída:

f = open("filenamethatdoesnotexist", "r")
---------------------------------------------------------------------------
FileNotFoundError                         Traceback (most recent call last)
<ipython-input-40-11dd75e3491b> in <module>()
----> 1 f = open("filenamethatdoesnotexist", "r")

FileNotFoundError: [Errno 2] No such file or directory: 'filenamethatdoesnotexist'

Se estivéssemos escrevendo um aplicativo com uma interface onde o usuário deve digitar ou selecionar um nome de arquivo, não gostaríamos que o aplicativo parasse se o arquivo não existisse. Em vez disso, precisamos capturar esta exceção e agir para tratá-la (informando, por exemplo, o usuário que um arquivo com tal nome não existe e perguntar se ele quer tentar outro nome de arquivo). Aqui está o esqueleto para capturar esta exceção:

try:
    f = open("arquivo_inexistente","r")
except IOError:
    print("Arquivo não pode ser aberto.")
Arquivo não pode ser aberto.

Há muito mais para ser dito sobre exceções e o uso delas em programas maiores. Comece lendo o Capítulo 8 do Python Tutorial: Erros e Exceções se você tiver interesse.

6.5.1. Lançando Exceções

Possibilidades de lançar uma exceção:

  • raise OverflowError

  • raise OverflowError, Bath is full (estilo antigo, desencorajado)

  • raise OverflowError(Bath is full)

  • e = OverflowError(Bath is full); raise e

6.5.1.1. Hierarquia de exceções

As exceções padrão são organizadas em uma hierarquia de herança, e.g. OverflowError é uma subclasse de ArithmeticError. Isso pode ser visto ao examinarmos help('exceptions'), por exemplo. Você pode derivar suas próprias exceções de qualquer um dos padrões. É um bom estilo que cada módulo defina sua própria exceção de base.

6.5.2. Criando as suas próprias exceções

  • Você pode e deve derivar suas próprias exceções a partir de uma exceção predefinida.

  • Para ver quais exceções predefenidas existem, procure no módulo de exceções (tente help('exceptions')) ou acesse <http://docs.python.org/library/ Exceptions.html # bltin-exceptions>.

6.5.3. LBYL vs EAFP

  • LBYL (Look Before You Leap = Pense duas vezes antes de agir) versus

  • EAFP (Easer to ask forgiveness than permission = Facilidade de pedir perdão do que permissão)

numerador = 7
denominador = 0

Exemplo para LBYL:

if denominador == 0:
    print("Oops...")
else:
    print(numerador/denominador)
Oops...

EAFP:

try:
    print(numerador/denominador)
except ZeroDivisionError:
    print("Oops...")
Oops...

O que a documentação do Python diz sobre EAFP:

Veja http://docs.python.org/glossary.html#term-eafp

O que a documentação do Python diz sobre LBYL:

Veja http://docs.python.org/glossary.html#term-lbyl

EAFP é a maneira “Pythônica”.