Você está na página 1de 205

Aprenda Computao com Python

Documentation
Verso 1.1

Allen Downey, Jeff Elkner and Chris Meyers

12/08/2010
Contedo

1 Prefcio 3
1.1 Como e porque eu vim a usar Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
1.2 Encontrando um livro-texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.3 Introduzindo programao com Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
1.4 Construindo uma comunidade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Apresentao 7

3 Captulo 1: O caminho do programa 9


3.1 1.1 A linguagem de programao Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3.2 1.2 O que um programa? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.3 1.3 O que depurao (debugging)? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
3.4 1.4 Linguagens naturais e linguagens formais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
3.5 1.5 O primeiro programa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
3.6 1.6 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14

4 Captulo 2: Variveis, expresses e comandos 17


4.1 2.1 Valores e tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
4.2 2.2 Variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
4.3 2.3 Nomes de variveis e palavras reservadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
4.4 2.4 Comandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.5 2.5 Avaliando expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
4.6 2.6 Operadores e operandos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
4.7 2.7 Ordem dos operadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.8 2.8 Operaes com strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
4.9 2.9 Composio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
4.10 2.11 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

5 Captulo 3: Funes 25
5.1 3.1 Chamadas de funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
5.2 3.2 Converso entre tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.3 3.3 Coero entre tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
5.4 3.4 Funes matemticas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
5.5 3.5 Composio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28

i
5.6 3.6 Adicionando novas funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
5.7 3.7 Definies e uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
5.8 3.8 Fluxo de execuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.9 3.9 Parmetros e argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.10 3.10 Variveis e parmetros so locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.11 3.11 Diagramas da pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.12 3.12 Funes com resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.13 3.13 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33

6 Captulo 4: Condicionais e recursividade 35


6.1 4.1 O operador mdulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
6.2 4.2 Expresses booleanas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.3 4.3 Operadores lgicos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
6.4 4.4 Execuo condicional . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.5 4.5 Execuo alternativa . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
6.6 4.6 Condicionais encadeados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.7 4.7 Condicionais aninhados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38
6.8 4.8 A instruo return . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.9 4.9 Recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39
6.10 4.10 Diagramas de pilha para funes recursivas . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40
6.11 4.11 Recursividade infinita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.12 4.12 Entrada pelo teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.13 4.13 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42

7 Captulo 5: Funes frutferas 45


7.1 5.1 Valores de retorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45
7.2 5.2 Desenvolvimento de programas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46
7.3 5.3 Composio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48
7.4 5.4 Funes booleanas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.5 5.5 Mais recursividade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
7.6 5.6 Voto de confiana (Leap of faith) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.7 5.7 Mais um exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.8 5.8 Checagem de tipos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.9 5.9 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53

8 Captulo 6: Iterao 55
8.1 6.1 Reatribuies . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
8.2 6.2 O comando while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
8.3 6.3 Tabelas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.4 6.4 Tabelas de duas dimenses (ou bi-dimensionais) . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.5 6.5 Encapsulamento e generalizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59
8.6 6.6 Mais encapsulamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.7 6.7 Variveis locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.8 6.8 Mais generalizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.9 6.9 Funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
8.10 6.10 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63

9 Captulo 7: Strings 65
9.1 7.1 Um tipo de dado composto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65
9.2 7.2 Comprimento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.3 7.3 Travessia e o loop for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66
9.4 7.4 Fatias de strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.5 7.5 Comparao de strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
9.6 7.6 Strings so imutveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
9.7 7.7 Uma funo find (encontrar) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69

ii
9.8 7.8 Iterando e contando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
9.9 7.9 O mdulo string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
9.10 7.10 Classificao de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70
9.11 7.11 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
9.12 7.11 Glossrio2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72

10 Captulo 8: Listas 73
10.1 8.1 Valores da lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73
10.2 8.2 Acessado elementos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
10.3 8.3 Comprimento da lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
10.4 8.4 Membros de uma lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75
10.5 8.5 Listas e laos for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
10.6 8.6 Operaes em listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
10.7 8.7 Fatiamento de listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
10.8 8.8 Listas so mutveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
10.9 8.9 Remoo em lista . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.10 8.10 Ojetos e valores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.11 8.11 Apelidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
10.12 8.12 Clonando listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
10.13 8.13 Lista como parmetro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
10.14 8.14 Lista aninhadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.15 8.15 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.16 8.16 Strings e listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.17 8.17 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
10.18 Outros termos utilizados neste captulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83

11 Captulo 9: Tuplas 85
11.1 9.1 Mutabilidade e tuplas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
11.2 9.2 Atribuies de tupla . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
11.3 9.3 Tuplas como valores de retorno . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86
11.4 9.4 Nmeros aleatrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
11.5 9.5 Lista de nmeros aleatrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
11.6 9.6 Contando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
11.7 9.7 Vrios intervalos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
11.8 9.8 Uma soluo em um s passo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
11.9 9.9 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

12 Captulo 10: Dicionrios 93


12.1 10.1 Operaes dos Dicionrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
12.2 10.2 Mtodos dos Dicionrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 94
12.3 10.3 Aliasing (XXX) e Copiar . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
12.4 10.4 Matrizes Esparsas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
12.5 10.5 Hint XXX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
12.6 10.6 Inteiros Longos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
12.7 10.7 Contando Letras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
12.8 10.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99

13 Captulo 11: Arquivos e excees 101


13.1 Arquivos e excees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
13.2 11.1 Arquivos texto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103
13.3 11.2 Gravando variveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
13.4 11.3 Diretrios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
13.5 11.4 Pickling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
13.6 11.5 Excees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
13.7 11.6 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108

iii
14 Captulo 12: Classes e objetos 109
14.1 12.1 Tipos compostos definidos pelo usurio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
14.2 12.2 Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
14.3 12.3 Instncias como parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
14.4 12.4 O significado de mesmo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
14.5 12.5 Retngulos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112
14.6 12.6 Instancias como valores retornados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
14.7 12.7 Objetos so mutveis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113
14.8 12.8 Copiando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114
14.9 12.9 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 115

15 Captulo 13: Classes e funes 117


15.1 13.1 Horario . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117
15.2 13.2 Funes Puras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118
15.3 13.3 Modificadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
15.4 13.4 O que melhor ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
15.5 13.5 Desenvolvimento Prototipado versus Desenvolvimento Planejamento . . . . . . . . . . . . . . . 120
15.6 13.6 Generalizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
15.7 13.7 Algoritmos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121
15.8 13.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122

16 Captulo 14: Classes e mtodos 123


16.1 14.1 Caractersticas da orientao a objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
16.2 14.2 exibeHora (printTime) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
16.3 14.3 Um outro exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
16.4 14.4 Um exemplo mais complicado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
16.5 14.10 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125

17 Captulo 15: Conjuntos de objetos 127


17.1 15.1 Composio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
17.2 15.2 Objetos Carta . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
17.3 15.3 Atributos de classe e o mtodo __str__ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128
17.4 15.4 Comparando cartas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129
17.5 15.5 Baralhos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
17.6 15.6 Imprimindo o baralho . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130
17.7 15.7 Embaralhando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
17.8 15.8 Removendo e distribuindo cartas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
17.9 15.9 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133

18 Capitulo 16: Herana 135


18.1 16.1 Herana . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 135
18.2 16.2 Uma mo de cartas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
18.3 16.3 Dando as cartas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
18.4 16.4 Exibindo a mao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137
18.5 16.5 A classe JogoDeCartas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
18.6 16.6 Classe MaoDeMico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
18.7 16.7 Classe Mico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 139
18.8 16.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142

19 Captulo 17: Listas encadeadas 143


19.1 17.1 Referncias Embutidas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
19.2 17.2 A classe No (Node) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144
19.3 17.3 Listas como Colees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
19.4 17.4 Listas e Recorrncia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
19.5 17.5 Listas Infinitas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146

iv
19.6 17.6 O Teorema da Ambigidade Fundamental . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
19.7 17.7 Modificando Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
19.8 17.8 Envoltrios e Ajudadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
19.9 17.9 A Classe ListaLigada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
19.10 17.10 Invariantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
19.11 17.11 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150

20 Captulo 18: Pilhas 153


20.1 18.1 Tipos abstratos de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153
20.2 18.2 O TAD Pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
20.3 18.3 Implementando pilhas com listas de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154
20.4 18.4 Empilhando e desempilhando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
20.5 18.5 Usando uma pilha para avaliar expresses ps-fixas . . . . . . . . . . . . . . . . . . . . . . . . 155
20.6 18.6 Anlise sinttica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
20.7 18.7 Avaliando em ps-fixo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156

21 Captulo 19: Filas 159


21.1 19.1 Um TDA Fila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
21.2 19.2 Fila encadeada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
21.3 19.3 Caractersticas de performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 160
21.4 19.4 Fila encadeada aprimorada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
21.5 19.5 Fila por prioridade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
21.6 19.6 A classe Golfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
21.7 19.7 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164

22 Captulo 20: rvores 165


22.1 20.1 Construindo rvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
22.2 20.2 Percorrendo rvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
22.3 20.3 rvores de expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 167
22.4 20.4 Percurso de rvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
22.5 20.5 Construindo uma rvore de expresso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
22.6 20.6 Manipulando erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
22.7 20.7 A rvore dos animais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174
22.8 20.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176

23 Apndice A: Depurao 177


23.1 A.1 Erros de sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
23.2 A.2 Erros de tempo de execuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
23.3 A.3 Erros de semntica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181

24 Apndice B: Criando um novo tipo de dado 185


24.1 B.1 Multiplicao de fraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 186
24.2 B.2 Soma de fraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187
24.3 B.3 Simplificando fraes: O algoritmo de Euclides . . . . . . . . . . . . . . . . . . . . . . . . . . 187
24.4 B.4 Comparando fraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
24.5 B.5 Indo mais alm... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
24.6 B.6 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190

25 Apndice C: Leituras recomendadas 191


25.1 C.1 Recomendaes para leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
25.2 C.2 Sites e livros sobre Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192
25.3 C.3 Livros de cincia da computao recomendados . . . . . . . . . . . . . . . . . . . . . . . . . . 193

26 Apndice D: GNU Free Documentation License 195

v
27 Indices and tables 197

vi
Aprenda Computao com Python Documentation, Verso 1.1

Contents:

Contedo 1
Aprenda Computao com Python Documentation, Verso 1.1

2 Contedo
CAPTULO 1

Prefcio

Por Jeff Elkner


Este livro deve sua existncia colaborao possibilitada pela Internet e pelo movimento do software livre. Seus
trs autores um professor universitrio, um professor secundarista e um programador profissional ainda no se
encontraram pessoalmente, mas temos sido capazes de trabalhar em estreita colaborao e temos sido ajudados por
muitos colegas maravilhosos que tm dedicado seu tempo e energia para ajudar a fazer deste um livro cada vez melhor.
Achamos que este livro um testemunho dos benefcios e possibilidades futuras deste tipo de colaborao, cujo
modelo tem sido posto em prtica por Richard Stallman e pela Free Software Foundation.

1.1 Como e porque eu vim a usar Python

Em 1999, o Exame de Colocao Avanada em Cincia da Computao da Comisso de Faculdades (College Boards
Advanced Placement (AP) Computer Science XXX) foi aplicado em C++ pela primeira vez. Como em muitas escolas
secundrias atravs do pas, a deciso de mudar linguagens teve um impacto direto no currculo de cincia da com-
putao na Yorktown High School em Arlington, Virginia, onde leciono. At ento, Pascal era a linguagem didtica
para nossos cursos de primeiro ano e avanado. Mantendo a prtica corrente de dar aos estudantes dois anos de ex-
posio mesma linguagem, tomamos a deciso de mudar para C++ no curso de primeiro ano para o ano letivo de
1997-98 de modo que estaramos em sincronismo com a mudana da Comisso de Faculdades (College Boards XXX)
em relao ao curso avanado (AP XXX) para o ano seguinte.
Dois anos depois, eu estava convencido que C++ foi uma escolha infeliz para introduzir os alunos em cincia da
computao. Ao mesmo tempo em que certamente uma linguagem de programao muito poderosa, tambm uma
linguagem extremamente difcil de aprender e de ensinar. Eu me encontrava constantemente lutando com a sintaxe
difcil de C++ e as mltiplas maneiras de fazer a mesma coisa, e estava, como resultado, perdendo muitos alunos
desnecessariamente. Convencido de que deveria existir uma linguagem melhor para a nossa classe de primeiro ano,
fui procurar por uma alternativa a C++.
Eu precisava de uma linguagem que pudesse rodar nas mquinas em nosso laboratrio Linux bem como nas platafor-
mas Windows e Macintosh que a maioria dos alunos tinha em casa. Eu precisava que ela fosse gratuita e disponvel
eletronicamente, assim os alunos poderiam utiliz-la em casa independentemente de suas rendas. Eu queria uma
linguagem que fosse utilizada por programadores profissionais, e que tivesse uma comunidade de desenvolvimento
ativa em torno dela. Ela teria que suportar ambas, programao procedural e orientada a objetos. E, mais importante,
deveria ser fcil de aprender e de ensinar. Quando considerei as alternativas tendo em mente aquelas metas, Python
sobressaiu-se como a melhor candidata para a tarefa.

3
Aprenda Computao com Python Documentation, Verso 1.1

Pedi para um dos talentosos estudantes de Yorktown, Matt Ahrens, que experimentasse Python. Em dois meses ele no
s aprendeu a linguagem como tambm escreveu uma aplicao chamada pyTicket que possibilitou nossa equipe
reportar problemas de tecnologia pela Web. Eu sabia que Matt no poderia ter finalizado uma aplicao daquele
porte em perodo to curto em C++, e esta realizao, combinada com a avaliao positiva de Python dada por Matt,
sugeriam que Python era a soluo que eu estava procurando.

1.2 Encontrando um livro-texto

Tendo decidido usar Python em minhas aulas introdutrias de cincia da computao do ano seguinte, o problema
mais urgente era a falta de um livro-texto disponvel.
O contedo livre veio em socorro. Anteriormente naquele ano, Richard Stallman tinha me apresentado a Allen
Downey. Ambos havamos escrito a Richard expressando interesse em desenvolver contedo educacional livre. Allen
j tinha escrito um livro-texto para o primeiro ano de cincia da computao, How to Think Like a Computer Scientist.
Quando li este livro, soube imediatamente que queria utiliz-lo nas minhas aulas. Era o mais claro e proveitoso texto
em cincia da computao que eu tinha visto. Ele enfatizava o processo de reflexo envolvido em programao em
vez de caractersticas de uma linguagem em particular. L-lo fez de mim imediatamente um professor melhor.
O How to Think Like a Computer Scientist era no s um excelente livro, como tambm fora lanado sob uma licena
pblica GNU, o que significava que ele poderia ser usado livremente e modificado para atender as necessidades de seu
usurio. Uma vez que eu havia decidido usar Python, me ocorreu que eu poderia traduzir a verso original do livro de
Allen do Java para a nova linguagem. Apesar de no estar capacitado para escrever eu mesmo um livro-texto, tendo
o livro de Allen para trabalhar, tornou possvel para mim faz-lo, ao mesmo tempo demonstrando que o modelo de
desenvolvimento cooperativo to bem utilizado em software poderia tambm funcionar para contedo educacional.
Trabalhar neste livro pelos ltimos dois anos tem sido recompensador para mim e meus alunos, e eles tiveram um
grande papel neste processo. A partir do momento em que eu podia fazer mudanas instantneas assim que algum
encontrasse um erro ortogrfico ou um trecho difcil, eu os encorajei a procurar por erros no livro, dando a eles pontos
de bonificao cada vez que fizessem uma sugesto que resultasse em uma mudana no texto. Isto teve o duplo
benefcio de encoraj-los a ler o texto mais cuidadosamente e de ter o texto totalmente revisado por seus crticos mais
importantes: alunos utilizando-o para aprender cincia da computao.
Para a segunda metade do livro, sobre programao orientada a objetos, eu sabia que seria preciso algum com uma
maior experincia do que a minha em programao real para faz-lo corretamente. O livro esteve em estado inacabado
por quase um ano at que a comunidade de software livre providenciasse mais uma vez os meios necessrios para sua
concluso.
Eu recebi um e-mail de Chris Meyers mostrando interesse no livro. Chris um programador profissional que comeou
a dar um curso de programao no ano anterior usando Python no Lane Community College em Eugene, Oregon. A
perspectiva de dar aquele curso ligou Chris ao livro, e ele comeou a ajudar o trabalho imediatamente. At o final
do ano letivo ele tinha criado um projeto colaborativo em nosso Website em http://www.ibiblio.org/obp
chamado Python for Fun e estava trabalhando com alguns dos meus alunos mais avanados como um guru (master
teacher XXX), guiando-os alm de onde eu poderia lev-los.

1.3 Introduzindo programao com Python

O processo de traduzir e utilizar How to Think Like a Computer Scientist pelos ltimos dois anos tem confirmado a
convenincia de Python no ensino de alunos iniciantes. Python simplifica tremendamente os programas exemplo e
torna idias importantes de programao mais fceis de ensinar.
O primeiro exemplo do texto ilustra este ponto. o tradicional programa Al mundo, o qual na verso C++ do livro
se parece com isto:

4 Captulo 1. Prefcio
Aprenda Computao com Python Documentation, Verso 1.1

#include <iostream.h>

void main()
{
cout << "Al, mundo." << endl;
}

Na verso Python, ele se transforma em:


print "Al, Mundo!"

Mesmo sendo um exemplo trivial, as vantagens do Python saltam aos olhos. O curso de Cincia da Computao I que
ministro em Yorktown no tem pr-requisitos, assim, muitos dos alunos que veem esse exemplo esto olhando para o
seu primeiro programa. Alguns deles esto indubitavelmente nervosos, por j terem ouvido falar que programao de
computadores difcil de aprender. A verso C++ tem sempre me forado a escolher entre duas opes insatisfatrias:
ou explicar os comandos #include, void main(), {, e } e arriscar confundir ou intimidar alguns dos alunos logo
assim que iniciam, ou dizer a eles No se preocupem com todas estas coisas agora; falaremos sobre elas mais tarde,
e correr o mesmo risco. O objetivo educacional neste ponto do curso introduzir os alunos idia de comando em
programao e v-los escrever seu primeiro programa, deste modo introduzindo-os ao ambiente de programao. O
programa em Python tem exatamente o que necessrio para conseguir isto, e nada mais.
Comparar o texto explicativo do programa em cada verso do livro ilustra ainda mais o que significa para o aluno
iniciante. Existem treze pargrafos de explicao do Al, mundo! na verso C++; na verso Python existem apenas
dois. Mais importante, os onze pargrafos perdidos no se ocupam das idias chave da programao de computa-
dores, mas com a mincia da sintaxe C++. Vejo a mesma coisa acontecendo atravs de todo o livro. Pargrafos
inteiros simplesmente desaparecem da verso Python do texto porque a sintaxe muito mais clara de Python os torna
desnecessrios.
Utilizar uma linguagem de to alto nvel como Python, permite ao professor deixar para falar mais tarde sobre os
nveis mais baixos, prximos mquina, quando os alunos j tero a experincia necessria para ver com mais sentido
os detalhes. Desta maneira podemos pedagogicamente por em primeiro lugar as primeiras coisas. Um dos melhores
exemplos disto a maneira com que Python lida com variveis. Em C++ uma varivel um nome para um lugar que
guarda uma coisa. Variveis tm de ser declaradas com seu tipo pelo menos em parte por que o tamanho do lugar a que
se referem precisa ser predeterminado. Assim, a idia de varivel fica amarrada ao hardware da mquina. O conceito
poderoso e fundamental de varivel j bastante difcil para o aluno iniciante (tanto em cincia da computao quanto
em lgebra). Bytes e endereos no ajudam neste caso. Em Python uma varivel um nome que se refere a uma coisa.
Este um conceito muito mais intuitivo para alunos iniciantes e est muito mais prximo do significado de varivel
que eles aprenderam em seus cursos de matemtica. Eu tive muito menos dificuldade em ensinar variveis este ano do
que tive no passado, e gastei menos tempo ajudando aos alunos com problemas no uso delas.
Um outro exemplo de como Python ajuda no ensino e aprendizagem de programao em sua sintaxe para funo.
Meus alunos tm sempre tido grande dificuldade na compreenso de funes. O problema principal gira em torno da
diferena entre a definio de uma funo e a chamada de uma funo, e a distino relacionada entre um parmetro
e um argumento. Python vem em auxlio com uma sintaxe no apenas curta quanto bela. As definies de funo
comeam com def, ento eu simplesmente digo aos meus alunos Quando voc define uma funo, comece com
def, seguido do nome da funo que voc est definindo; quando voc chama uma funo, simplesmente chame-a
digitando o nome dela. Parmetros ficam nas definies; argumentos vo com as chamadas. No existem tipos de
retorno, tipos de parmetro ou passagem de parmetros por valor ou por referncia no meio do caminho, permitindo-
me ensinar funes em menos da metade do tempo que isto me tomava anteriormente, com uma melhor compreenso.
A utilizao do Python tem melhorado a efetividade de nosso programa em cincia da computao para todos os
estudantes. Eu vejo um nvel geral de sucesso muito mais alto e um nvel mais baixo de frustrao do que experimentei
durante os dois anos em que ensinei C++. Eu avano mais rpido com melhores resultados. Mais alunos deixam o
curso com a habilidade de criar programas significativos e com uma atitude positiva em relao a experincia de
programao que isso traz.

1.3. Introduzindo programao com Python 5


Aprenda Computao com Python Documentation, Verso 1.1

1.4 Construindo uma comunidade

Tenho recebido e-mails de todo o planeta de pessoas utilizando este livro para aprender ou ensinar programao.
Uma comunidade de usurios tem comeado a emergir e muitas pessoas tm contribudo com o projeto enviando seus
materiais para o Website cooperativo em:
http://www.thinkpython.com
Com a publicao do livro em formato impresso, minha expectativa quanto ao crescimento da comunidade de usurios
que ela seja contnua e acelerada. O surgimento desta comunidade de usurios e a possibilidade que sugere de
colaborao semelhante entre educadores tem sido para mim a parte mais excitante do trabalho neste projeto. Tra-
balhando juntos, podemos aumentar a qualidade do material disponvel para o nosso uso e poupar tempo valioso. Eu
convido voc a se juntar a nossa comunidade e espero ouvir algo de voc. Por favor, escreva para os autores em
feedback@thinkpython.com.
Jeffrey Elkner
Yorktown High School
Arlington, Virginia

6 Captulo 1. Prefcio
CAPTULO 2

Apresentao

Por David Beazley


Como educador, pesquisador e autor de livros, regozija-me ver completo este trabalho. Python uma linguagem de
programao divertida e extremamente fcil de usar que tem ganho forte popularidade nestes ltimos poucos anos.
Desenvolvida dez anos atrs por Guido van Rossun, a sintaxe simples do Python e seu sentido geral so grande-
mente derivados do ABC, uma linguagem didtica que foi desenvolvida nos anos 80. Entretanto, Python tambm foi
criado para solucionar problemas reais e tomou emprestado uma grande quantidade de caractersticas de linguagens
de programao como C++, Java, Modula-3 e Scheme. Por causa disso, uma das mais notveis caractersticas do
Python o grande apelo que tem junto a desenvolvedores profissionais de software, cientistas, pesquisadores, artistas
e educadores.
A Despeito deste apelo do Python junto s mais variadas comunidades, voc pode ainda estar pensando ?por que
Python?? ou ?por que ensinar programao com Python??. Responder estas perguntas no uma tarefa fcil ?
especialmente se a opinio pblica est do lado de alternativas mais masoquistas como C++ e Java. Entretanto, eu
acho que a resposta mais direta que programar com Python um bocado divertido e mais produtivo.
Quando ministro cursos de cincias da computao, o que desejo cobrir conceitos importantes alm de tornar a
matria interessante e os alunos participativos. Infelizmente, existe uma tendncia entre os cursos introdutrios de
programao a focar ateno demais em abstraes matemticas, e de frustrao entre os alunos com problemas
enfadonhos e inoportunos relacionados a detalhes de sintaxe em baixo nvel, compilao e a imposio de regras
que aparentemente s um expert pode compreender (enforcement of seemingly arcane rules XXX). Embora alguma
abstrao e formalismo sejam importantes para engenheiros profissionais de software e estudantes que planejam con-
tinuar seus estudos em cincias da computao, escolher tal abordagem em um curso introdutrio faz da cincia da
computao algo entediante. Quando ministro um curso, no desejo uma sala cheia de alunos sem inspirao. Em vez
disso, preferiria muito mais v-los tentando solucionar problemas interessantes explorando idias diferentes, trilhando
caminhos no convencionais, quebrando regras, e aprendendo a partir de seus erros. Fazendo assim, no pretendo
desperdiar metade de um semestre tentando explicar problemas obscuros de sintaxe, mensagens ininteligveis de
compiladores ou as vrias centenas de maneiras pelas quais um programa pode gerar uma falha geral de proteo.
Uma das razes pelas quais eu gosto de Python que ele oferece um equilbrio realmente bom entre o lado prtico e
o lado conceitual. Sendo Python interpretado, os iniciantes podem pegar a linguagem e comear a fazer coisas legais
quase imediatamente sem se perderem em problemas de compilao e ligao (linking XXX). Alm disso, Python vem
com uma grande biblioteca de mdulos que podem ser utilizados para fazer todo tipo de tarefa, desde a programao
para a web at grficos. Com tal enfoque prtico temos uma bela maneira de alcanar o engajamento dos alunos e
permitir que eles finalizem projetos significativos. Entretanto, Python tambm pode servir de excelente embasamento
para a introduo de conceitos importantes em cincia da computao. J que Python suporta plenamente procedi-
mentos (procedures) e classes, os alunos podem ser gradualmente introduzidos a tpicos como abstrao procedural,
estruturas de dados, e programao orientada a objetos ? todos aplicveis em cursos posteriores de Java ou C++.

7
Aprenda Computao com Python Documentation, Verso 1.1

Python ainda toma emprestado certas caractersticas de linguagens de programao funcionais e pode ser usado para
introduzir conceitos cujos detalhes poderiam ser aprofundados em cursos de Scheme e Lisp.
Lendo o prefcio de Jeffrey, fiquei impressionado com seu comentrio de que Python o fez ver um ?maior nvel de
sucesso e um menor nvel de frustrao? o que lhe permitiu ?progredir mais depressa com resultados melhores?.
Embora estes comentrios refiram-se aos seus cursos introdutrios, eu s vezes uso Python exatamente pelas mesmas
razes em cursos avanados de ps-graduao (graduate = pos-graduacao XXX) em cincia da computao na Uni-
versidade de Chicago. Nestes cursos, enfrento constantemente a assustadora tarefa de cobrir muitos tpicos difceis
em um rapidssimo trimestre (quarter XXX) de nove semanas. Embora me seja possvel inflingir um bocado de dor e
sofrimento pelo uso de uma linguagem como C++, tenho percebido muitas vezes que este enfoque contraproducente
? especialmente quando o curso sobre um tpico no relacionado apenas com ?programar?. Acho que usar Python
me permite um melhor foco no tpico em questo, enquanto permite que os alunos completem projetos substanciais
em classe.
Embora Python seja ainda uma linguagem jovem e em evoluo, acredito que tem um futuro brilhante em educao.
Este livro um passo importante nessa direo.
David Beazley
Universidade de Chicago
Autor de Python Essencial Reference

8 Captulo 2. Apresentao
CAPTULO 3

Captulo 1: O caminho do programa

Tpicos
Captulo 1: O caminho do programa
1.1 A linguagem de programao Python
1.2 O que um programa?
1.3 O que depurao (debugging)?
* 1.3.1 Erros de sintaxe
* 1.3.2 Erros em tempo de execuo (runtime errors)
* 1.3.3 Erros de semntica (ou de lgica)
* 1.3.4 Depurao experimental (debugging)
1.4 Linguagens naturais e linguagens formais
1.5 O primeiro programa
1.6 Glossrio

O objetivo deste livro ensinar o leitor a pensar como um cientista da computao. Essa maneira de pensar combina
algumas das melhores caractersticas da matemtica, da engenharia e das cincias naturais. Como os matemticos, os
cientistas da computao usam linguagens formais para representar ideias (especificamente, computaes). Como os
engenheiros, eles projetam coisas, montando sistemas a partir de componentes e avaliando as vantagens e desvanta-
gens de diferentes alternativas. Como os cientistas naturais, eles observam o comportamento de sistemas complexos,
formulam hipteses e testam previses.
A habilidade mais importante de um cientista da computao a soluo de problemas. Soluo de problemas
a habilidade de formular questes, pensar criativamente sobre solues possveis e expressar uma soluo de forma
clara e precisa. Ocorre que aprender a programar uma excelente oportunidade de praticar a habilidade da soluo de
problemas. por isso que este captulo se chama O caminho do programa.
Em certo nvel, voc estar aprendendo a programar, habilidade que til em si mesma. Em outro nvel, voc usar
a programao como um meio para atingir um objetivo. medida que voc for avanando na leitura, esse objetivo
ficar mais claro.

3.1 1.1 A linguagem de programao Python

Python a linguagem de programao que voc vai estudar neste livro. Python um exemplo de linguagem de
programao de alto nvel. Outras linguagens de alto nvel de que voc j pode ter ouvido falar so C++, PHP e Java.

9
Aprenda Computao com Python Documentation, Verso 1.1

Como voc pode deduzir a partir da expresso linguagem de alto nvel, tambm existem as linguagens de baixo
nvel, s vezes chamadas de linguagens de mquina ou linguagem assembly (linguagens de montagem). De
forma simples, o computador s consegue executar programas escritos em linguagens de baixo nvel. Deste modo,
programas escritos em linguagens de alto nvel precisam ser processados antes que possam rodar. Esse processamento
extra toma algum tempo, o que uma pequena desvantagem em relao s linguagens de alto nvel.
Mas as vantagens so enormes. Primeiro, muito mais fcil programar em uma linguagem de alto nvel. mais
rpido escrever programas em uma linguagem de alto nvel; eles so mais curtos e mais fceis de ler, e h maior
probabilidade de esterem corretos. Segundo, as linguagens de alto nvel so portveis, o que significa que podem
rodar em diferentes tipos de computador, com pouca ou nenhuma modificao. Programas em baixo nvel s podem
rodar em um nico tipo de computador e precisam ser re-escritos para rodar em outro tipo.
Devido a essas vantagens, quase todos os programas so escritos em linguagens de alto nvel. As de baixo nvel so
utilizadas somente para umas poucas aplicaes especializadas.
Dois tipos de programas processam linguagens de alto nvel, traduzindo-as em linguagens de baixo nvel: interpreta-
dores e compiladores. O interpretador l um programa escrito em linguagem de alto nvel e o executa, ou seja, faz o
que o programa diz. Ele processa o programa um pouco de cada vez, alternadamente: hora lendo algumas linhas, hora
executando essas linhas e realizando clculos.

O compilador l o programa e o traduz completamente antes que o programa comece a rodar. Neste caso, o programa
escrito em linguagem de alto nvel chamado de cdigo fonte, e o programa traduzido chamado de cdigo objeto
ou executvel. Uma vez que um programa compilado, voc pode execut-lo repetidamente, sem que precise de nova
traduo.

Python considerada uma linguagem interpretada, pois os programas em Python so executados por um interpretador.
Existem duas maneiras de usar o interpretador: no modo de linha de comando e no modo de script. No modo de linha
de comando, voc digita programas em Python e o interpretador mostra o resultado:
$ python
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 1 + 1
2

A primeira linha deste exemplo o comando que inicia o interpretador Python. As trs linhas seguintes so mensagens
do interpretador. A quarta linha comea com >>>, que o sinal usado pelo interpretador para indicar que ele est
pronto. No exemplo anterior, digitamos print 1 + 1 e o interpretador respondeu 2.
Voc tambm pode escrever um programa em um arquivo e usar o interpretador para executar o contedo desse arquivo.

10 Captulo 3. Captulo 1: O caminho do programa


Aprenda Computao com Python Documentation, Verso 1.1

Um arquivo como este chamado de script. Por exemplo, usamos um editor de texto para criar um arquivo chamado
leticia.py com o seguinte contedo:
print 1 + 1

Por conveno, arquivos que contenham programas em Python tm nomes que terminam com .py.
Para executar o programa, temos de dizer ao interpretador o nome do script:
$ python leticia.py
2

Em outros ambientes de desenvolvimento, os detalhes da execuo de programas podem ser diferentes. Alm disso, a
maioria dos programas so mais interessantes do que esse.
A maioria dos exemplos neste livro so executados a partir da linha de comando. Trabalhar com a linha de comando
conveniente no desenvolvimento e testagem de programas, porque voc pode digitar os programas e execut-los
imediatamente. Uma vez que voc tem um programa que funciona, deve guard-lo em um script, de forma a poder
execut-lo ou modific-lo no futuro.

3.2 1.2 O que um programa?

Um programa uma sequncia de instrues que especificam como executar um clculo ou determinada tarefa.
Tal tarefa pode matemtica, como solucionar um sistema de equaes ou encontrar as razes de um polinmio, mas
tambm pode ser simblica, como buscar e substituir uma palavra em um documento ou (estranhamente) compilar um
programa.
Os detalhes so diferentes em diferentes linguagens, mas algumas instrues bsicas aparecem em praticamente todas
as linguagens:
entrar: Pegar dados do teclado, de um arquivo ou de algum outro dispositivo de entrada.
sair: Mostrar dados na tela ou enviar dados para um arquivo ou outro dispositivo de sada.
calcular: Executar operaes matemticas bsicas, como adio e multiplicao.
executar condicionalmente: Checar certas condies e executar a sequncia apropriada de instrues.
repetir: Executar alguma ao repetidamente, normalmente com alguma variao.
Acredite se quiser: isso praticamente tudo. Todos os programas que voc j usou, no importa quo complicados, so
feitos de instrues mais ou menos parecidas com essas. Assim, poderamos definir programao como o processo de
dividir uma tarefa grande e complexa em subtarefas cada vez menores, at que as subtarefas sejam simples o suficiente
para serem executadas com uma dessas instrues bsicas.
Isso pode parecer um pouco vago, mas vamos voltar a esse tpico mais adiante, quando falarmos sobre algoritmos.

3.3 1.3 O que depurao (debugging)?

Programar um processo complicado e, como feito por seres humanos, frequentemente conduz a erros. Por mero
capricho, erros em programas so chamados de bugs e o processo de encontr-los e corrigi-los chamado de depu-
rao (debugging).
Trs tipos de erro podem acontecer em um programa: erros de sintaxe, erros em tempo de execuo (runtime errors)
e erros de semntica (tambm chamados de erros de lgica). Distinguir os trs tipos ajuda a localiz-los mais rpido:

3.2. 1.2 O que um programa? 11


Aprenda Computao com Python Documentation, Verso 1.1

3.3.1 1.3.1 Erros de sintaxe

O interpretador do Python s executa um programa se ele estiver sintaticamente correto; caso contrrio, o processo
falha e retorna uma mensagem de erro. Sintaxe se refere estrutura de um programa e s regras sobre esta estrutura.
Por exemplo, em portugus, uma frase deve comear com uma letra maiscula e terminar com um ponto.
esta frase contm um erro de sintaxe. Assim como esta
Para a maioria dos leitores, uns errinhos de sintaxe no chegam a ser um problema significativo e por isso que
conseguimos ler a poesia moderna de e. e. cummings sem cuspir mensagens de erro. Python no to indulgente.
Se o seu programa tiver um nico erro de sintaxe em algum lugar, o interpretador Python vai exibir uma mensagem
de erro e vai terminar - e o programa no vai rodar. Durante as primeiras semanas da sua carreira como programador,
voc provavelmente perder um bocado de tempo procurando erros de sintaxe. Conforme for ganhando experincia,
entretanto, cometer menos erros e os localizar mais rpido.

3.3.2 1.3.2 Erros em tempo de execuo (runtime errors)

O segundo tipo de erro o erro de runtime, ou erro em tempo de execuo, assim chamado porque s aparece quando
voc roda o programa. Esses erros so tambm conhecidos como excees, porque normalmente indicam que alguma
coisa excepcional (e ruim) aconteceu.
Erros de runtime so raros nos programas simples que voc vai ver nos primeiros captulos - ento, vai demorar um
pouco at voc se deparar com um erro desse tipo.

3.3.3 1.3.3 Erros de semntica (ou de lgica)

O terceiro tipo de erro o erro de semntica (mais comumente chamado erro de lgica). Mesmo que o seu programa
tenha um erro de semntica, ele vai rodar com sucesso, no sentido de que o computador no vai gerar nenhuma
mensagem de erro. S que o programa no vai fazer a coisa certa, vai fazer alguma outra coisa. Especificamente,
aquilo que voc tiver dito para ele fazer (o computador trabalha assim: seguindo ordens).
O problema que o programa que voc escreveu no aquele que voc queria escrever. O significado do programa
(sua semntica ou lgica) est errado. Identificar erros semnticos pode ser complicado, porque requer que voc
trabalhe de trs para frente, olhando a sada do programa e tentando imaginar o que ele est fazendo.

3.3.4 1.3.4 Depurao experimental (debugging)

Uma das habilidades mais importantes que voc vai adquirir a de depurar. Embora possa ser frustrante, depurar
uma das partes intelectualmente mais ricas, desafiadoras e interessantes da programao.
De certa maneira, a depurao como um trabalho de detetive. Voc se depara com pistas, e tem que deduzir os
processos e eventos que levaram aos resultados que aparecem.
Depurar tambm como uma cincia experimental. Uma vez que voc tem uma ideia do que est errado, voc
modifica o seu programa e tenta de novo. Se a sua hiptese estava correta, ento voc consegue prever o resultado da
modificao e fica um passo mais perto de um programa que funciona. Se a sua hiptese estava errada, voc tem que
tentar uma nova. Como Sherlock Holmes mostrou: Quando voc tiver eliminado o impossvel, aquilo que restou,
ainda que improvvel, deve ser a verdade. (Arthur Conan Doyle, O signo dos quatro).
Para algumas pessoas, programao e depurao so a mesma coisa. Ou seja, programar o processo de gradualmente
depurar um programa, at que ele faa o que voc quer. A ideia comear com um programa que faa alguma coisa e
ir fazendo pequenas modificaes, depurando-as conforme avana, de modo que voc tenha sempre um programa que
funciona.

12 Captulo 3. Captulo 1: O caminho do programa


Aprenda Computao com Python Documentation, Verso 1.1

Por exemplo, o Linux um sistema operacional que contm milhares de linhas de cdigo, mas comeou como um
programa simples, que Linus Torvalds usou para explorar o chip Intel 80386. De acordo com Larry Greenfield, Um
dos primeiros projetos de Linus Torvalds foi um programa que deveria alternar entre imprimir AAAA e BBBB. Isso
depois evoluiu at o Linux. (The Linux Users Guide Verso Beta 1)
Captulos posteriores faro mais sugestes sobre depurao e outras prticas de programao.

3.4 1.4 Linguagens naturais e linguagens formais

Linguagens naturais so as linguagens que as pessoas falam, como o portugus, o ingls e o espanhol. Elas no foram
projetadas pelas pessoas (muito embora as pessoas tentem colocar alguma ordem nelas); elas evoluram naturalmente.
Linguagens formais so linguagens que foram projetadas por pessoas, para aplicaes especficas. Por exemplo,
a notao que os matemticos usam uma linguagem formal, que particularmente boa em denotar relaes entre
nmeros e smbolos. Os qumicos usam uma linguagem formal para representar a estrutura qumica das molculas. E,
mais importante:
Linguagens de programao so linguagens formais que foram desenvolvidas para expressar com-
putaes.
As linguagens formais tendem a ter regras estritas quanto sintaxe. Por exemplo, 3 + 3 = 6 uma expresso matemtica
sintaticamente correta, mas 3=+6$ no . H2O um nome qumico sintaticamente correto, mas 2Zz no .
As regras de sintaxe so de dois tipos, um relacionado aos smbolos, outro estrutura. Os smbolos so os elementos
bsicos da linguagem, como as palavras, nmeros, e elementos qumicos. Um dos problemas com 3=+6$ que $ no
um smbolo vlido em linguagem matemtica (pelo menos at onde sabemos). Do mesmo modo, 2Zz invlida
porque no existe nenhum elemento cuja abreviatura seja Zz.
O segundo tipo de erro de sintaxe est relacionado estrutura de uma expresso, quer dizer, ao modo como os sm-
bolos esto arrumados. A expresso 3=+6$ estruturalmente invlida, porque voc no pode colocar um sinal de
mais imediatamente aps um sinal de igual. Do mesmo modo, frmulas moleculares devem ter ndices subscritos
colocados depois do nome do elemento, no antes.
Faa este exerccio: crie o que parea ser uma frase bem estruturada em portugus com smbolos irrecon-
hecveis dentro dela. Depois escreva outra frase com todos os smbolos vlidos, mas com uma estrutura
invlida.
Quando voc l uma frase em portugus ou uma expresso em uma linguagem formal, voc tem de imaginar como
a estrutura da frase (embora, em uma linguagem natural, voc faa isso inconscientemente). Este processo, na
computao, chamado parsing (anlise sinttica).
Por exemplo, quando voc ouve a frase, Caiu a ficha, entende que a ficha o sujeito e caiu o verbo. Uma vez
que voc analisou a frase, consegue entender o seu significado, ou a semntica da frase. Assumindo que voc saiba o
que uma ficha e o que significa cair, voc entender o sentido geral dessa frase.
Muito embora as linguagens formais e as naturais tenham muitas caractersticas em comum (smbolos, estrutura,
sintaxe e semntica), existem muitas diferenas:
ambiguidade: As linguagens naturais esto cheias de ambiguidades, que as pessoas contornam usando pistas con-
textuais e outras informaes. J as linguagens formais so desenvolvidas para serem quase ou totalmente
desprovidas de ambiguidade, o que significa que qualquer expresso tem precisamente s um sentido, indepen-
dentemente do contexto.
redundncia: Para compensar a ambiguidade e reduzir maus entendidos, emprega-se muita redundncia nas lingua-
gens naturais, o que frequentemente as torna prolixas. As linguagens formais so menos redundantes e mais
concisas.

3.4. 1.4 Linguagens naturais e linguagens formais 13


Aprenda Computao com Python Documentation, Verso 1.1

literalidade: As linguagens naturais esto cheias de expresses idiomticas e metforas. Se eu digo Caiu a ficha,
possvel que no exista ficha nenhuma, nem nada que tenha cado. Nas linguagens formais, no h sentido
ambguo.
Pessoas que crescem falando uma linguagem natural, ou seja, todo mundo, muitas vezes tm dificuldade de se acostu-
mar com uma linguagem formal. De certa maneira, a diferena entre linguagens formais e naturais como a diferena
entre poesia e prosa, porm mais acentuada:
poesia: As palavras so usadas pela sua sonoridade, alm de seus sentidos, e o poema como um todo cria um efeito
ou uma reao emocional. A ambiguidade no apenas frequente, mas na maioria das vezes, proposital.
prosa: O sentido literal das palavras mais importante, e a estrutura contribui mais para o significado. A prosa mais
fcil de analisar do que a poesia, mas ainda , muitas vezes, ambgua.
programas: O significado de um programa de computador exato e literal, e pode ser inteiramente entendido pela
anlise de seus smbolos e de sua estrutura.
Aqui vo algumas sugestes para a leitura de programas (e de outras linguagens formais). Primeiro, lembre-se de que
linguagens formais so muito mais densas do que linguagens naturais, por isso, mais demorado l-las. A estrutura
tambm muito importante, logo, geralmente no uma boa ideia ler de cima para baixo, da esquerda para a direita.
Em vez disso, aprenda a analisar o programa na sua cabea, identificando os smbolos e interpretando a estrutura.
Finalmente, os detalhes so importantes. Pequenas coisas, como erros ortogrficos e m pontuao, com as quais voc
pode se safar nas linguagens naturais, podem fazer uma grande diferena em uma linguagem formal.

3.5 1.5 O primeiro programa

Tradicionalmente, o primeiro programa escrito em uma nova linguagem de programao chamado de Al, Mundo!
porque tudo que ele faz apresentar as palavras Al, Mundo!. Em Python, ele assim:
print "Al, Mundo!"

Isso um exemplo de um comando print, que, na realidade, no imprime nada em papel. Ele apresenta o valor na
tela. Neste caso, o resultado so as palavras:
Al, Mundo!

As aspas no programa marcam o comeo e o fim do valor, elas no aparecem no resultado final.
Algumas pessoas julgam a qualidade de uma linguagem de programao pela simplicidade do programa Al,
Mundo!. Por esse padro, Python se sai to bem quanto possvel.

3.6 1.6 Glossrio

algoritmo (algorithm) Processo geral para soluo de uma certa categoria de problema.
anlise sinttica (parse) Examinar um programa e analisar sua estrutura sinttica.
bug Erro em um programa.
cdigo fonte (source code) Um programa em uma linguagem de alto nvel, antes de ter sido compilado.
cdigo objeto (object code) A sada do compilador, depois que ele traduziu o programa.
comando print (print statement) Instruo que leva o interpretador Python a apresentar um valor na tela.
compilar (compile) Traduzir todo um programa escrito em uma linguagem de alto nvel para uma de baixo nvel de
uma s vez, em preparao para uma execuo posterior.

14 Captulo 3. Captulo 1: O caminho do programa


Aprenda Computao com Python Documentation, Verso 1.1

depurao (debugging) O processo de encontrar e remover qualquer um dos trs tipos de erros de programao.
erro de semntica ou lgica (semantic error) Erro em um programa, que o leva a fazer algo diferente do que pre-
tendia o programador.
erro de sintaxe (syntax error) Erro em um programa, que torna impossvel a anlise sinttica (logo, tambm impos-
svel a interpretao).
erro em tempo de execuo (runtime error) Erro que no ocorre at que o programa seja executado, mas que impede
que o programa continue.
exceo (exception) Um outro nome para um erro em tempo de execuo ou erro de runtime.
executvel (executable) Um outro nome para cdigo objeto que est pronto para ser executado.
interpretar (interpret) Executar um programa escrito em uma linguagem de alto nvel, traduzindo-o uma linha de
cada vez.
linguagem de alto nvel (high-level language) Uma linguagem de programao como Python: projetada para ser
fcil para os seres humanos utilizarem.
linguagem de baixo nvel (low-level language) Uma linguagem de programao que concebida para ser fcil para
um computador, tal como a linguagem de mquina ou a linguagem montagem (assembly language)
linguagem formal (formal language) Qualquer linguagem desenvolvida pelas pessoas para propsitos especficos,
tais como, a representao de ideias matemticas ou programas de computadores; todas as linguagens de pro-
gramao so linguagens formais.
linguagem natural (natural language) Qualquer lngua falada pelos seres humanos que tenha evoludo natural-
mente.
portabilidade (portability) Propriedade que um programa tem de rodar em mais de um tipo de computador.
programa (program) Conjunto de instrues que especifica uma computao.
script Um programa guardado em um arquivo (normalmente um que ser interpretado).
semntica (semantics) O significado de um programa.
smbolo (token) Um elemento bsico da estrutura sinttica de um programa, anlogo a uma palavra em uma lin-
guagem natural.
sintaxe (syntax) A estrutura de um programa.
soluo de problemas (problem solving) O processo de formular um problema, encontrar uma soluo e expressar
esta soluo.

3.6. 1.6 Glossrio 15


Aprenda Computao com Python Documentation, Verso 1.1

16 Captulo 3. Captulo 1: O caminho do programa


CAPTULO 4

Captulo 2: Variveis, expresses e


comandos

Tpicos
Captulo 2: Variveis, expresses e comandos
2.1 Valores e tipos
2.2 Variveis
2.3 Nomes de variveis e palavras reservadas
2.4 Comandos
2.5 Avaliando expresses
2.6 Operadores e operandos
2.7 Ordem dos operadores
2.8 Operaes com strings
2.9 Composio
2.11 Glossrio

4.1 2.1 Valores e tipos

O valor (por exemplo, letras e nmeros) uma das coisas fundamentais que um programa manipula. Os valores que
j vimos at agora foram o 2 (como resultado, quando adicionamos 1 + 1) e "Al, Mundo!".
Esses valores pertencem a tipos diferentes: 2 um inteiro, e "Al, Mundo!" uma string, assim chamada porque
string, em ingls, quer dizer sequncia, srie, cadeia (de caracteres), ou neste caso, srie de letras. Voc (e o
interpretador) consegue identificar strings porque elas aparecem entre aspas.
O comando print tambm funciona com inteiros:
>>> print 4
4

Se voc estiver em dvida sobre qual o tipo de um determinado valor, o interpretador pode revelar:
>>> type("Al, Mundo!")
<type string>

17
Aprenda Computao com Python Documentation, Verso 1.1

>>> type(17)
<type int>

Nenhuma surpresa: strings pertencem ao tipo string e inteiros pertencem ao tipo int. Menos obviamente, nmeros
com um ponto decimal pertencem a um tipo chamado float, porque estes nmeros so representados em um formato
chamado ponto flutuante 1 :
>>> type(3.2)
<type float>

O que dizer de valores como "17" e "3.2"? Eles parecem nmeros, mas esto entre aspas, como strings:
>>> type("17")
<type string>
>>> type("3.2")
<type string>

Eles so strings.
Ao digitar um nmero grande, tentador usar pontos entre grupos de trs dgitos, assim: 1.000.000. Isso no funciona
por que Python usa o ponto como separador decimal. Usar a vrgula, como se faz em ingls, resulta numa expresso
vlida, mas no no nmero que queramos representar:
>>> print 1,000,000
1 0 0

No nada do que se esperava! Python interpreta 1,000,000 como uma tupla, algo que veremos no Captulo 9. Por
hora, lembre-se apenas de no colocar vrgulas nos nmeros.

4.2 2.2 Variveis

Uma das caractersticas mais poderosas de uma linguagem de programao a habilidade de manipular variveis.
Uma varivel um nome que se refere a um valor.
O comando de atribuio cria novas variveis e d a elas valores:
>>> mensagem = "E a, Doutor?"
>>> n = 17
>>> pi = 3.14159

Este exemplo faz trs atribuies. A primeira atribui a string "E a, Doutor?" a uma nova varivel chamada
mensagem. A segunda d o valor inteiro 17 a n, e a terceira atribui o nmero de ponto flutuante 3.14159 varivel
chamada pi.
Uma maneira comum de representar variveis no papel escrever o nome delas com uma seta apontando para o
valor da varivel. Esse tipo de figura chamado de diagrama de estado porque mostra em que estado cada varivel
est (pense nisso como o estado de esprito da varivel). O diagrama a seguir mostra o resultado das instrues de
atribuio:
1 N.T.: Observe o uso de ponto no lugar da vrgula para separar a parte inteira da parte fracionria.

18 Captulo 4. Captulo 2: Variveis, expresses e comandos


Aprenda Computao com Python Documentation, Verso 1.1

O comando print tambm funciona com variveis:


>>> print mensagem
E a, Doutor?
>>> print n
17
>>> print pi
3.14159

Em cada um dos casos, o resultado o valor da varivel. Variveis tambm tm tipo. Novamente, podemos perguntar
ao interpretador quais so eles:
>>> type(mensagem)
<type string>
>>> type(n)
<type int>
>>> type(pi)
<type float>

O tipo de uma varivel o tipo do valor ao qual ela se refere.

4.3 2.3 Nomes de variveis e palavras reservadas

Os programadores geralmente escolhem nomes significativos para suas variveis, pois os nomes documentam para o
que a varivel usada.
Nomes de variveis podem ser arbitrariamente longos. Eles podem conter tanto letras quanto nmeros, mas tm de
comear com uma letra. Embora seja vlida a utilizao de letras maisculas, por conveno, no usamos. Se voc o
fizer, lembre-se de que maisculas e minsculas so diferentes. Bruno e bruno so variveis diferentes.
O caractere para sublinhado ( _ ) pode aparecer em um nome. Ele muito utilizado em nomes com mltiplas palavras,
tal como em meu_nome ou preco_do_cha_na_china.
Se voc der a uma varivel um nome invlido, causar um erro de sintaxe:
>>> 76trombones = "grande parada"
SyntaxError: invalid syntax
>>> muito$ = 1000000
SyntaxError: invalid syntax
>>> class = "Ciencias da Computacao 101"
SyntaxError: invalid syntax

76trombones invlida por no comear com uma letra. muito$ invlida por conter um caractere ilegal, o
cifro. Mas o que est errado com class?

4.3. 2.3 Nomes de variveis e palavras reservadas 19


Aprenda Computao com Python Documentation, Verso 1.1

Ocorre que class uma das palavras reservadas em Python. Palavras reservadas definem as regras e a estrutura da
linguagem e no podem ser usadas como nomes de variveis.
Python tem 29 palavras reservadas:
and def exec if not return
assert del finally import or try
break elif for in pass while
class else from is print yield
continue except global lambda raise

Pode ser til ter essa lista mo 2 . Se o interpretador acusar erro sobre um de seus nomes de varivel e voc no
souber o porqu, veja se o nome est na lista.

4.4 2.4 Comandos

Um comando uma instruo que o interpretador Python pode executar. Vimos at agora dois tipos de comandos: de
exibio (print) e de atribuio.
Quando voc digita um comando na linha de comando, o Python o executa e mostra o resultado, se houver um. O
resultado de um comando print a exibio de um valor. Comandos de atribuio no produzem um resultado
visvel.
Um script normalmente contm uma sequncia de comandos. Se houver mais de um comando, os resultados apare-
cero um de cada vez, conforme cada comando seja executado.
Por exemplo, o script:
print 1
x = 2
print 2

produz a sada:
1
2

Lembrando que o comando de atribuio no produz sada.

4.5 2.5 Avaliando expresses

Uma expresso uma combinao de valores, variveis e operadores. Se voc digitar uma expresso na linha de
comando, o interpretador avalia e exibe o resultado:
>>> 1 + 1
2

Embora expresses contenham valores, variveis e operadores, nem toda expresso contm todos estes elementos. Um
valor por si s considerado uma expresso, do mesmo modo que uma varivel:
>>> 17
17
>>> x
2
2 N.T.: esta lista pode ser obtida atravs do prprio interpretador Python, com apenas dois comandos: import keyword; print

keyword.kwlist

20 Captulo 4. Captulo 2: Variveis, expresses e comandos


Aprenda Computao com Python Documentation, Verso 1.1

Avaliar uma expresso no exatamente a mesma coisa que imprimir um valor:


>>> mensagem = "E a, Doutor?"
>>> mensagem
E a, Doutor?
>>> print mensagem
E a, Doutor?

Quando Python exibe o valor de uma expresso, usa o mesmo formato que voc usaria para entrar com o valor. No
caso de strings, isso significa que as aspas so includas 3 . Mas o comando print imprime o valor da expresso, que,
neste caso, o contedo da string.
Num script, uma expresso sozinha um comando vlido, porm sem efeito. O script:
17
3.2
"Al, Mundo!"
1 + 1

no produz qualquer sada. Como voc mudaria o script para exibir os valores destas quatro expresses?

4.6 2.6 Operadores e operandos

Operadores so smbolos especiais que representam computaes como adio e multiplicao. Os valores que o
operador usa so chamados operandos.
Todas as expresses seguintes so vlidas em Python e seus significados so mais ou menos claros:
20+32 hora-1 hora*60+minuto minuto/60 5**2 (5+9)*(15-7)

Em Python, os smbolos +, -, / e o uso de parnteses para agrupamento tm o mesmo significado que em matemtica.
O asterisco (*) o smbolo para multiplicao e ** o smbolo para potenciao.
Quando um nome de varivel aparece no lugar de um operando, ele substitudo pelo valor da varivel, antes da
operao ser executada.
Adio, subtrao, multiplicao e potenciao fazem o que se espera, mas voc pode ficar surpreso com a diviso. A
operao seguinte tem um resultado inesperado:
>>> minuto = 59
>>> minuto/60
0

O valor de minuto 59 e, em aritmtica convencional, 59 dividido por 60 0,98333, no 0. A razo para a discrepncia
que Python est realizando uma diviso inteira.
Quando ambos os operandos so inteiros, o resultado tem de ser tambm um inteiro e, por conveno, a diviso inteira
sempre arredonda para baixo, mesmo em casos como este, em que o inteiro seguinte est muito prximo:
>>> minuto*100/60
98

De novo, o resultado arredondado para baixo, mas agora pelo menos a resposta aproximadamente correta. A
alternativa usar a diviso em ponto flutuante, o que veremos no captulo 3.
3 N.T.: Python aceita aspas simples ou duplas para delimitar strings.

4.6. 2.6 Operadores e operandos 21


Aprenda Computao com Python Documentation, Verso 1.1

4.7 2.7 Ordem dos operadores

Quando mais de um operador aparece em uma expresso, a ordem de avaliao depende das regras de precedncia.
Python segue as mesmas regras de precedncia para seus operadores matemticos que a matemtica. O acrnimo
PEMDAS uma maneira prtica de lembrar a ordem das operaes:
P: Parnteses tm a mais alta precedncia e podem ser usados para forar uma expresso a ser avaliada
na ordem que voc quiser. J que expresses entre parnteses so avaliadas primeiro, 2 * (3-1) 4, e
(1+1)**(5-2) 8. Voc tambm pode usar parnteses para tornar uma expresso mais fcil de ler, como em
(minuto * 100) / 60, ainda que isso no altere o resultado.
E: Exponenciao ou potenciao tem a prxima precedncia mais alta, assim 2**1+1 3 e no 4, e 3*1**3
3 e no 27.
MDAS: Multiplicao e Diviso tm a mesma precedncia, que mais alta do que a da Adio e da Subtrao,
que tambm tm a mesma precedncia. Assim 2*3-1 d 5 em vez de 4, e 2/3-1 -1, no 1 (lembre-se de
que na diviso inteira, 2/3=0).
Operadores com a mesma precedncia so avaliados da esquerda para a direita. Assim, na expresso
minuto*100/60, a multiplicao acontece primeiro, resultando em 5900/60, o que se transforma pro-
duzindo 98. Se as operaes tivessem sido avaliadas da direita para a esquerda, o resultado poderia ter sido
59*1, que 59, que est errado.

4.8 2.8 Operaes com strings

De maneira geral, voc no pode executar operaes matemticas em strings, ainda que as strings se paream com
nmeros. O que segue invlido (assumindo que mensagem do tipo string):
mensagem-1
"Al"/123
mensagem*"Al"
"15"+2

Interessante o operador +, que funciona com strings, embora ele no faa exatamente o que voc poderia esperar.
Para strings, o operador + representa concatenao, que significa juntar os dois operandos ligando-os pelos extremos.
Por exemplo:
fruta = "banana"
assada = " com canela"
print fruta + assada

A sada deste programa banana com canela. O espao antes da palavra com parte da string e necessrio
para produzir o espao entre as strings concatenadas.
O operador * tambm funciona com strings; ele realiza repetio. Por exemplo, "Legal"*3
"LegalLegaLegal". Um dos operadores tem que ser uma string; o outro tem que ser um inteiro.
Por um lado, esta interpretao de + e * faz sentido pela analogia entre adio e multiplicao. Assim como 4*3
equivale a 4+4+4, no de estranhar que "Legal"*3 seja o mesmo que "Legal"+"Legal"+"Legal". Por
outro lado, uma diferena significativa separa concatenao e repetio de adio e multiplicao. Voc saberia men-
cionar uma propriedade da adio e da multiplicao que no ocorre na concatenao e na repetio?

22 Captulo 4. Captulo 2: Variveis, expresses e comandos


Aprenda Computao com Python Documentation, Verso 1.1

4.9 2.9 Composio

At agora, vimos os elementos de um programa (variveis, expresses, e instrues ou comandos) isoladamente, sem
mencionar como combin-los.
Uma das caractersticas mais prticas das linguagens de programao a possibilidade de pegar pequenos blocos e
combin-los numa composio. Por exemplo, ns sabemos como somar nmeros e sabemos como exibi-los; acontece
que podemos fazer as duas coisas ao mesmo tempo:
>>> print 17 + 3
20

Na realidade, a soma tem que acontecer antes da impresso, assim, as aes no esto na realidade acontecendo ao
mesmo tempo. O ponto que qualquer expresso envolvendo nmeros, strings, e variveis pode ser usada dentro de
um comando print. Voc j tinha visto um exemplo disto:
print "Nmero de minutos desde a meia-noite: ", hora*60+minuto

Esta possibilidade pode no parecer muito impressionante agora, mas voc ver outros exemplos em que a composio
torna possvel expressar clculos e tarefas complexas de modo limpo e conciso.
Ateno: Existem limites quanto ao lugar onde voc pode usar certos tipos de expresso. Por exemplo, o lado esquerdo
de um comando de atribuio tem que ser um nome de varivel, e no uma expresso. Assim, o seguinte no vlido:
minuto+1 = hora.

4.10 2.11 Glossrio

atribuio (assignment) Comando que atribui um valor a uma varivel.


avaliar (evaluate) Simplificar uma expresso atravs da realizao de operaes, para produzir um valor nico.
comando (statement) Trecho de cdigo que representa uma instruo ou ao. At agora, os comandos vistos foram
de atribuio e exibio.
comentrio (comment) Informao em um programa dirigida a outros programadores (ou qualquer pessoa que esteja
lendo o cdigo fonte) e que no tem efeito na execuo do programa.
composio (composition) Habilidade de combinar expresses e comandos simples em expresses e comandos com-
postos, de forma a representar operaes complexas de forma concisa.
concatenar (concatenate) Juntar dois operandos lado a lado.
diagrama de estado (state diagram) Representao grfica de um conjunto de variveis e os valores aos quais elas
se referem.
diviso inteira (integer division) Operao que divide um inteiro por outro e resulta em um inteiro. A diviso inteira
resulta no nmero de vezes que o numerador divisvel pelo denominador e descarta qualquer resto.
expresso (expression) Combinao de variveis, operadores e valores, que representa um resultado nico.
operando (operand) Um dos valores sobre o qual o operador opera.
operador (operator) Smbolo especial que representa uma computao simples, como adio, multiplicao ou con-
catenao de strings.
palavra-chave (keyword) Palavra reservada usada pelo compilador/interpretador para analisar o programa; voc no
pode usar palavras-chave como if, def, e while como nomes de variveis.
ponto-flutuante (floating-point) Formato para representar nmeros que possuem partes fracionrias.

4.9. 2.9 Composio 23


Aprenda Computao com Python Documentation, Verso 1.1

regras de precedncia (rules of precedence) O conjunto de regras que governa a ordem em que expresses envol-
vendo mltiplos operadores e operandos so avaliadas.
tipo (type) Um conjunto de valores. O tipo de um valor determina como ele pode ser usado em expresses. At agora,
os tipos vistos so: inteiros (tipo int), nmeros em ponto-flutuante (tipo float) e strings (tipo string).
valor (value) Um nmero ou string (ou outra coisa que ainda vamos conhecer) que pode ser atribuda a uma varivel
ou computada em uma expresso.
varivel (variable) Nome que se refere a um valor.

24 Captulo 4. Captulo 2: Variveis, expresses e comandos


CAPTULO 5

Captulo 3: Funes

Tpicos
Captulo 3: Funes
3.1 Chamadas de funes
3.2 Converso entre tipos
3.3 Coero entre tipos
3.4 Funes matemticas
3.5 Composio
3.6 Adicionando novas funes
3.7 Definies e uso
3.8 Fluxo de execuo
3.9 Parmetros e argumentos
3.10 Variveis e parmetros so locais
3.11 Diagramas da pilha
3.12 Funes com resultados
3.13 Glossrio

5.1 3.1 Chamadas de funes

Voc j viu um exemplo de uma chamada de funo:


>>> type(32)
<type str>

O nome da funo type e ela exibe o tipo de um valor ou varivel. O valor ou varivel, que chamado de
argumento da funo, tem que vir entre parnteses. comum se dizer que uma funo recebe um valor ou mais
valores e retorna um resultado. O resultado chamado de valor de retorno.
Em vez de imprimir um valor de retorno, podemos atribui-lo a uma varivel:
>>> bia = type(32)
>>> print bia
<type str>

25
Aprenda Computao com Python Documentation, Verso 1.1

Como outro exemplo, a funo id recebe um valor ou uma varivel e retorna um inteiro, que atua como um identifi-
cador nico para aquele valor:
>>> id(3)
134882108
>>> bia = 3
>>> bia(beth)
134882108

Todo valor tem um id, que um nmero nico relacionado ao local onde ele est guardado na memria do computador.
O id de uma varivel o id do valor a qual ela se refere.

5.2 3.2 Converso entre tipos

Python prov uma coleo de funes nativas que convertem valores de um tipo em outro. A funo int recebe um
valor e o converte para inteiro, se possvel, ou, se no, reclama:
>>> int(32)
32
>>> int(Al)
ValueError: invalid literal for int() : Al

int tambm pode converter valores em ponto flutuante para inteiro, mas lembre que isso trunca a parte fracionria:
>>> int(3.99999)
3
>>> int(-2.3)
-2

A funo float converte inteiros e strings em nmeros em ponto flutuante:


>>> float(32)
32.0
>>> float(3.14159)
3.14159

Finalmente, a funo str converte para o tipo string:


>>> str(32)
32
>>> str(3.14149)
3.14149

Pode parecer curioso que Python faa distino entre o valor inteiro 1 e o valor em ponto flutuante 1.0. Eles podem
representar o mesmo nmero, mas pertencem a tipos diferentes. A razo que eles so representados de modo
diferente dentro do computador.

5.3 3.3 Coero entre tipos

Agora que podemos converter entre tipos, temos outra maneira de lidar com a diviso inteira. Voltando ao exemplo do
captulo anterior, suponha que queiramos calcular a frao de hora que j passou. A expresso mais bvia, minuto
/ 60, faz aritmtica inteira, assim, o resultado sempre 0, mesmo aos 59 minutos passados da hora.
Uma soluo converter minuto para ponto flutuante e fazer a diviso em ponto flutuante:

26 Captulo 5. Captulo 3: Funes


Aprenda Computao com Python Documentation, Verso 1.1

>>> minuto = 59
>>> float(minuto) / 60
0.983333333333

Opcionalmente, podemos tirar vantagem das regras de converso automtica entre tipos, chamada de coero de
tipos. Para os operadores matemticos, se qualquer operando for um float, o outro automaticamente convertido
para float:
>>> minuto = 59
>>> minuto / 60.0
0.983333333333

Fazendo o denominador um float, foramos o Python a fazer a diviso em ponto flutuante.

5.4 3.4 Funes matemticas

Em matemtica, voc provavelmente j viu funes como seno (sen, sin em ingls) e logaritmo (log), e apren-
deu a resolver expresses como sen(pi/2) e log(1/x). Primeiro voc resolve e expresso entre parnteses (o
argumento). Por exemplo, pi/2 aproximadamente 1,571, e 1/x 0.1 (se x for 10,0).
A voc avalia a funo propriamente dita, seja procurando numa tabela ou realizando vrios clculos. O sen de 1,571
1 e o log de 0,1 -1 (assumindo que log indica o logaritmo na base 10).
Este processo pode ser aplicado repetidamente para avaliar expresses mais complicadas, como
log(1/sen(pi/2)). Primeiro voc avalia o argumento na funo mais interna, depois avalia a funo e
assim por diante.
Python tem um mdulo matemtico que prov a maioria das funes matemticas mais familiares. Um mdulo um
arquivo que contm uma coleo de funes relacionadas agrupadas juntas.
Antes de podermos usar as funes contidas em um mdulo, temos de import-lo:
>>> import math

Para chamar uma das funes, temos que especificar o nome do mdulo e o nome da funo, separados por um ponto.
Esse formato chamado de notao de ponto:
>>> decibel = math.log10(17.0)
>>> angulo = 1.5
>>> altura = math.sin(angulo)

A primeira instruo atribui a decibel o logaritmo de 17 na base 10. Existe tambm uma funo chamada log,
usada para calcular o logaritmo em outra base ou o logaritmo natural de um nmero (base e).
A terceira instruo encontra o seno do valor da varivel angulo. sin e as outras funes trigonomtricas (cos,
tan, etc.) recebem argumentos em radianos. Para converter de graus em radianos, divida por 360 e multiplique por
2*pi. Por exemplo, para encontrar o seno de 45 graus, primeiro calcule o ngulo em radianos e depois ache o seno:
>>> graus = 45
>>> angulo = graus * 2 * math.pi / 360.0
>>> math.sin(angulo)
0.707106781187

A constante pi tambm parte do mdulo math. Se voc sabe geometria, pode checar o resultado anterior
comparando-o com a raiz quadrada de dois dividido por dois:
>>> math.sqrt(2) / 2.0
0.707106781187

5.4. 3.4 Funes matemticas 27


Aprenda Computao com Python Documentation, Verso 1.1

5.5 3.5 Composio

Do mesmo modo como nas funes matemticas, as funes do Python podem ser compostas, o que significa que voc
pode usar uma expresso como parte de outra. Por exemplo, voc pode usar qualquer expresso como um argumento
para uma funo:
>>> x = math.cos(angulo + pi/2)

Esta instruo toma o valor de pi, divide-o por 2, e soma o resultado ao valor de angulo. A soma ento passada
como um argumento para a funo cos.
Voc tambm pode pegar o resultado de uma funo e pass-lo como um argumento para outra:
>>> x = math.exp(math.log(10.0))

Esta instruo encontra o logaritmo natural (base e) de 10 e ento eleva e quela potncia. O resultado atribudo a
x.

5.6 3.6 Adicionando novas funes

At aqui, temos utilizado somente as funes que vm com Python, mas tambm possvel adicionar novas funes.
Criar novas funes para resolver seus prprios problemas uma das coisas mais teis de uma linguagem de progra-
mao de propsito geral.
No contexto de programao, funo uma sequncia nomeada de instrues ou comandos, que realizam uma oper-
ao desejada. Esta operao especificada numa definio de funo. At agora, as funes que usamos neste livro
so pr-definidas e suas definies no foram apresentadas. Isso demonstra que podemos usar funes sem ter que nos
preocupar com os detalhes de suas definies.
A sintaxe para uma definio de funo :
def NOME_DA_FUNCAO( LISTA DE PARAMETROS ) :
COMANDOS

Voc pode usar o nome que quiser para as funes que criar, exceto as palavras reservadas do Python. A lista de
parmetros especifica que informao, se houver alguma, voc tem que fornecer para poder usar a nova funo.
Uma funo pode ter quantos comandos forem necessrios, mas eles precisam ser endentados a partir da margem
esquerda. Nos exemplos deste livro, usaremos uma endentao de dois espaos.
As primeiras funes que vamos mostrar no tero parmetros, ento, a sintaxe ter esta aparncia:
def novaLinha():
print

Esta funo chamada de novaLinha. Os parnteses vazios indicam que ela no tem parmetros. Contm apenas
um nico comando, que gera como sada um caractere de nova linha (isso o que acontece quando voc usa um
comando print sem qualquer argumento).
A sintaxe para a chamada desta nova funo a mesma sintaxe para as funes nativas:
print Primeira Linha.
novaLinha()
print Segunda Linha.

A sada deste programa :

28 Captulo 5. Captulo 3: Funes


Aprenda Computao com Python Documentation, Verso 1.1

Primeira Linha.

Segunda Linha.

Observe o espao extra entre as duas linhas. E se quisssemos mais espao entre as linhas? Poderamos chamar a
mesma funo repetidamente:
print Primeira Linha.
novaLinha()
novaLinha()
novaLinha()
print Segunda Linha.

Ou poderamos escrever uma nova funo chamada tresLinhas, que produzisse trs novas linhas:
def tresLinhas() :
novaLinha()
novaLinha()
novaLinha()

print Primeira Linha.


tresLinhas()
print Segunda Linha.

Esta funo contm trs comandos, todos com recuo de dois espaos a partir da margem esquerda. J que o prximo
comando no est endentado, Python reconhece que ele no faz parte da funo.
Algumas coisas que devem ser observadas sobre este programa:
1. Voc pode chamar o mesmo procedimento repetidamente. Isso muito comum, alm de til.
2. Voc pode ter uma funo chamando outra funo; neste caso tresLinhas chama novaLinha.
Pode no estar claro, at agora, de que vale o esforo de criar novas funes - existem vrias razes, mas este exemplo
demonstra duas delas:
Criar uma nova funo permite que voc coloque nome em um grupo de comandos. As funes podem simpli-
ficar um programa ao ocultar a execuo de uma tarefa complexa por trs de um simples comando cujo nome
pode ser uma palavra em portugus, em vez de algum cdigo misterioso.
Criar uma nova funo pode tornar o programa menor, por eliminar cdigo repetido. Por exemplo, um atalho
para imprimir nove novas linhas consecutivas chamar tresLinhas trs vezes.
Como exerccio, escreva uma funo chamada noveLinhas que use tresLinhas para imprimir
nove linhas em branco. Como voc poderia imprimir vinte e sete novas linhas?

5.7 3.7 Definies e uso

Reunindo os fragmentos de cdigo da Seo 3.6, o programa completo fica assim:


def novaLinha() :
print

def tresLinhas() :
novaLinha()
novaLinha()
novaLinha()

print Primeira Linha.

5.7. 3.7 Definies e uso 29


Aprenda Computao com Python Documentation, Verso 1.1

tresLinhas()
print Segunda Linha.

Esse programa contm duas definies de funes: novaLinha e tresLinhas. Definies de funes so exe-
cutadas como quaisquer outros comandos, mas o efeito criar a nova funo. Os comandos dentro da definio da
funo no so executados at que a funo seja chamada, logo, a definio da funo no gera nenhuma sada.
Como voc j deve ter imaginado, preciso criar uma funo antes de poder execut-la. Em outras palavras, a definio
da funo tem que ser executada antes que ela seja chamada pela primeira vez.
Como exerccio, mova as ltimas trs linhas deste programa para o topo, de modo que a chamada da
funo aparea antes das definies. Rode o programa e veja que mensagem de erro voc ter.
Tambm a ttulo de exerccio, comece com a verso que funciona do programa e mova a definio de
novaLinha para depois da definio de tresLinhas. O que acontece quando voc roda este pro-
grama?

5.8 3.8 Fluxo de execuo

Para assegurar que uma funo esteja definida antes do seu primeiro uso, preciso saber em que ordem os comandos
so executados, ou seja, descobrir qual o fluxo de execuo do programa.
A execuo sempre comea com o primeiro comando do programa. Os comandos so executados um de cada vez,
pela ordem, de cima para baixo.
As definies de funo no alteram o fluxo de execuo do programa, mas lembre-se que comandos dentro da funo
no so executados at a funo ser chamada. Embora no seja comum, voc pode definir uma funo dentro de outra.
Neste caso, a definio mais interna no executada at que a funo mais externa seja chamada.
Chamadas de funo so como um desvio no fluxo de execuo. Em vez de ir para o prximo comando, o fluxo salta
para a primeira linha da funo chamada, executa todos os comandos l e ento volta atrs para retomar de onde havia
deixado.
Parece muito simples, at a hora em que voc lembra que uma funo pode chamar outra. Enquanto estiver no meio
de uma funo, o programa poderia ter de executar os comandos em uma outra funo. Mas enquanto estivesse
executando esta nova funo, o programa poderia ter de executar ainda outra funo!
Felizmente, Python adepto de monitorar a posio onde est, assim, cada vez que uma funo se completa, o
programa retoma de onde tinha parado na funo que a chamou. Quando chega ao fim do programa, ele termina.
Qual a moral dessa histria srdida? Quando voc for ler um programa, no o leia de cima para baixo. Em vez disso,
siga o fluxo de execuo.

5.9 3.9 Parmetros e argumentos

Algumas das funes nativas que voc j usou requerem argumentos, aqueles valores que controlam como a funo
faz seu trabalho. Por exemplo, se voc quer achar o seno de um nmero, voc tem que indicar qual nmero . Deste
modo, sin recebe um valor numrico como um argumento.
Algumas funes recebem mais de um argumento. Por exemplo, pow recebe dois argumentos, a base e o expoente.
Dentro da funo, os valores que lhe so passados so atribudos a variveis chamadas parmetros.
Veja um exemplo de uma funo definida pelo usurio, que recebe um parmetro:
def imprimeDobrado(bruno):
print bruno, bruno

30 Captulo 5. Captulo 3: Funes


Aprenda Computao com Python Documentation, Verso 1.1

Esta funo recebe um nico argumento e o atribui a um parmetro chamado bruno. O valor do parmetro (a essa
altura, no sabemos qual ser) impresso duas vezes, seguido de uma nova linha. Estamos usando bruno para
mostrar que o nome do parmetro deciso sua, mas claro que melhor escolher um nome que seja mais ilustrativo.
A funo imprimeDobrado funciona para qualquer tipo que possa ser impresso:
>>> imprimeDobrado(Spam)
Spam Spam
>>> imprimeDobrado(5)
5 5
>>> imprimeDobrado(3.14159)
3.14159 3.14159

Na primeira chamada da funo, o argumento uma string. Na segunda, um inteiro. Na terceira um float.
As mesmas regras de composio que se aplicam a funes nativas tambm se aplicam s funes definidas pelo
usurio, assim, podemos usar qualquer tipo de expresso como um argumento para imprimeDobrado:
>>> imprimeDobrado(Spam*4)
SpamSpamSpamSpam SpamSpamSpamSpam
>>> imprimeDobrado(math.cos(math.pi))
-1.0 -1.0

Como acontece normalmente, a expresso avaliada antes da execuo da funo, assim imprimeDobrado imprime
SpamSpamSpamSpam SpamSpamSpamSpam em vez de Spam*4 Spam*4.
Como exerccio, escreva um chamada a imprimeDobrado que imprima Spam*4 Spam*4.
Dica: strings podem ser colocadas tanto entre aspas simples quanto duplas e o tipo de aspas que no
for usado para envolver a string pode ser usado dentro da string, como parte dela.
Tambm podemos usar uma varivel como argumento:
>>> miguel = Eric, the half a bee.
>>> imprimeDobrado(miguel)
Eric, the half a bee. Eric, the half a bee.

N.T.: Eric, the half a bee uma msica do grupo humorstico britnico Monty Python. A linguagem Python foi
batizada em homenagem ao grupo e, por isso, os programadores gostam de citar piadas deles em seus exemplos.
Repare numa coisa importante: o nome da varivel que passamos como um argumento (miguel) no tem nada a ver
com o nome do parmetro (bruno). No importa de que modo o valor foi chamado de onde veio (do chamador);
aqui, em imprimeDobrado, chamamos a todo mundo de bruno.

5.10 3.10 Variveis e parmetros so locais

Quando voc cria uma varivel local dentro de uma funo, ela s existe dentro da funo e voc no pode us-la fora
de l. Por exemplo:
def concatDupla(parte1, parte2):
concat = parte1 + parte2
imprimeDobrado(concat)

Esta funo recebe dois argumentos, concatena-os, e ento imprime o resultado duas vezes. Podemos chamar a funo
com duas strings:
>>> canto1 = Pie Jesu domine,
>>> canto2 = dona eis requiem.
>>> concatDupla(canto1, canto2)
Pie Jesu domine, Dona eis requiem. Pie Jesu domine, Dona eis requiem.

5.10. 3.10 Variveis e parmetros so locais 31


Aprenda Computao com Python Documentation, Verso 1.1

Quando a funo concatDupla termina, a varivel concat destruda. Se tentarmos imprimi-la, teremos um erro:
>>> print concat
NameError: concat

Parmetros so sempre locais. Por exemplo, fora da funo imprimeDobrado, no existe nada que se chama
bruno. Se voc tentar utiliz-la, o Python vai reclamar.

5.11 3.11 Diagramas da pilha

Para entender que variveis podem ser usadas aonde, s vezes til desenhar um diagrama da pilha. Como os
diagramas de estado, diagramas da pilha mostram o valor de cada varivel, mas tambm a funo qual cada varivel
pertence.
Cada funo representada por um quadro. Um quadro uma caixa com o nome de uma funo ao lado dela e os
parmetros e variveis da funo dentro dela. O diagrama de pilha para o exemplo anterior tem a seguinte aparncia:

A ordem da pilha mostra o fluxo de execuo. imprimeDobrado foi chamado por concatDupla, e
concatDupla foi chamado por __main__ (principal), que um nome especial para a funo mais no topo. Quando
voc cria uma varivel fora de qualquer funo, ela pertence __main__.
Cada parmetro se refere ao mesmo valor que o seu argumento correspondente. Assim, parte1 tem o mesmo valor
de canto1, parte2 tem o mesmo valor de canto2 e bruno tem o mesmo valor de concat.
Se um erro acontece durante uma chamada de funo, Python imprime o nome da funo, e o nome da funo que a
chamou, e o nome da funo que chamou a que chamou, percorrendo todo o caminho de volta a __main__.
Por exemplo, se tentssemos acessar concat de dentro de imprimeDobrado, teramos um NameError:
Traceback (innermost last):
File "teste.py", line 13, in __main__
concatDupla(canto1, canto2)
File "teste.py", line 5, in concatDupla
imprimeDobrado(concat)
File "teste.py", line 9, in imprimeDobrado

32 Captulo 5. Captulo 3: Funes


Aprenda Computao com Python Documentation, Verso 1.1

print concat
NameError: concat

Esta lista de funes chamada de traceback. Ela mostra em qual arquivo de programa o erro ocorreu, em que linha,
e quais funes estavam sendo executadas naquele momento. Mostra tambm a linha de cdigo que causou o erro.
Note a similaridade entre o traceback e o diagrama da pilha. No coincidncia.

5.12 3.12 Funes com resultados

A essa altura, voc deve ter percebido que algumas das funes que estamos usando, tais como as funes matemticas,
produzem resultados. Outras funes, como novaLinha, executam uma ao, mas no retornam um valor. O que
levanta algumas questes:
1. O que acontece se voc chama uma funo e no faz nada com o resultado (por exemplo, no atribui o resultado
a uma varivel ou o usa como parte de uma expresso maior)?
2. O que acontece se voc usa uma funo que no produz resultado em uma expresso tal como novaLinha()
+ 7?
3. Voc pode escrever funes que produzem resultados, ou est preso a funes como novaLinha e
imprimeDobrado?
A resposta para a terceira questo afirmativa e ns vamos fazer isso no Captulo 5.
A ttulo de exerccio, responda as outras duas questes testando-as. Se tiver dvida sobre o que vlido
ou invlido em Python, tente buscar a resposta perguntando ao interpretador.

5.13 3.13 Glossrio

argumento (argument) Valor fornecido a uma funo quando ela chamada. Este valor atribudo ao parmetro
correspondente na funo.
chamada de funo (function call) Comando que executa uma funo. Consiste do nome da funo seguido de uma
lista de argumentos entre parnteses.
coero de tipo (type coercion) Uma coero de tipo que ocorre automaticamente, de acordo com as regras de coer-
cividade do Python.
converso de tipo (type conversion) Comando explcito que pega um valor de um tipo e devolve o valor correspon-
dente em outro tipo.
definio de funo (function definition) Comando que cria uma nova funo, especificando seu nome, parmetros
e comandos que ela executa.
diagrama da pilha (stack diagram) Representao grfica da pilha de funes, suas variveis e os valores aos quais
elas se referem.
fluxo de execuo (flow of execution) A ordem na qual os comandos so executados durante a execuo do pro-
grama.
frame Retngulo no diagrama da pilha que representa uma chamada de funo. Contm as variveis locais e os
parmetros da funo.
funo (function) Sequncia de comandos nomeada, que realiza alguma tarefa til. As funes podem ou no receber
parmetros e podem ou no retornar valores.
mdulo (module) Arquivo que contm uma coleo de funes e classes relacionadas entre si.

5.12. 3.12 Funes com resultados 33


Aprenda Computao com Python Documentation, Verso 1.1

notao de ponto (dot notation) A sintaxe para chamar uma funo que est em outro mdulo, especificando o nome
do mdulo, seguido por um ponto (.) e o nome da funo.
parmetro (parameter) Nome usado numa funo para referir-se a um valor passado como argumento.
traceback Lista de funes que esto em execuo, impressa quando um erro de execuo ocorre.
valor de retorno (return value) O resultado da funo. Se uma chamada de funo usada como expresso, o valor
de retorno o valor da expresso.
varivel local (local variable) Varivel definida dentro da funo. Uma varivel local s pode ser usada dentro da
funo onde foi definida.

34 Captulo 5. Captulo 3: Funes


CAPTULO 6

Captulo 4: Condicionais e
recursividade

Tpicos
Captulo 4: Condicionais e recursividade
4.1 O operador mdulo
4.2 Expresses booleanas
4.3 Operadores lgicos
4.4 Execuo condicional
4.5 Execuo alternativa
4.6 Condicionais encadeados
4.7 Condicionais aninhados
4.8 A instruo return
4.9 Recursividade
4.10 Diagramas de pilha para funes recursivas
4.11 Recursividade infinita
4.12 Entrada pelo teclado
4.13 Glossrio

6.1 4.1 O operador mdulo

O operador mdulo trabalha com inteiros (e expresses que tm inteiros como resultado) e produz o resto da diviso
do primeiro pelo segundo. Em Python, o operador mdulo um smbolo de porcentagem (%). A sintaxe a mesma
que a de outros operadores:
>>> quociente = 7 / 3
>>> print quociente
2
>>> resto = 7 % 3
>>> print resto
1

Ento, 7 dividido por 3 2 e o resto 1.

35
Aprenda Computao com Python Documentation, Verso 1.1

O operador mdulo se revela surpreendentemente til. Por exemplo, voc pode checar se um nmero divisvel por
outro - se x % y d zero, ento x divisvel por y.
Voc tambm pode extrair o algarismo ou algarismos mais direita de um nmero. Por exemplo, x % 10 resulta o
algarismo mais direita de x (na base 10). Similarmente, x % 100 resulta nos dois dgitos mais direita.

6.2 4.2 Expresses booleanas

Uma expresso booleana uma expresso que verdadeira (True) ou falsa (False). Em Python, uma expresso que
verdadeira tem o valor 1, e uma expresso que falsa tem o valor 0.
O operador == compara dois valores e produz uma expresso booleana:
>>> 5 == 5
True
>>> 5 == 6
False

No primeiro comando, os dois operadores so iguais, ento a expresso avalia como True (verdadeiro); no segundo
comando, 5 no igual a 6, ento temos False (falso).
O operador == um dos operadores de comparao; os outros so:
x != y # x diferente de y
x > y # x maior que y
x < y # x menor que y
x >= y # x maior ou igual a y
x <= y # x menor ou igual a y

Embora esses operadores provavelmente sejam familiares a voc, os smbolos em Python so diferentes dos smbolos
da matemtica. Um erro comum usar um sinal de igual sozinho (=) em vez de um duplo (==). Lembre-se de que =
um operador de atribuio e == um operador de comparao. Tambm no existem coisas como =< ou =>.

6.3 4.3 Operadores lgicos

Existem trs operadores lgicos: and, or, not (e, ou, no). A semntica (significado) destes operadores similar
aos seus significados em ingls (ou portugus). Por exemplo, x > 0 and x < 10 verdadeiro somente se x for
maior que 0 e menor que 10.
n%2 == 0 or n%3 == 0 verdadeiro se qualquer das condies for verdadeira, quer dizer, se o nmero n for
divisvel por 2 ou por 3.
Finalmente, o operador lgico not nega uma expresso booleana, assim, not(x > y) verdadeiro se (x > y)
for falso, quer dizer, se x for menor ou igual a y.
A rigor, os operandos de operadores lgicos deveriam ser expresses booleanas, mas Python no muito rigoroso.
Qualquer nmero diferente de zero interpretado como verdadeiro (True):
>>> x = 5
>>> x and 1
1
>>> y = 0
>>> y and 1
0

Em geral, esse tipo de coisa no considerado de bom estilo. Se voc precisa comparar um valor com zero, deve
faz-lo explicitamente.

36 Captulo 6. Captulo 4: Condicionais e recursividade


Aprenda Computao com Python Documentation, Verso 1.1

6.4 4.4 Execuo condicional

Para poder escrever programas teis, quase sempre precisamos da habilidade de checar condies e mudar o compor-
tamento do programa de acordo com elas. As instrues condicionais nos do essa habilidade. A forma mais simples
a instruo if (se):
if x > 0
print "x positivo"

A expresso booleana depois da instruo if chamada de condio. Se ela verdadeira (true), ento a instruo
endentada executada. Se no, nada acontece.
Assim como outras instrues compostas, a instruo if constituda de um cabealho e de um bloco de instrues:
CABECALHO:
PRIMEIRO COMANDO
...
ULTIMO COMANDO

O cabealho comea com uma nova linha e termina com dois pontos (:). Os comandos ou instrues endentados que
seguem so chamados de bloco. A primeira instruo no endentada marca o fim do bloco. Um bloco de comandos
dentro de um comando composto ou instruo composta chamado de corpo do comando.
No existe limite para o nmero de instrues que podem aparecer no corpo de uma instruo if, mas tem que haver
pelo menos uma. Ocasionalmente, til ter um corpo sem nenhuma instruo (usualmente, como um delimitador de
espao para cdigo que voc ainda no escreveu). Nesse caso, voc pode usar o comando pass, que indica ao Python:
passe por aqui sem fazer nada.

6.5 4.5 Execuo alternativa

Um segundo formato da instruo if a execuo alternativa, na qual existem duas possibilidades e a condio
determina qual delas ser executada. A sintaxe se parece com:
if x % 2 == 0:
print x, " par"
else:
print x, " impar"

Se o resto da diviso de x por 2 for 0, ento sabemos que x par, e o programa exibe a mensagem para esta condio.
Se a condio falsa, o segundo grupo de instrues executado. Desde que a condio deva ser verdadeira (True) ou
falsa (False), precisamente uma das alternativas vai ser executada. As alternativas so chamadas ramos (branches),
porque existem ramificaes no fluxo de execuo.
Por final, se voc precisa checar a paridade de nmeros com frequncia, pode colocar este cdigo dentro de uma
funo:
def imprimeParidade(x):
if x % 2 == 0:
print x, " par"
else:
print x, " impar"

Para qualquer valor de x, imprimeParidade exibe uma mensagem apropriada. Quando voc a chama, pode
fornecer uma expresso de resultado inteiro como um argumento:
>>> imprimeParidade(17)
>>> imprimeParidade(y+1)

6.4. 4.4 Execuo condicional 37


Aprenda Computao com Python Documentation, Verso 1.1

6.6 4.6 Condicionais encadeados

s vezes existem mais de duas possibilidades e precisamos de mais que dois ramos. Uma condicional encadeada
uma maneira de expressar uma operao dessas:
if x < y:
print x, " menor que", y
elif x > y:
print x, " maior que", y
else:
print x, "e", y, "so iguais"

elif uma abreviao de else if (seno se). De novo, precisamente um ramo ser executado. No existe limite
para o nmero de instrues elif, mas se existir uma instruo else ela tem que vir por ltimo:
if escolha == A:
funcaoA()
elif escolha == B:
funcaoB()
elif escolha == C:
funcaoC()
else:
print "Escolha invlida."

Cada condio checada na ordem. Se a primeira falsa, a prxima checada, e assim por diante. Se uma delas
verdadeira, o ramo correspondente executado, e a instruo termina. Mesmo que mais de uma condio seja
verdadeira, apenas o primeiro ramo verdadeiro executa.
Como exerccio, coloque os exemplos acima em funes chamadas comparar(x, y) e
executar(escolha).

6.7 4.7 Condicionais aninhados

Um condicional tambm pode ser aninhado dentro de outra. Poderamos ter escrito o exemplo tricotmico (dividido
em trs) como segue:
if x == y:
print x, "e", y, "so iguais"
else:
if x < y:
print x, " menor que", y
else:
print x, " maior que", y

O condicional mais externo tem dois ramos. O primeiro ramo contm uma nica instruo de sada. O segundo ramo
contm outra instruo if, que por sua vez tem dois ramos. Os dois ramos so ambos instrues de sada, embora
pudessem conter instrues condicionais tambm.
Embora a endentao das instrues torne a estrutura aparente, condicionais aninhados tornam-se difceis de ler rapi-
damente. Em geral, uma boa ideia evitar o aninhamento quando for possvel.
Operadores lgicos frequentemente fornecem uma maneira de simplificar instrues condicionais aninhadas. Por
exemplo, podemos reescrever o cdigo a seguir usando uma nica condicional:
if 0 < x:
if x < 10:
print "x um nmero positivo de um s algarismo."

38 Captulo 6. Captulo 4: Condicionais e recursividade


Aprenda Computao com Python Documentation, Verso 1.1

A instruo print executada somente se a fizermos passar por ambos os condicionais, ento, podemos usar um
operador and:
if 0 < x and x < 10:
print "x um nmero positivo de um s algarismo."

Esses tipos de condies so comuns, assim, Python prov uma sintaxe alternativa que similar notao matemtica:
if 0 < x < 10:
print "x um nmero positivo de um s algarismo."

6.8 4.8 A instruo return

O comando return permite terminar a execuo de uma funo antes que ela alcance seu fim. Uma razo para us-lo
se voc detectar uma condio de erro:
import math

def imprimeLogaritmo(x):
if x <= 0:
print "Somente nmeros positivos, por favor."
return

resultado = math.log(x)
print "O log de x ", resultado

A funo imprimeLogaritmo recebe um parmetro de nome x. A primeira coisa que ela faz checar se x menor
ou igual a 0, neste caso ela exibe uma mensagem de erro e ento usa return para sair da funo. O fluxo de execuo
imediatamente retorna ao ponto chamador, quer dizer, de onde a funo foi chamada, e as linhas restantes da funo
no so executadas.
Lembre-se que para usar uma funo do mdulo de matemtica, math, voc tem de import-lo.

6.9 4.9 Recursividade

J mencionamos que vlido uma funo chamar outra funo, e voc viu vrios exemplos disso. Mas ainda no
tnhamos dito que tambm vlido uma funo chamar a si mesma. Talvez no seja bvio porque isso bom, mas
trata-se de uma das coisas mais mgicas e interessantes que um programa pode fazer. Por exemplo, d uma olhada na
seguinte funo:
def contagemRegressiva(n):
if n == 0:
print "Fogo!"
else:
print n
contagemRegressiva(n-1)

contagemRegressiva espera que o parmetro, n, seja um inteiro positivo. Se n for 0, ela produz como
sada a palavra Fogo!. De outro modo, ela produz como sada n e ento chama uma funo de nome
contagemRegressiva ela mesma passando n-1 como argumento.
O que acontece se chamarmos essa funo da seguinte maneira:
>>> contagemRegressiva(3)

6.8. 4.8 A instruo return 39


Aprenda Computao com Python Documentation, Verso 1.1

A execuo de contagemRegressiva comea com n=3, e desde que n no 0, produz como sada o valor 3, e
ento chama a si mesma...
A execuo de contagemRegressiva comea com n=2, e desde que n no 0, produz como sada o valor 2, e
ento chama a si mesma...
A execuo de contagemRegressiva comea com n=1, e desde que n no 0, produz como sada o valor 1, e
ento chama a si mesma...
A execuo de contagemRegressiva comea com n=0, e desde que n 0, produz como sada a palavra Fogo!
e ento retorna.
A contagemRegressiva que tem n=1 retorna.
A contagemRegressiva que tem n=2 retorna.
A contagemRegressiva que tem n=3 retorna.
E ento estamos de volta em __main__ (que viagem!). Assim, a sada completa se parece com:
3
2
1
Fogo!

Como um segundo exemplo, d uma olhada novamente nas funes novaLinha e tresLinhas:
def novaLinha():
print

def tresLinhas():
novaLinha()
novaLinha()
novaLinha()

Muito embora isso funcione, no seria muito til se precisssemos gerar como sada 2 novas linhas, ou 106. Uma
alternativa melhor seria esta:
def nLinhas(n):
if n > 0:
print
nLinhas(n-1)

Esse programa similar a contagemRegressiva. Sempre que n for maior que 0, ele gera como sada uma nova
linha e ento chama a si mesmo para gerar como sada n-1 linhas adicionais. Deste modo, o nmero total de novas
linhas 1 + (n-1) que, se voc estudou lgebra direitinho, vem a ser o prprio n.
O processo de uma funo chamando a si mesma chamado de recursividade, e tais funes so ditas recursivas.

6.10 4.10 Diagramas de pilha para funes recursivas

Na Seo 3.11, usamos um diagrama de pilha para representar o estado de um programa durante uma chamada de
funo. O mesmo tipo de diagrama pode ajudar a interpretar uma funo recursiva.
Toda vez que uma funo chamada, Python cria um novo quadro (frame) para a funo, que contm as variveis
locais e parmetros da funo. Para uma funo recursiva, ter que existir mais de um quadro na pilha ao mesmo
tempo.
Esta figura mostra um diagrama de pilha para contagemRegressiva, chamada com n = 3:

40 Captulo 6. Captulo 4: Condicionais e recursividade


Aprenda Computao com Python Documentation, Verso 1.1

Como de costume, no topo da pilha est o quadro para __main__. Ele est vazio porque nem criamos qualquer
varivel em __main__ nem passamos qualquer valor para ele.
Os quatro quadros contagemRegressiva tm valores diferentes para o parmetro n. A parte mais em baixo na
pilha, onde n=0, chamada de caso base. Ele no faz uma chamada recursiva, ento no h mais quadros.
Como exerccio, desenhe um diagrama de pilha para nLinhas chamada com n=4.

6.11 4.11 Recursividade infinita

Se uma recursividade nunca chega ao caso base, ela prossegue fazendo chamadas recursivas para sempre, e o programa
nunca termina. Isto conhecido como recursividade infinita, e geralmente no considerada uma boa ideia. Aqui est
um programa mnimo com uma recursividade infinita:
def recursiva():
recursiva()

Na maioria dos ambientes de programao, um programa com recursividade infinita na verdade no roda para sempre.
Python reporta uma mensagem de erro quando a profundidade mxima de recursividade alcanada:
File "<stdin>", line 2, in recursiva
(98 repetitions omitted)
File "<stdin>", line 2, in recursiva
RuntimeError: Maximum recursion depth exceeded

Este traceback um pouco maior do que aquele que vimos no captulo anterior. Quando o erro ocorre, existem 100
quadros recursiva na pilha!
Como exerccio, escreva uma funo com recursividade infinita e rode-a no interpretador Python.

6.11. 4.11 Recursividade infinita 41


Aprenda Computao com Python Documentation, Verso 1.1

6.12 4.12 Entrada pelo teclado

Os programas que temos escrito at agora so um pouco crus, no sentido de no aceitarem dados entrados pelo usurio.
Eles simplesmente fazem a mesma coisa todas as vezes.
Python fornece funes nativas que pegam entradas pelo teclado. A mais simples chamada raw_input. Quando
esta funo chamada, o programa pra e espera que o usurio digite alguma coisa. Quando o usurio aperta a tecla
Enter ou Return, o programa prossegue e a funo raw_input retorna o que o usurio digitou como uma string:
>>> entrada = raw_input()
O que voc est esperando?
>>> print entrada
O que voc est esperando?

Antes de chamar raw_input, uma boa ideia exibir uma mensagem dizendo ao usurio o que ele deve entrar. Esta
mensagem uma como se fosse uma pergunta (prompt). Esta pergunta pode ser enviada como um argumento para
raw_input:
>>> nome = raw_input("Qual... o seu nome? ")
Qual... o seu nome? Arthur, Rei dos Bretes!
>>> print nome
Arthur, Rei dos Bretes!

Se esperamos que a entrada seja um inteiro, podemos usar a funo input:


pergunta = "Qual... a velocidade de vo de uma andorinha?\n"
velocidade = input(pergunta)

Se o usurio digita uma string de nmeros, ela convertida para um inteiro e atribuda a velocidade. Infelizmente,
se o usurio digitar um caractere que no seja um nmero, o programa trava:
>>> velocidade = input(pergunta)
Qual... a velocidade de vo de uma andorinha?
De qual voc fala, uma andorinha Africana ou uma Europeia?
SyntaxError: invalid syntax

Para evitar esse tipo de erro, geralmente bom usar raw_input para pegar uma string e, ento, usar funes de
converso para converter para outros tipos.

6.13 4.13 Glossrio

aninhamento (nesting) Estrutura de programa dentro da outra, como um comando condicional dentro de um bloco
de outro comando condicional.
bloco (block) Grupo de comandos consecutivos com a mesma endentao.
caso base (base case) Bloco de comando condicional numa funo recursiva que no resulta em uma chamada recur-
siva.
comando composto (compound statement) Comando que consiste de um cabealho e um corpo. O cabealho ter-
mina com um dois-pontos (:). O corpo endentado em relao ao cabealho.
comando condicional (conditional statement) Comando que controla o fluxo de execuo dependendo de alguma
condio.
condio (condition) A expresso booleana que determina qual bloco ser executado num comando condicional.
corpo (body) O bloco que se segue ao cabealho em um comando composto.

42 Captulo 6. Captulo 4: Condicionais e recursividade


Aprenda Computao com Python Documentation, Verso 1.1

expresso booleana (boolean expression) Uma expresso que verdadeira ou falsa.


operador de comparao (comparison operator) Um dos operadores que compara dois valores: ==, !=, >, <, >=,
e <=.
operador lgico (logical operator) Um dos operadores que combina expresses booleanas: and, or, e not.
operador mdulo (modulus operator) Operador denotado por um smbolo de porcentagem (%), que trabalha com
inteiros e retorna o resto da diviso de um nmero por outro.
prompt Indicao visual que diz ao usurio que o programa est esperando uma entrada de dados.
recursividade (recursion) O processo de chamar a prpria funo que est sendo executada.
recursividade infinita (infinite recursion) Funo que chama a si mesma recursivamente sem nunca chegar ao caso
base. Aps algum tempo, uma recursividade infinita causa um erro de execuo.

6.13. 4.13 Glossrio 43


Aprenda Computao com Python Documentation, Verso 1.1

44 Captulo 6. Captulo 4: Condicionais e recursividade


CAPTULO 7

Captulo 5: Funes frutferas

Tpicos
Captulo 5: Funes frutferas
5.1 Valores de retorno
5.2 Desenvolvimento de programas
5.3 Composio
5.4 Funes booleanas
5.5 Mais recursividade
5.6 Voto de confiana (Leap of faith)
5.7 Mais um exemplo
5.8 Checagem de tipos
5.9 Glossrio

7.1 5.1 Valores de retorno

Algumas das funes nativas do Python que temos usado, como as funes matemticas, produziram resultados.
Chamar a funo gerou um novo valor, o qual geralmente atribumos uma varivel ou usamos como parte de uma
expresso:
e = math.exp(1.0)
altura = raio * math.sin(angulo)

Mas at agora, nenhuma das funes que ns escrevemos retornou um valor.


Neste captulo, iremos escrever funes que retornam valores, as quais chamaremos de funes frutferas, ou funes
que do frutos, na falta de um nome melhor. O primeiro exemplo area, que retorna a rea de um crculo dado o seu
raio:
import math

def area(raio):
temp = math.pi * raio**2
return temp

45
Aprenda Computao com Python Documentation, Verso 1.1

J vimos a instruo return antes, mas em uma funo frutfera a instruo return inclui um valor de retorno.
Esta instruo significa: Retorne imediatamente desta funo e use a expresso em seguida como um valor de re-
torno. A expresso fornecida pode ser arbitrariamente complicada, de modo que poderamos ter escrito esta funo
de maneira mais concisa:
def area(raio):
return math.pi * raio**2

Por outro lado, variveis temporrias como temp muitas vezes tornam a depurao mais fcil.
s vezes til ter mltiplos comandos return, um em cada ramo de uma condicional:
def valorAbsoluto(x):
if x < 0:
return -x
else:
return x

J que estes comandos return esto em ramos alternativos da condicional, apenas um ser executado. To logo um
seja executado, a funo termina sem executar qualquer instruo ou comando subsequente.
O cdigo que aparece depois de uma instruo return, ou em qualquer outro lugar que o fluxo de execuo jamais
alcance, chamado cdigo morto (dead code).
Em uma funo frutfera, uma boa ideia assegurar que todo caminho possvel dentro do programa encontre uma
instruo return. Por exemplo:
def valorAbsoluto(x):
if x < 0:
return -x
elif x > 0:
return x

Este programa no est correto porque se x for 0, nenhuma das condies ser verdadeira, e a funo terminar sem
encontrar um comando return. Neste caso, o valor de retorno ser um valor especial chamado None:
>>> print valorAbsoluto(0)
None

Como exerccio, escreva uma funo compare que retorne 1 se x > y, 0 se x == y e -1 se x < y.

7.2 5.2 Desenvolvimento de programas

Neste ponto, voc deve estar apto a olhar para funes completas e dizer o que elas fazem. Tambm, se voc vem
fazendo os exerccios, voc escreveu algumas pequenas funes. Conforme escrever funes maiores, voc pode
comear a ter mais dificuldade, especialmente com erros em tempo de execuo (erros de runtime) ou erros semnticos.
Para lidar com programas de crescente complexidade, vamos sugerir uma tcnica chamada desenvolvimento incre-
mental. A meta do desenvolvimento incremental evitar sees de depurao (debugging) muito longas pela adio e
teste de somente uma pequena quantidade de cdigo de cada vez.
Como exemplo, suponha que voc queira encontrar a distncia entre dois pontos, dados pelas coordenadas (x1,y1) e
(x2,y2). Pelo teorema de Pitgoras, a distncia :
distancia = V (x2 - x1)2 + (y2 - y1)2 (5.1)

XXX: falta o sinal de raiz e elevar os expoentes desta frmula


O primeiro passo considerar como deveria ser uma funo distancia em Python. Em outras palavras, quais so
as entradas (parmetros) e qual a sada (valor de retorno)?

46 Captulo 7. Captulo 5: Funes frutferas


Aprenda Computao com Python Documentation, Verso 1.1

Neste caso, os dois pontos so as entradas, os quais podemos representar usando quatro parmetros. O valor de retorno
a distncia, que um valor em ponto flutuante.
J podemos escrever um esboo da funo:
def distancia(x1, y1, x2, y2):
return 0.0

Obviamente, esta verso da funo no calcula distncias; ela sempre retorna zero. Mas ela est sintaticamente correta,
e vai rodar, o que significa que podemos test-la antes de torn-la mais complicada.
Para testar a nova funo, vamos cham-la com valores hipotticos:
>>> distancia(1, 2, 4, 6)
0.0

Escolhemos estes valores de modo que a distncia horizontal seja igual a 3 e a distncia vertical seja igual a 4; deste
modo, o resultado 5 (a hipotenusa de um tringulo 3-4-5). Quando testamos uma funo, til sabermos qual o
resultado correto.
Neste ponto, j confirmamos que a funo est sintaticamente correta, e podemos comear a adicionar linhas de cdigo.
Depois de cada mudana adicionada, testamos a funo de novo. Se um erro ocorre em qualquer ponto, sabemos aonde
ele deve estar: nas linhas adicionadas mais recentemente.
Um primeiro passo lgico nesta operao encontrar as diferenas x2 - x1 e y2 - y1. Ns iremos guardar estes valores
em variveis temporrias chamadas dx e dy e imprimi-las:
def distancia(x1, y1, x2, y2):
dx = x2 - x1
dy = y2 - y1
print "dx vale", dx
print "dy vale", dy
return 0.0

Se a funo estiver funcionando, as sadas devero ser 3 e 4. Se assim, sabemos que a funo est recebendo os
parmetros corretos e realizando o primeiro clculo corretamente. Se no, existem poucas linhas para checar.
Em seguida, calcularemos a soma dos quadrados de dx e dy:
def distancia(x1, y1, x2, y2):
dx = x2 - x1
dy = y2 - y1
dquadrado = dx**2 + dy**2
print "dquadrado vale: ", dquadrado
return 0.0

Note que removemos os comandos print que havamos escrito no passo anterior. Cdigo como este ajuda a escrever
o programa, mas no parte do produto final (em ingls usado o termo scaffolding).
De novo, ns vamos rodar o programa neste estgio e checar a sada (que deveria ser 25).
Finalmente, se ns tnhamos importado o mdulo matemtico math, podemos usar a funo sqrt para computar e
retornar o resultado:
def distancia(x1, x2, y1, y2):
dx = x2 - x1
dy = y2 - y1
dquadrado = dx**2 + dy**2
resultado = math.sqrt(dquadrado)
return resultado

Se isto funcionar corretamente, voc conseguiu. Caso contrrio, talvez fosse preciso imprimir (exibir) o valor de
resultado antes da instruo return.

7.2. 5.2 Desenvolvimento de programas 47


Aprenda Computao com Python Documentation, Verso 1.1

Enquanto for iniciante, voc deve acrescentar apenas uma ou duas linhas de cdigo de cada vez. Conforme ganhar mais
experincia, voc se ver escrevendo e depurando pedaos maiores. De qualquer modo, o processo de desenvolvimento
incremental pode poupar um bocado de tempo de depurao.
Os aspectos chave do processo so:
1. Comece com um programa que funciona e faa pequenas mudanas incrementais. Em qualquer ponto do pro-
cesso, se houver um erro, voc saber exatamente onde ele est.
2. Use variveis temporrias para manter valores intermedirios de modo que voc possa exibi-los e chec-los.
3. Uma vez que o programa funcione, voc pode querer remover algum cdigo muleta, ou algum scaffolding ou
consolidar mltiplos comandos dentro de expresses compostas, mas somente se isto no tornar o programa
difcil de ler.
Como um exerccio, use o desenvolvimento incremental para escrever uma funo chamada
hipotenusa que retorna a medida da hipotenusa de um tringulo retngulo dadas as medidas dos dois
catetos como parmetros. Registre cada estgio do desenvolvimento incremental conforme voc avance.

7.3 5.3 Composio

Conforme voc poderia esperar agora, voc pode chamar uma funo de dentro de outra. Esta habilidade chamada
de composio.
Como um exemplo, vamos escrever uma funo que recebe dois pontos, o centro de um crculo e um ponto em seu
permetro, e calcula a rea do crculo.
Assuma que o ponto do centro est guardado nas variveis xc e yc, e que o ponto do permetro est nas variveis xp
e yp. O primeiro passo encontrar o raio do crculo, o qual a entre os dois pontos. Felizmente, temos uma funo,
distancia, que faz isto:
Raio = distancia(xc, yc, xp, yp)

O segundo passo encontrar a rea de um crculo com o raio dado e retorn-la:


resultado = area(raio)
return resultado

Juntando tudo numa funo, temos:


def area2(xc, yc, xp, yp):

raio = distancia(xc, yc, xp, yp)


resultado = area(raio)
return resultado

Chamamos esta funo de area2 para distinguir da funo area, definida anteriormente. S pode existir uma
nica funo com um determinado nome em um determinado mdulo.
As variveis temporrias raio e resultado so teis para o desenvolvimento e para depurao (debugging), mas
uma vez que o programa esteja funcionando, podemos torn-lo mais conciso atravs da composio das chamadas de
funo:
def area2(xc, yc, xp, yp):

return area(distancia(xc, yc, xp, yp))

Como exerccio, escreva uma funo coeficienteAngular(x1, y1, x2, y2) que retorne a coeficiente an-
gular de uma linha dados os pontos (x1, y1) e (x2, y2). Depois use esta funo em uma funo chamada cortaY(x1,
y1, x2, y2) que retorne a interseo da linha com o eixo y, dados os pontos (x1, y1) e (x2, y2).

48 Captulo 7. Captulo 5: Funes frutferas


Aprenda Computao com Python Documentation, Verso 1.1

7.4 5.4 Funes booleanas

Funes podem retornar valores booleanos, o que muitas vezes conveniente por ocultar testes complicados dentro de
funes. Por exemplo:
def ehDivisivel(x, y):
If x % y == 0:
return True # verdadeiro (True), divisvel
else:
return False # falso (False), no divisvel

O nome desta funo ehDivisivel ( divisvel). comum dar a uma funo booleana nomes que soem como
perguntas sim/no. ehDivisivel retorna ou True ou False para indicar se x ou no divisvel por y.
Podemos tornar a funo mais concisa se tirarmos vantagem do fato de a condio da instruo if ser ela mesma uma
expresso booleana. Podemos retorn-la diretamente, evitando totalmente o if:
def ehDivisivel(x, y):
return x % y == 0

Esta sesso mostra a nova funo em ao:


>>> ehDivisivel(6, 4)
False
>>> ehDivisivel(6, 3)
True

Funes booleanas so frequentemente usadas em comandos condicionais:


if ehDivisivel(x, y):
print "x divisvel por y"
else:
print "x no divisvel por y"

Mas a comparao extra desnecessria.


Como exerccio, escreva uma funo estaEntre(x, y, z) que retorne True se y < x < z ou False,
se no.

7.5 5.5 Mais recursividade

At aqui, voc aprendeu apenas um pequeno subconjunto da linguagem Python, mas pode ser que te interesse saber
que este pequeno subconjunto uma linguagem de programao completa, o que significa que qualquer coisa que
possa ser traduzida em operao computacional pode ser expressa nesta linguagem. Qualquer programa j escrito
pode ser reescrito usando somente os aspectos da linguagem que voc aprendeu at agora (usualmente, voc precisaria
de uns poucos comandos para controlar dispositivos como o teclado, mouse, discos, etc., mas isto tudo).
Provar esta afirmao um exerccio nada trivial, que foi alcanado pela primeira vez por Alan Turing, um dos
primeiros cientistas da computao (algum poderia dizer que ele foi um matemtico, mas muitos dos primeiros
cientistas da computao comearam como matemticos). Por isso, ficou conhecido como Tese de Turing. Se voc
fizer um curso em Teoria da Computao, voc ter chance de ver a prova.
Para te dar uma ideia do que voc pode fazer com as ferramentas que aprendeu a usar at agora, vamos avaliar algumas
funes matemticas recursivamente definidas. Uma definio recursiva similar uma definio circular, no sentido
de que a definio faz referncia coisa que est sendo definida. Uma verdadeira definio circular no muito til:
vorpal: adjetivo usado para descrever algo que vorpal.

7.4. 5.4 Funes booleanas 49


Aprenda Computao com Python Documentation, Verso 1.1

Se voc visse esta definio em um dicionrio, ficaria confuso. Por outro lado, se voc procurasse pela definio da
funo matemtica fatorial, voc encontraria algo assim:
0! = 1
n! = n.(n-1)!

Esta definio diz que o fatorial de 0 1, e que o fatorial de qualquer outro valor, n, n multiplicado pelo fatorial de
n-1.
Assim, 3! (l-se 3 fatorial ou fatorial de 3) 3 vezes 2!, o qual 2 vezes 1!, o qual 1 vezes 0!. Colocando tudo
isso junto, 3! igual 3 vezes 2 vezes 1 vezes 1, o que 6.
Se voc pode escrever uma definio recursiva de alguma coisa, voc geralmente pode escrever um programa em
Python para execut-la. O primeiro passo decidir quais so os parmetros para esta funo. Com pouco esforo,
voc dever concluir que fatorial recebe um nico parmetro:
def fatorial(n):

Se acontece de o argumento ser 0, tudo o que temos de fazer retornar 1:


def fatorial(n):
if n == 0:
return 1

Por outro lado, e esta a parte interessante, temos que fazer uma chamada recursiva para encontrar o fatorial de n-1 e
ento multiplic-lo por n:
def fatorial(n):
if n == 0:
return 1
else:
recursivo = fatorial(n-1)
resultado = n * recursivo
return resultado

O fluxo de execuo para este programa similar ao fluxo de contagemRegressiva na Seo 4.9. Se chamarmos
fatorial com o valor 3:
J que 3 no 0, tomamos o segundo ramo e calculamos o fatorial de n-1 ...
J que 2 no 0, tomamos o segundo ramo e calculamos o fatorial de n-1 ...
J que 1 no 0, tomamos o segundo ramo e calculamos o fatorial de n-1 ...
J que 0 0, tomamos o primeiro ramo e retornamos 1 sem fazer mais qualquer chamada recursiva.
O valor retornado (1) multiplicado por n, que 1, e o resultado retornado.
O valor retornado (1) multiplicado por n, que 2, e o resultado retornado.
O valor retornado (2) multiplicado por n, que 3, e o resultado, 6, se torna o valor de retorno da chamada de funo
que iniciou todo o processo.
Eis o diagrama de pilha para esta sequncia de chamadas de funo:

50 Captulo 7. Captulo 5: Funes frutferas


Aprenda Computao com Python Documentation, Verso 1.1

Os valores de retorno so mostrados sendo passados de volta para cima da pilha. Em cada quadro, o valor de retorno
o valor de resultado, o qual o produto de n por recursivo.

7.6 5.6 Voto de confiana (Leap of faith)

Seguir o fluxo de execuo uma maneira de ler programas, mas que pode rapidamente se transformar em um labirinto.
Uma alternativa o que chamamos de voto de confiana. Quando voc tem uma chamada de funo, em vez de
seguir o fluxo de execuo, voc assume que a funo funciona corretamente e retorna o valor apropriado.
De fato, voc est agora mesmo praticando este voto de confiana ao usar as funes nativas. Quando voc chama
math.cos ou math.exp, voc no examina a implementao destas funes. Voc apenas assume que elas fun-
cionam porque as pessoas que escreveram as bibliotecas nativas eram bons programadores.
O mesmo tambm verdade quando voc chama uma de suas prprias funes. Por exemplo, na Seo 5.4, es-
crevemos a funo chamada ehDivisivel que determina se um nmero divisvel por outro. Uma vez que nos
convencemos que esta funo est correta ao testar e examinar o cdigo podemos usar a funo sem examinar o
cdigo novamente.
O mesmo tambm verdadeiro para programas recursivos. Quando voc tem uma chamada recursiva, em vez de
seguir o fluxo de execuo, voc poderia assumir que a chamada recursiva funciona (produz o resultado correto) e
ento perguntar-se, Assumindo que eu possa encontrar o fatorial de n-1, posso calcular o fatorial de n? Neste caso,
claro que voc pode, multiplicando por n.
Naturalmente, um pouco estranho que uma funo funcione corretamente se voc ainda nem terminou de escrev-la,
mas por isso que se chama voto de confiana!

7.7 5.7 Mais um exemplo

No exemplo anterior, usamos variveis temporrias para deixar claros os passos e tornar o cdigo mais fcil de depurar,
mas poderamos ter economizado algumas linhas:
def fatorial(n):
if n == 0:
return 1

7.6. 5.6 Voto de confiana (Leap of faith) 51


Aprenda Computao com Python Documentation, Verso 1.1

else:
return n * fatorial(n-1)

De agora em diante, tenderemos a utilizar um formato mais conciso, mas recomendamos que voc use a verso mais
explcita enquanto estiver desenvolvendo cdigo. Quando ele estiver funcionando, voc pode enxug-lo se estiver se
sentindo inspirado.
Depois de fatorial, o exemplo mais comum de uma funo matemtica definida recursivamente fibonacci,
a qual tem a seguinte definio:
fibonacci(0) = 1
fibonacci(1) = 1
fibonacci(n) = fibonacci(n-1) + fibonacci(n-2);

Traduzido em Python, parecer assim:


def fibonacci(n):
if n == 0 or n == 1:
return 1
else:
return fibonacci(n-1) + fibonacci(n-2)

Se voc tentar seguir o fluxo de execuo aqui, mesmo para valores bem pequenos de n, sua cabea explodir. Mas,
de acordo com o voto de confiana, se voc assume que as duas chamadas recursivas funcionam corretamente, ento
claro que voc ter o resultado correto ao junt-las.

7.8 5.8 Checagem de tipos

O que acontece se chamamos fatorial e damos a ela 1.5 como argumento?:


>>> fatorial (1.5)
RuntimeError: Maximum recursion depth exceeded

Parece um caso de recursividade infinita. Mas o que ser que de fato? Existe um caso base quando n == 0. O
problema que o valor de n nunca encontra o caso base.
Na primeira chamada recursiva, o valor de n 0.5. Na prxima, ele igual a -0.5. Da em diante, ele se torna cada vez
menor, mas jamais ser 0.
Temos ento duas alternativas. Podemos tentar generalizar a funo fatorial para que funcione com nmeros em
ponto flutuante, ou fazemos fatorial realizar a checagem de tipo de seus parmetros. A primeira chamada funo
gamma e est um pouco alm do escopo deste livro. Sendo assim, ficaremos com a segunda.
Podemos usar type para comparar o tipo do parmetro com o tipo de um valor inteiro conhecido (como 1). Ao
mesmo tempo em que fazemos isto, podemos nos certificar tambm de que o parmetro seja positivo:
def fatorial (n):
if type(n) != type(1):
print "Fatorial somente definido para inteiros."
return -1
elif n < 0:
print "Fatorial somente definido para inteiros positivos."
return -1
elif n ==0:
return 1
else:
return n * fatorial(n-1)

52 Captulo 7. Captulo 5: Funes frutferas


Aprenda Computao com Python Documentation, Verso 1.1

Agora temos trs casos base. O primeiro pega os no-inteiros. O segundo pega os inteiros negativos. Em ambos os
casos, o programa exibe uma mensagem de erro e retorna um valor especial, -1, para indicar que alguma coisa saiu
errada:
>>> fatorial ("Fred")
Fatorial somente definido para inteiros.
-1
>>> fatorial (-2)
Fatorial somente definido para inteiros positivos.
-1

Se passarmos pelas duas checagens, ento saberemos que n um inteiro positivo, e poderemos provar que a recursivi-
dade encontra seu trmino.
Este programa demonstra um padro (pattern) chamado s vezes de guardio. As duas primeiras condicionais atuam
como guardis, protegendo o cdigo que vem em seguida de valores que poderiam causar um erro. Os guardies
tornam possvel garantir a correo do cdigo.

7.9 5.9 Glossrio

cdigo morto (dead code) Parte de um programa que nunca pode ser executada, muitas vezes por que ela aparece
depois de uma instruo return.
desenvolvimento incremental (incremental development) Uma estratgia de desenvolvimento de programas que
evita a depurao ao adicionar e testar somente uma pequena quantidade de cdigo de cada vez.
funo frutfera (fruitful function) Uma funo que produz um valor de retorno.
guardio (guardian) Uma condio que checa e manipula circunstncias que poderiam causar um erro.
None Um valor especial em Python, retornado por funes que no possuem uma instruo return ou tm uma
instruo return sem argumento.
scaffolding Cdigo usado durante o desenvolvimento do programa, mas que no faz parte do produto final.
varivel temporria (temporary variable) Uma varivel usada para guardar um valor intermedirio em um clculo
complexo.
valor de retorno (return value) O valor entregue como resultado de uma chamada de funo.

7.9. 5.9 Glossrio 53


Aprenda Computao com Python Documentation, Verso 1.1

54 Captulo 7. Captulo 5: Funes frutferas


CAPTULO 8

Captulo 6: Iterao

Tpicos
Captulo 6: Iterao
6.1 Reatribuies
6.2 O comando while
6.3 Tabelas
6.4 Tabelas de duas dimenses (ou bi-dimensionais)
6.5 Encapsulamento e generalizao
6.6 Mais encapsulamento
6.7 Variveis locais
6.8 Mais generalizao
6.9 Funes
6.10 Glossrio

8.1 6.1 Reatribuies

Como voc talvez j tenha descoberto, permitido fazer mais de uma atribuio mesma varivel. Uma nova
atribuio faz uma varivel existente referir-se a um novo valor (sem se referir mais ao antigo).:
bruno = 5
print bruno,
bruno = 7
print bruno

A sada deste programa 5 7, porque na primeira vez que bruno impresso, seu valor 5 e na segunda vez, seu
valor 7. A vrgula no final do primeiro comando print suprime a nova linha no final da sada, que o motivo pelo
qual as duas sadas aparecem na mesma linha.
Veja uma reatribuio em um diagrama de estado:

55
Aprenda Computao com Python Documentation, Verso 1.1

Com a reatribuio torna-se ainda mais importante distinguir entre uma operao de atribuio e um comando de
igualdade. Como Python usa o sinal de igual ( = ) para atribuio, existe a tendncia de lermos um comando como a
= b como um comando de igualdade. Mas no !
Em primeiro lugar, igualdade comutativa e atribuio no . Por exemplo, em matemtica, se a = 7 ento 7 = a. Mas
em Python, o comando a = 7 permitido e 7 = a no .
Alm disso, em matemtica, uma expresso de igualdade sempre verdadeira. Se a = b agora, ento, a ser sempre
igual a b. Em Python, um comando de atribuio pode tornar duas variveis iguais, mas elas no tm que permanecer
assim:
a = 5
b = a # a e b agora so iguais
b = 3 # a e b no so mais iguais

A terceira linha muda o valor de a mas no muda o valor de b, ento, elas no so mais iguais. (Em algumas linguagens
de programao, um smbolo diferente usado para atribuio, como <- ou :=, para evitar confuso.)
Embora a reatribuio seja freqentemente til, voc deve us-la com cautela. Se o valor das variveis muda freqen-
temente, isto pode fazer o cdigo difcil de ler e de depurar.

8.2 6.2 O comando while

Os computadores so muito utilizados para automatizar tarefas repetitivas. Repetir tarefas idnticas ou similares sem
cometer erros uma coisa que os computadores fazem bem e que as pessoas fazem poorly.
Vimos dois programas, nLinhas e contagemRegressiva, que usam recursividade (recurso) para fazer a
repetio, que tambm chamada iterao. Porque a iterao muito comum, Python tem vrias caractersticas
para torn-la mais fcil. A primeira delas em que vamos dar uma olhada o comando while.
Aqui est como fica contagemRegressiva com um comando while:
def contagemRegressiva(n):
while n > 0:
print n
n = n-1
print "Fogo!"

Desde que removemos a chamada recursiva, esta funo no recursiva.


Voc quase pode ler o comando while como se fosse Ingls. Ele significa, Enquanto (while) n for maior do que 0,
siga exibindo o valor de n e diminuindo 1 do valor de n. Quando chegar a 0, exiba a palavra Fogo!.
Mais formalmente, aqui est o fluxo de execuo para um comando while:
1. Teste a condio, resultando 0 ou 1.
2. Se a condio for falsa (0), saia do comando while e continue a execuo a partir do prximo comando.
3. Se a condio for verdadeira (1), execute cada um dos comandos dentro do corpo e volte ao passo 1.

56 Captulo 8. Captulo 6: Iterao


Aprenda Computao com Python Documentation, Verso 1.1

O corpo consiste de todos os comandos abaixo do cabealho, com a mesma endentao.


Este tipo de fluxo chamado de um loop (ou lao) porque o terceiro passo cria um loop ou um lao de volta ao topo.
Note que se a condio for falsa na primeira vez que entrarmos no loop, os comandos dentro do loop jamais sero
executados.
O corpo do loop poderia alterar o valor de uma ou mais variveis de modo que eventualmente a condio se torne falsa
e o loop termine. Se no for assim, o loop se repetir para sempre, o que chamado de um loop infinito. Uma fonte
de diverso sem fim para os cientistas da computao a observao de que as instrues da embalagem de shampoo,
Lave, enxge, repita um loop infinito.
No caso de contagemRegressiva, podemos provar que o loop terminar porque sabemos que o valor de n finito,
e podemos ver que o valor de n diminui dentro de cada repetio (iterao) do loop, ento, eventualmente chegaremos
ao 0. Em outros casos, isto no to simples de afirmar:
def sequencia(n):
while n != 1:
print n,
if n%2 == 0: # n par
n = n/2
else: # n impar
n = n*3+1

A condio para este loop n != 1, ento o loop vai continuar at que n seja 1, o que tornar a condio falsa.
Dentro de cada repetio (iterao) do loop, o programa gera o valor de n e ento checa se ele par ou impar. Se ele
for par, o valor de n dividido por 2. Se ele for impar, o valor substitudo por n*3+1. Por exemplo, se o valor
inicial (o argumento passado para seqncia) for 3, a seqncia resultante ser 3, 10, 5, 16, 8, 4, 2, 1.
J que n s vezes aumenta e s vezes diminui, no existe uma prova bvia de que n jamais venha a alcanar 1, ou de
que o programa termine. Para alguns valores particulares de n, podemos provar o trmino. Por exemplo, se o valor
inicial for uma potncia de dois, ento o valor de n ser par dentro de cada repetio (iterao) do loop at que alcance
1. O exemplo anterior termina com uma dessas seqncias comeando em 16.
Valores especficos parte, A questo interessante se h como provarmos que este programa termina para todos os
valores de n. At hoje, ningum foi capaz de provar que sim ou que no!
Como um exerccio, reescreva a funo nLinhas da seo 4.9 usando iterao em vez de recurso.

8.3 6.3 Tabelas

Uma das coisas para qual os loops so bons para gerar dados tabulares. Antes que os computadores estivessem
readily disponveis, as pessoas tinham que calcular logaritmos, senos, cossenos e outras funes matemticas mo.
Para tornar isto mais fcil, os livros de matemtica continham longas tabelas listando os valores destas funes. Criar
as tabelas era demorado e entediante, e elas tendiam a ser cheias de erros.
Quando os computadores entraram em cena, uma das reaes iniciais foi Isto timo! Podemos usar computadores
para geras as tabelas, assim no haver erros. Isto veio a se tornar verdade (na maioria das vezes) mas shortsighted.
Rapidamente, porm, computadores e calculadoras tornaram-se to pervasivos que as tabelas ficaram obsoletas.
Bem, quase. Para algumas operaes, os computadores usam tabelas de valores para conseguir uma resposta aprox-
imada e ento realizar clculos para melhorar a aproximao. Em alguns casos, tm havido erros nas tabelas un-
derlying, o caso mais famoso sendo o da tabela usada pelo processador Pentium da Intel para executar a diviso em
ponto-flutuante.
Embora uma tabela de logaritmos no seja mais to til quanto j foi um dia, ela ainda d um bom exemplo de iterao.
O seguinte programa gera uma seqncia de valores na coluna da esquerda e seus respectivos logaritmos na coluna da
direita:

8.3. 6.3 Tabelas 57


Aprenda Computao com Python Documentation, Verso 1.1

x = 1.0
while x < 10.0:
print x, \t, math.log(x)
x = x + 1.0

A string \t representa um caracter de tabulao.


Conforme caracteres e strings vo sendo mostrados na tela, um ponteiro invisvel chamado cursor marca aonde apare-
cer o prximo caractere. Depois de um comando print, o cursor normalmente vai para o incio de uma nova
linha.
O caractere de tabulao desloca o cursor para a direita at que ele encontre uma das marcas de tabulao. Tabulao
til para fazer colunas de texto line up, como na sada do programa anterior:
1.0 0.0
2.0 0.69314718056
3.0 1.09861228867
4.0 1.38629436112
5.0 1.60943791243
6.0 1.79175946923
7.0 1.94591014906
8.0 2.07944154168
9.0 2.19722457734

Se estes valores parecem odd, lembre-se que a funo log usa a base e. J que potncias de dois so to importantes
em cincia da computao, ns freqentemente temos que achar logaritmos referentes base 2. Para fazermos isso,
podemos usar a seguinte frmula:
(XXX diagramar frmula matemtica)
log2 x = loge x (6.1) loge 2
Alterando o comando de sada para:
print x, \t, math.log(x)/math.log(2.0)

o que resultar em:


1.0 0.0
2.0 1.0
3.0 1.58496250072
4.0 2.0
5.0 2.32192809489
6.0 2.58496250072
7.0 2.80735492206
8.0 3.0
9.0 3.16992500144

Podemos ver que 1, 2, 4 e 8 so potncias de dois porque seus logaritmos na base 2 so nmeros redondos. Se
precisssemos encontrar os logaritmos de outras potncias de dois, poderamos modificar o programa deste modo:
x = 1.0
while x < 100.0:
print x, \t, math.log(x)/math.log(2.0)
x = x * 2.0

Agora, em vez de somar algo a x a cada iterao do loop, o que resulta numa seqncia aritmtica, ns multiplicamos
x por algo, resultando numa seqncia geomtrica. O resultado :
1.0 0.0
2.0 1.0

58 Captulo 8. Captulo 6: Iterao


Aprenda Computao com Python Documentation, Verso 1.1

4.0 2.0
8.0 3.0
16.0 4.0
32.0 5.0
64.0 6.0

Por causa do caractere de tabulao entre as colunas, a posio da segunda coluna no depende do nmero de dgitos
na primeira coluna.
Tabelas de logaritmos podem no ser mais teis, mas para cientistas da computao, conhecer as potncias de dois !
Como um exerccio, modifique este programa de modo que ele produza as potncias de dois acima de 65.535 (ou seja,
216). Imprima e memorize-as.
O caractere de barra invertida em \t indica o incio de uma seqncia de escape. Seqncias de escape so usadas
para representar caracteres invisveis como de tabulao e de nova linha. A seqncia \n representa uma nova linha.
Uma seqncia de escape pode aparecer em qualquer lugar em uma string; no exemplo, a seqncia de escape de
tabulao a nica coisa dentro da string.
Como voc acha que se representa uma barra invertida em uma string?
Como um exerccio, escreva um nica string que
produza
esta sada.

8.4 6.4 Tabelas de duas dimenses (ou bi-dimensionais)

Uma tabela de duas dimenses uma tabela em que voc l o valor na interseo entre uma linha e uma coluna. Uma
tabela de multiplicao um bom exemplo. Digamos que voc queira imprimir uma tabela de multiplicao de 1 a 6.
Uma boa maneira de comear escrever um loop que imprima os mltiplos de 2, todos em uma linha:
i = 1
while i <= 6:
print 2*i, ,
i = i + 1
print

A primeira linha inicializa a varivel chamada i, a qual age como um contador ou varivel de controle do loop.
Conforme o loop executado, o valor de i incrementado de 1 a 6. Quando i for 7, o loop termina. A cada repetio
(iterao) do loop, mostrado o valor de 2*i, seguido de trs espaos.
De novo, a vrgula no comando print suprime a nova linha. Depois que o loop se completa, o segundo comando
print inicia uma nova linha.
A sada do programa :
2 4 6 8 10 12

At aqui, tudo bem. O prximo passo encapsular e generalizar.

8.5 6.5 Encapsulamento e generalizao

Encapsulamento o processo de wrapping um pedao de cdigo em uma funo, permitindo que voc tire vantagem de
todas as coisas para as quais as funes so boas. Voc j viu dois exemplos de encapsulamento: imprimeParidade

8.4. 6.4 Tabelas de duas dimenses (ou bi-dimensionais) 59


Aprenda Computao com Python Documentation, Verso 1.1

na seo 4.5; e eDivisivel na seo 5.4


Generalizao significa tomar algo que especfico, tal como imprimir os mltiplos de 2, e torn-lo mais geral, tal
como imprimir os mltiplos de qualquer inteiro.
Esta funo encapsula o loop anterior e generaliza-o para imprimir mltiplos de n:
def imprimeMultiplos(n):
i = 1
while i <= 6:
print n*i, \t ,
i = i + 1
print

Para encapsular, tudo o que tivemos que fazer foi adicionar a primeira linha, que declara o nome de uma funo e sua
lista de parmetros. Para generalizar, tudo o que tivemos que fazer foi substituir o valor 2 pelo parmetro n.
Se chamarmos esta funo com o argumento 2, teremos a mesma sada que antes. Com o argumento 3, a sada :
3 6 9 12 15 18

Com o argumento 4, a sada :


4 8 12 16 20 24

Agora voc provavelmente pode adivinhar como imprimir uma tabela de multiplicao - chamando
imprimeMultiplos repetidamente com argumentos diferentes. De fato, podemos usar um outro loop:
i = 1
while i <= 6:
imprimeMultiplos(i)
i = i + 1

Note o quanto este loop parecido com aquele dentro de imprimeMultiplos. Tudo o que fiz foi substituir o
comando print pela chamada funo.
A sada deste programa uma tabela de multiplicao:
1 2 3 4 5 6
2 4 6 8 10 12
3 6 9 12 15 18
4 8 12 16 20 24
5 10 15 20 25 30
6 12 18 24 30 36

8.6 6.6 Mais encapsulamento

Para demonstrar de novo o encapsulamento, vamos pegar o cdigo do final da seo 6.5 e acondicion-lo, envolv-lo
em uma funo:
def imprimeTabMult():
i = 1
while i <= 6:
imprimeMultiplos(i)
i = i + 1

Este processo um plano de desenvolvimento comum. Ns desenvolvemos cdigo escrevendo linhas de cdigo
fora de qualquer funo, ou digitando-as no interpretador. Quando temos o cdigo funcionando, extramos ele e o
embalamos em uma funo.

60 Captulo 8. Captulo 6: Iterao


Aprenda Computao com Python Documentation, Verso 1.1

Este plano de desenvolvimento particularmente til se voc no sabe, quando voc comea a escrever, como dividir
o programa em funes. Esta tcnica permite a voc projetar enquanto desenvolve.

8.7 6.7 Variveis locais

Voc pode estar pensando como podemos utilizar a mesma varivel, i, em ambos, imprimeMultiplos e
imprimeTabMult. Isto no causaria problemas quando uma das funes mudasse o valor da varivel?
A resposta no, porque o i em imprimeMultiplos e o i em imprimeTabMult no so a mesma varivel.
Variveis criadas dentro de uma definio de funo so locais; voc no pode acessar uma varivel local de fora da
funo em que ela mora. Isto significa que voc livre para ter mltiplas variveis com o mesmo nome, desde que
elas no estejam dentro da mesma funo.
O diagrama de pilha para este programa mostra que duas variveis chamadas i no so a mesma varivel. Elas podem
se referir a valores diferentes e alterar o valor de uma no afeta outra.

O valor de i em imprimeTabMult vai de 1 a 6. No diagrama, i agora 3. Na prxima iterao do loop i ser


4. A cada iterao do loop, imprimeTabMult chama imprimeMultiplos com o valor corrente de i como
argumento. O valor atribudo ao parmetro n.
Dentro de imprimeMultiplos, o valor de i vai de 1 a 6. No diagrama, i agora 2. Mudar esta varivel no tem
efeito sobre o valor de i em imprimeTabMult.
comum e perfeitamente legal ter variveis locais diferentes com o mesmo nome. Em particular, nomes como i e j
so muito usados para variveis de controle de loop. Se voc evitar utiliz-los em uma funo s porque voc j os
usou em outro lugar, voc provavelmente tornar seu programa mais difcil de ler.

8.8 6.8 Mais generalizao

Como um outro exemplo de generalizao, imagine que voc precise de um programa que possa imprimir uma tabela
de multiplicao de qualquer tamanho, no apenas uma tabela de seis por seis. Voc poderia adicionar um parmetro
a imprimeTabMult:

8.7. 6.7 Variveis locais 61


Aprenda Computao com Python Documentation, Verso 1.1

def imprimeTabMult(altura):
i = 1
while i <= altura:
imprimeMultiplos(i)
i = i + 1

Ns substitumos o valor 6 pelo parmetro altura. Se chamarmos imprimeTabMult com o argumento 7, ela mostra:
1 2 3 4 5 6
2 4 6 8 10 12
3 6 9 12 15 18
4 8 12 16 20 24
5 10 15 20 25 30
6 12 18 24 30 36
7 14 21 28 35 42

Isto bom, exceto que ns provavelmente quereramos que a tabela fosse quadrada - com o mesmo nmero de linhas
e colunas. Para fazer isso, adicionamos outro parmetro a imprimeMultiplos para especificar quantas colunas a
tabela deveria ter.
S para confundir, chamamos este novo parmetro de altura, demonstrando que diferentes funes podem ter
parmetros com o mesmo nome (como acontece com as variveis locais). Aqui est o programa completo:
def imprimeMultiplos(n, altura):
i = 1
while i <= altura:
print n*i, t,
i = i + 1
print

def imprimeTabMult(altura):
i = 1
while i <= altura:
imprimeMultiplos(i, altura)
i = i + 1

Note que quando adicionamos um novo parmetro, temos que mudar a primeira linha da funo (o cabealho da
funo), e ns tambm temos que mudar o lugar de onde a funo chamada em imprimeTabMult.
Como esperado, este programa gera uma tabela quadrada de sete por sete:
1 2 3 4 5 6 7
2 4 6 8 10 12 14
3 6 9 12 15 18 21
4 8 12 16 20 24 28
5 10 15 20 25 30 35
6 12 18 24 30 36 42
7 14 21 28 35 42 49

Quando voc generaliza uma funo apropriadamente, voc muitas vezes tem um programa com capacidades que
voc no planejou. Por exemplo, voc pode ter notado que, porque ab = ba, todas as entradas na tabela aparecem duas
vezes. Voc poderia economizar tinta imprimindo somente a metade da tabela. Para fazer isso, voc tem que mudar
apenas uma linha em imprimeTabMult. Mude:
imprimeTabMult(i, altura)

para:
imprimeTabMult(i, i)

e voc ter:

62 Captulo 8. Captulo 6: Iterao


Aprenda Computao com Python Documentation, Verso 1.1

1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49

Como um exerccio, trace a execuo desta verso de imprimeTabMult e explique como ela funciona.

8.9 6.9 Funes

H pouco tempo mencionamos todas as coisas para as quais as funes so boas. Agora, voc pode estar
pensando que coisas exatamente so estas. Aqui esto algumas delas:
Dar um nome para uma seqncia de comandos torna seu programa mais fcil de ler e de depurar.
Dividir um programa longo em funes permite que voc separe partes do programa, depure-as isoladamente, e
ento as componha em um todo.
Funes facilitam tanto recurso quanto iterao.
Funes bem projetadas so freqentemente teis para muitos programas. Uma vez que voc escreva e depure
uma, voc pode reutiliz-la.

8.10 6.10 Glossrio

reatribuio (multiple assignment 1 ) quando mais de um valor atribudo a mesma varivel durante a execuo do
programa.
iterao (iteration) execuo repetida de um conjunto de comandos/instrues (statements) usando uma chamada
recursiva de funo ou um lao (loop).
lao (loop) um comando/instruo ou conjunto de comandos/instrues que executam repetidamente at que uma
condio de interrupo seja atingida.
lao infinito (infinite loop) um lao em que a condio de interrupo nunca ser atingida.
corpo (body) o conjunto de comandos/instrues que pertencem a um lao.
varivel de lao (loop variable) uma varivel usada como parte da condio de interrupo do lao.
tabulao (tab) um carcter especial que faz com que o cursor mova-se para a prxima parada estabelecida de tabu-
lao na linha atual.
nova-linha (newline) um carcter especial que faz com que o cursor mova-se para o incio da prxima linha.
cursor (cursor) um marcador invisvel que determina onde o prximo carcter var ser impresso.
sequncia de escape (escape sequence) um carcter de escape () seguido por um ou mais caracteres imprimveis,
usados para definir um carcter no imprimvel.
encapsular (encapsulate) quando um programa grande e complexo dividido em componentes (como funes) e
estes so isolados um do outro (pelo uso de variveis locais, por exemplo).
generalizar (generalize) quando algo que desnecessariamente especfico (como um valor constante) substitudo
por algo apropriadamente geral (como uma varivel ou um parmetro). Generalizaes do maior versatilidade
ao cdigo, maior possibilidade de reuso, e em algumas situaes at mesmo maior facilidade para escrev-lo.

8.9. 6.9 Funes 63


Aprenda Computao com Python Documentation, Verso 1.1

plano de desenvolvimento (development plan) um processo definido para desenvolvimento de um programa. Neste
captulo, ns demonstramos um estilo de desenvolvimento baseado em escrever cdigo para executar tarefas
simples e especficas, usando encapsulamento e generalizao.

64 Captulo 8. Captulo 6: Iterao


CAPTULO 9

Captulo 7: Strings

Tpicos
Captulo 7: Strings
7.1 Um tipo de dado composto
7.2 Comprimento
7.3 Travessia e o loop for
7.4 Fatias de strings
7.5 Comparao de strings
7.6 Strings so imutveis
7.7 Uma funo find (encontrar)
7.8 Iterando e contando
7.9 O mdulo string
7.10 Classificao de caracteres
7.11 Glossrio
7.11 Glossrio2

9.1 7.1 Um tipo de dado composto

At aqui, vimos trs diferentes tipos de dado: int, float e string. Strings so qualitativamente diferentes dos
outros dois tipos porque so feitas de pedaos menores - caracteres.
Tipos que consistem de pedaos menores so chamados tipos de dados compostos. Dependendo do que estejamos
fazendo, pode ser que precisemos tratar um tipo de dado composto como uma coisa nica, ou pode ser que queiramos
acessar suas partes. Esta ambigidade til.
O operador colchete seleciona um nico caractere de uma string.:
>>> fruta = "banana"
>>> letra = fruta[1]
>>> print letra

A expresso fruta[1] seleciona o caractere nmero 1 de fruta. A varivel letra referencia ou refere-se ao
resultado da expresso. Quando exibimos letra, temos uma surpresa:

65
Aprenda Computao com Python Documentation, Verso 1.1

A primeira letra de "banana" no a. A menos que voc seja um cientista da computao. Neste caso, voc
deve entender a expresso dentro dos colchetes como um deslocamento (offset,) a partir do comeo da string, e o
deslocamento da primeira letra zero. Assim, b a 0 (zero-sima) letra de "banana", a a 1 (um-sima,
diferente de primeira), e n a 2 (dois-sima, diferente de segunda) letra.
Para pegar a primeira letra de uma string, voc simplesmente pe 0, ou qualquer expresso que resulte o valor 0, dentro
dos colchetes:
>>> letra = fruta[0]
>>> print letra
b

A expresso entre colchetes chamada de ndice. Um ndice especifica um membro de um conjunto ordenado, neste
caso o conjunto de caracteres da string. O ndice indica aquele membro que voc quer, da seu nome. Ele pode ser
qualquer expresso inteira.

9.2 7.2 Comprimento

A funo len retorna o nmero de caracteres de uma string:


>>> fruta = "banana"
>>> len(fruta)
6

Para pegar a ltima letra de uma string, voc pode ficar tentado a fazer alguma coisa assim:
comprimento = len(fruta)
ultima = fruta[comprimento] # ERRO!

No vai funcionar. Isto vai causar o seguinte erro em tempo de execuo (runtime error): IndexError: string
index out of range. (ErroDeIndice: ndice da string fora do intervalo). A razo que no existe 6 letra em
"banana". J que comeamos a contar do zero, as seis letras so numeradas de 0 a 5. Para pegar o ltimo caractere,
temos que subtrair 1 de comprimento:
comprimento = len(fruta)
ultima = fruta[comprimento-1]

Como alternativa, podemos usar ndices negativos, os quais contam de trs pra frente os elementos da string. A
expresso fruta[-1] resulta a ltima letra, fruta[-2] resulta a penltima (a segunda de trs para frente), e
assim por diante.

9.3 7.3 Travessia e o loop for

Vrias computaes envolvem o processamento de uma string um caractere de cada vez. Muitas vezes elas comeam
com o primeiro, selecionam um de cada vez, fazem alguma coisa com ele, e continuam at o fim. Este padro de
processamento chamado uma travessia (traversal, com a idia de percorrimento). Uma maneira de codificar uma
travessia com um comando while:
indice = 0
while indice < len(fruta):
letra = fruta[indice]
print letra
indice = indice + 1

66 Captulo 9. Captulo 7: Strings


Aprenda Computao com Python Documentation, Verso 1.1

Este loop percorre a string e exibe cada letra em sua prpria linha. A condio do loop indice < len(fruta),
assim, quando ndice igual ao comprimento da string, a condio se torna falsa, e o corpo do loop no executado.
O ltimo caractere acessado aquele com o ndice len(fruta)-1, que vem a ser o ltimo caractere da string.
Como um exerccio, escreva uma funo que tome uma string como argumento e devolva suas letras de
trs para frente, uma por linha.
Usar um ndice para percorrer um conjunto de valores to comum que Python oferece uma sintaxe alternativa
simplificada - o loop for:
for char in fruta:
print char

A cada vez atravs do loop, o prximo caractere da string atribudo varivel char. O loop continua at que no
reste mais caracteres.
O exemplo seguinte mostra como usar concatenao e um loop for para gerar uma srie abecedrio. Abecedrio
se refere a uma srie ou lista na qual os elementos aparecem em ordem alfabtica. Por exemplo, no livro de Robert
McCloskeys Make Way for Ducklings, os nomes dos ducklings so Jack, Kack, Lack, Mack, Nack, Ouack, Pack e
Quack. O loop seguinte, produz como sada aqueles nomes, em ordem:
prefixos = "JKLMNOPQ"
sufixo = "ack"

for letra in prefixos:


print letra + sufixo

A sada deste programa :


Jack
Kack
Lack
Mack
Nack
Oack
Pack
Qack

Naturalmente, esta sada no est cem por cento certa porque Ouack e Quack esto escritos de maneira errada.
Como um exerccio, modifique o programa para corrigir este erro.

9.4 7.4 Fatias de strings

Um segmento de uma string chamado de uma fatia. Selecionar uma fatia similar a selecionar um caractere:
>>> s = "Pedro, Paulo e Maria"
>>> print s[0:5]
Pedro
>>> print s[7:12]
Paulo
>>> print s[16:21]
Maria

O operador [n:m] retorna a parte da string do n-simo caractere ao m-simo caractere, incluindo o primeiro mas
excluindo o ltimo. Este comportamento no intuitivo; ele faz mais sentido se voc imaginar os ndices apontando
para os intervalos entre os caracteres, como no seguinte diagrama:

9.4. 7.4 Fatias de strings 67


Aprenda Computao com Python Documentation, Verso 1.1

Se voc omitir o primeiro ndice (antes dos dois pontos :), a fatia comea do incio da string. Se voc omitir o
segundo ndice, a fatia vai at o final da string. Assim:
>>> fruta = "banana"
>>> fruta[:3]
ban
>>> fruta[3:]
ana

O que voc acha de s[:] significa?

9.5 7.5 Comparao de strings

O operador de comparao funciona com strings. Para ver se duas strings so iguais:
if palavra == "banana":
print "Sim, ns no temos bananas!"

Outras operaes de comparao so teis para colocar palavras em ordem alfabtica:


if palavra < "banana":
print "Sua palavra," + palavra + ", vem antes de banana."
elif palavra > "banana":
print "Sua palavra," + palavra + ", vem depois de banana."
else:
print "Sim, ns no temos bananas!"

Entretanto, voc deve atentar para o fato de que Pyhton no manipula letras maisculas e minsculas da mesma
maneira que as pessoas o fazem. Todas as letras maisculas vm antes das minsculas. Como resultado:
Sua palavra, Zebra, vem antes de banana.

Uma maneira comum de resolver este problema converter as strings para um formato padro, seja todas minsculas,
ou todas maisculas, antes de realizar a comparao. Um problema mais difcil fazer o programa perceber que zebras
no so frutas.

9.6 7.6 Strings so imutveis

tentador usar o operador [] no lado esquerdo de uma expresso de atribuio, com a inteno de alterar um caractere
em uma string. Por exemplo:
saudacao = "Al, mundo!"
saudacao[0] = E # ERRO!
print saudacao

68 Captulo 9. Captulo 7: Strings


Aprenda Computao com Python Documentation, Verso 1.1

Em vez de produzir a sada El, Mundo!, este cdigo produz o erro em tempo de execuo (runtime error):
TypeError: object doesnt support item assignment (ErroDeTipo: objeto no d suporte
atribuio de item.)
Strings so imutveis, o que significa que voc no pode mudar uma string que j existe. O melhor que voc pode
fazer criar uma nova string que seja uma variao da original:
saudacao = "Al, mundo!"
novaSaudacao = E + saudacao[1:]
print novaSaudacao

A soluo aqui concatenar uma nova primeira letra com uma fatia de saudacao. Esta operao no tem nenhum
efeito sobre a string original.

9.7 7.7 Uma funo find (encontrar)

O que faz a seguinte funo?:


def find(str, ch):
indice = 0
while indice < len(str):
if str[indice] == ch:
return indice
indice = indice + 1
return -1

Num certo sentido, find (encontrar) o oposto do operador []. Em vez de pegar um ndice e extrair o caractere
correspondente, ela pega um caractere e encontra (finds) em qual ndice aquele caractere aparece. Se o caractere no
encontrado, a funo retorna -1.
Este o primeiro exemplo que vemos de uma instruo return dentro de um loop. Se str[indice] == ch, a
funo retorna imediatamente, abandonando o loop prematuramente.
Se o caractere no aparece na string, ento o programa sai do loop normalmente e retorna -1.
Este padro de computao s vezes chamado de travessia eureka, porque to logo ele encontra (find) o que est
procurando, ele pode gritar Eureka! e parar de procurar.
Como um exerccio, modifique a funo find (encontrar) de modo que ela receba um terceiro parmetro,
o ndice da string por onde ela deve comear sua procura.

9.8 7.8 Iterando e contando

O programa seguinte conta o nmero e vezes que a letra a aparece em uma string:
fruta = "banana"
contador = 0
for letra in fruta:
if letra == a:
contador = contador + 1
print contador

Este programa demonstra um outro padro de computao chamado de contador. A varivel contador inicializada
em 0 e ento incrementada cada vez que um a encontrado. (Incrementar o mesmo que aumentar em um; o
oposto de decrementar, e no tem relao com excremento, que um substantivo.) Quando se sai do loop, contador
guarda o resultado - o nmero total de as.

9.7. 7.7 Uma funo find (encontrar) 69


Aprenda Computao com Python Documentation, Verso 1.1

Como um exerccio, encapsule este cdigo em uma funo chamada contaLetras, e generalize-a de
modo que possa aceitar uma string e uma letra como parmetros.
Como um segundo exerccio, reescreva esta funo de modo que em vez de percorrer a string, ela use a
verso com trs parmetros de find (encontrar) da seo anterior.

9.9 7.9 O mdulo string

O mdulo string contm funes teis que manipulam strings. Conforme usual, ns temos que importar o mdulo
antes que possamos utiliz-lo:
>>> import string

O mdulo string inclui uma funo chamada find (encontrar) que faz a mesma coisa que a funo que escrevemos.
Para cham-la, temos que especificar o nome do mdulo e o nome da funo usando a notao de ponto.:
>>> fruta = "banana"
>>> indice = string.find(fruta, "a")
>>> print indice
1

Este exemplo demonstra um dos benefcios dos mdulos - eles ajudam a evitar colises entre nomes de funes
nativas e nomes de funes definidas pelo usurio. Usando a notao de ponto podemos especificar que verso de
find (encontrar) ns queremos.
De fato, string.find mais generalizada que a nossa verso. Primeiramente, ela pode encontrar substrings, no
apenas caracteres:
>>> string.find("banana", "na")
2

Alm disso, ela recebe um argumento adicional que especifica o ndice pelo qual ela deve comear sua procura:
>>> string.find("banana", "na", 3)
4

Ou ela pode receber dois argumentos adicionais que especificam o intervalo de ndices:
>>> string.find("bob", "b", 1, 2)
-1

Neste exemplo, a busca falha porque a letra b no aparece no intervalo entre 1 e 2 (no incluindo o 2) do ndice.

9.10 7.10 Classificao de caracteres

Muitas vezes til examinar um caractere e testar se ele maisculo ou minsculo, ou se ele um caractere ou um
dgito. O mdulo string oferece vrias constantes que so teis para esses propsitos.
A string string.lowercase contm todas as letras que o sistema considera como sendo minsculas. Similar-
mente, string.uppercase contm todas as letras maisculas. Tente o seguinte e veja o que voc obtm:
>>> print string.lowercase
>>> print string.uppercase
>>> print string.digits

Ns podemos usar essas constantes e find (encontrar) para classificar caracteres. Por exemplo, se
find(lowercase, ch) retorna um valor outro que no -1, ento ch deve ser minsculo:

70 Captulo 9. Captulo 7: Strings


Aprenda Computao com Python Documentation, Verso 1.1

def eMinusculo(ch):
return string.find(string.lowercase, ch) != -1

Como uma alternativa, podemos tirar vantagem do operador in, que determina se um caractere aparece em uma string:
def eMinusculo(ch):
return ch in string.lowercase

Ainda, como uma outra alternativa, podemos usar o operador de comparao:


def eMinusculo(ch):
return a <= ch <= z

Se ch estiver entre a e z, ele deve ser uma letra minscula.


Como um exerccio, discuta que verso de eMinusculo voc acha que ser a mais rpida. Voc pode
pensar em outras razes alm da velocidade para preferir uma em vez de outra?
Outra constante definida no mdulo string pode te surpreender quando voc executar um print sobre ela:
>>> print string.whitespace

Caracteres de espaamento (ou espaos em branco) movem o cursor sem imprimir qualquer coisa. Eles criam
os espaos em branco entre os caracteres visveis (pelo menos numa folha de papel branco). A string constante
string.whitespace contm todos os caracteres de espaamento, incluindo espao, tabulao (\t) e nova linha
(\n).
Existem outras funes teis no mdulo string, mas este livro no pretende ser um manual de referncia. Por outro
lado, Python Library Reference exatamente isto. Em meio a uma abundante documentao, ele est disponvel no
site da web do Python, www.python.org.

9.11 7.11 Glossrio

tipo de dado composto (compound data type) Um tipo de dado no qual o valor consiste de componentes, ou elemen-
tos, que so eles mesmos valores.
travessia (traverse) Iterar atravs dos elementos de um conjunto, realizando uma operao similar em cada um deles.
ndice (index) Uma varivel ou valor usados para selecionar um membro de um conjunto ordenado, como um carac-
tere em uma string.
fatia (slice) Uma parte de uma string especificada por um intervalo de ndices.
mutvel (mutable) Um tipo de dado composto a cujos elementos podem ser atribudos novos valores.
contador (counter) Uma varivel utilizada para contar alguma coisa, usualmente inicializada em zero e ento incre-
mentada.
incrementar (increment) aumentar o valor de uma varivel em 1.
decrementar (decrement) diminuir o valor de uma varivel em 1.
espaamento (whitespace) Qualquer um dos caracteres que move o cursor sem imprimir caracteres visveis. A con-
stante string.whitespace contm todos os caracteres de espaamento.

9.11. 7.11 Glossrio 71


Aprenda Computao com Python Documentation, Verso 1.1

9.12 7.11 Glossrio2

tipo de dado composto (compound data type) Um tipo de dado em que os valores so compostos de componentes,
ou elementos, que podem ser tratados como valores separados.
atravessar (traverse) Iterar atravs dos elementos definidos, executando uma operao similar em cada.
ndice (index) Uma varivel ou valor usado para selecionar um membro de uma definio ordenada, como um carac-
tere de uma string.
fatia (slice) Uma parte da string especificada por um intervalo de ndice.
mutvel (mutable) Um tipo de dado composto do qual elementos podem atribuir novos valores.
contador (counter) Uma varivel usada para contar alguma coisa, geralmente iniciada em zero e incrementada.
incremento (increment) Para aumentar o valor da varivel.
decremento (decrement) Para dimiuir o valor da varivel.
espao em branco (whitespace) Qualquer caractere que move o cursor sem imprimir caracteres visveis. A constante
string.whitespace contm todos os caracteres de espao em branco.

72 Captulo 9. Captulo 7: Strings


CAPTULO 10

Captulo 8: Listas

Tpicos
Captulo 8: Listas
8.1 Valores da lista
8.2 Acessado elementos
8.3 Comprimento da lista
8.4 Membros de uma lista
8.5 Listas e laos for
8.6 Operaes em listas
8.7 Fatiamento de listas
8.8 Listas so mutveis
8.9 Remoo em lista
8.10 Ojetos e valores
8.11 Apelidos
8.12 Clonando listas
8.13 Lista como parmetro
8.14 Lista aninhadas
8.15 Matrizes
8.16 Strings e listas
8.17 Glossrio
Outros termos utilizados neste captulo

Uma lista um conjunto ordenado de valores, onde cada valor identificado por um ndice. Os valores que compem
uma lista so chamados elementos. Listas so similares a strings, que so conjuntos ordenados de caracteres, com a
diferena que os elementos de uma lista podem possuir qualquer tipo. Listas e strings XXX e outras coisas que se
comportam como conjuntos ordenados XXX so chamados seqncias.

10.1 8.1 Valores da lista

Existem vrias maneiras de criar uma nova lista; a mais simples envolver os elementos em colchetes ([ e ]):
>>> [10, 20, 30, 40]
>>> [spam, bungee, swallow]

73
Aprenda Computao com Python Documentation, Verso 1.1

O primeiro exemplo uma lista de quatro inteiros. O segundo uma lista de trs strings. Os elementos de uma lista
no necessitam ser do mesmo tipo. A lista a seguir contm uma string, um valor float, um valor inteiro, e mirabile
dictu uma outra lista:
>>> [alo, 2.0, 5, [10,20]]

Uma lista dentro de outra lista dita estar aninhada.


Listas que contm inteiros consecutivos so comuns, ento Python fornece uma maneira simples de cri-los:
>>> range(1,5)
[1, 2, 3, 4]

A funo range pega dois argumentos e devolve uma lista que contm todos os inteiros do primeiro at o segundo,
incluindo o primeiro mas no incluindo o segundo!
Existem outras formas de range. Com um argumento simples, ela cria uma lista que inicia em 0:
>>> range(10)
[0,1, 2, 3, 4, 5, 6, 7, 8, 9]

Se existe um terceiro argumento, ele especifica o espao entre os valores sucessivos, que chamado de tamanho do
passo. Este exemplo conta de 1 at 10 em passos de 2:
>>> range(1, 10, 2)
[1, 3, 5, 7, 9]

Finalmente, existe uma lista especial que no contm elementos. Ela chamada lista vazia, e sua notao [].
Com todas estas formas de criar listas, seria decepcionante se no pudssemos atribuir valores de listas a variveis ou
passar listas como parmetros a funes. Felizmente, podemos.
>>> vocabulario = [melhorar, castigar, defenestrar]
>>> numeros = [17, 123]
>>> vazio = []
>>> print vocabulario, numeros, vazio
[melhorar, castigar, defenestrar] [17, 123] []

10.2 8.2 Acessado elementos

A sintaxe para acessar os elementos de uma lista a mesma que a sintaxe para acessar os caracteres de uma string XXX
o operator colchete ([]). A expresso dentro dos colchetes especifica o ndice. Lembre-se que os ndices iniciam em
0:
>>> print numeros[0]
>>> numeros[1]= 5

O operador colchete pode aparecer em qualquer lugar em uma expresso. Quando ele aparece no lado esquerdo de
uma atribuio, ele modifica um dos elementos em uma lista, de forma que o um-simo elemento de numeros, que
era 123, agora 5.
Qualquer expresso inteira pode ser utilizada como um ndice:
>>> numeros[3-2]
5
>>> numeros[1.0]
TypeError: sequence index must be integer

Se voc tentar ler ou escrever um elemento que no existe, voc recebe um erro de tempo de execuo (runtime error):

74 Captulo 10. Captulo 8: Listas


Aprenda Computao com Python Documentation, Verso 1.1

>>> numeros[2]=5
IndexError: list assignment index out of range

Se um ndice possui um valor negativo, ele conta ao contrrio a partir do final da lista:
>>> numeros[-1]
5
>>> numeros[-2]
17
>>> numeros[-3]
IndexError: list index out of range

numeros[-1] o ltimo elemento da lista, numeros[-2] o penltimo e numeros[-3] no existe.


comum utilizar uma varivel de lao como um ndice da lista:
>>> cavaleiros = [guerra, fome, peste, morte]
i = 0
while i < 4:
print cavaleiros[i]
i = i + 1

Este lao while conta de 0 at 4. Quando a varivel do lao i 4, a condio falha e o lao se encerra. Desta forma
o corpo do lao executado somente quando i 0, 1, 2 e 3.
Em cada vez dentro do lao, a varivel i utilizada como um ndice para a lista, exibindo o i-simo elemento. Este
padro de computao chamado de percurso na lista.

10.3 8.3 Comprimento da lista

A funo len devolve o comprimento de uma lista. uma boa idia utilizar este valor como o limite superior de um
lao ao invs de uma constante. Desta forma, se o tamanho da lista mudar, voc no precisar ir atravs de todo o
programa modificando todos os laos; eles funcionaro corretamente para qualquer tamanho de lista:
>>> cavaleiros = [guerra, fome, peste, morte]
i = 0
while i < len(cavaleiros):
print cavaleiros[i]
i = i + 1

A ltima vez que o corpo do lao executado, i len(cavaleiros) - 1, que o ndice do ltimo elemento.
Quando i igual a len(cavaleiros), a condio falha e o corpo no executado, o que uma boa coisa, porque
len(cavaleiros) no um ndice legal.
Embora uma lista possa conter uma outra lista, a lista aninhada ainda conta como um elemento simples. O compri-
mento desta lista quatro:
>>> [spam!, 1, [Brie, Roquefort, Pol l Veq], [1, 2 3]]

Como um exerccio, escreva um lao que percorra a lista anterior e exiba o comprimento de cada elemento.
O que acontece se voc manda um inteiro para len?

10.4 8.4 Membros de uma lista

in um operador lgico que testa se um elemento membro de uma seqncia. Ns o utilizamos na Seo 7.10
com strings, mas ele tambm funciona com listas e outras seqncias:

10.3. 8.3 Comprimento da lista 75


Aprenda Computao com Python Documentation, Verso 1.1

>>> cavaleiros = [guerra, fome, peste, morte]


>>> peste in cavaleiros
True
>>> depravao in cavaleiros
False

Uma vez que peste um membro da lista cavaleiros, o operador in devolve verdadeiro. Uma vez que
depravao no est na lista, in devolve falso.
Podemos utilizar tambm o not em combinao com o in para testar se um elemento no um membro de uma lista:
>>> depravao not in cavaleiros
True

10.5 8.5 Listas e laos for

O lao for que vimos na Seo 7.3 tambm funciona com listas. A sintaxe generalizada de um lao for :
for VARIAVEL in LISTA:
CORPO

Esta declarao equivalente a:


>>> i = 0
>>> while i < len(LISTA):
>>> VARIAVEL = LISTA[i]
>>> XXX BODY
>>> i = i + 1

O lao for mais conciso porque podemos eliminar a varivel do lao, i. Aqui est o lao anterior escrito com
umlao for:
>>> for cavaleiro in cavaleiros:
print cavaleiro

Quase se l como Portugus: For (para cada) cavaleiro in (na lista de) cavaleiros, print (imprima o nome do) cav-
aleiro.
Qualquer expresso de lista pode ser utilizada num lao for:
>>> for numero in range(20):
if numero % 2 == 0:
print numero

>>> for fruta in ["banana", "abacaxi", "laranja"]:


print "Eu gosto de comer " + fruta + "s!"

O primeiro exemplo exibe todos os nmeros pares entre zero e dezenove. O segundo exemplo expressa o entusiasmo
por vrias frutas.

10.6 8.6 Operaes em listas

O operador + concatena listas:

76 Captulo 10. Captulo 8: Listas


Aprenda Computao com Python Documentation, Verso 1.1

>>> a = [1, 2, 3]
>>> b = [4, 5, 6]
>>> c = a + b
>>> print c
[1, 2, 3, 4, 5, 6]

Similarmente, o operador * repete uma lista um nmero dado de vezes:


>>> [0] * 4
[0, 0, 0, 0]
>>> [1, 2, 3] * 3
[1, 2, 3, 1, 2, 3, 1, 2, 3]

O primeiro exemplo repete [0] quatro vezes. O segundo exemplo repete a lista [1, 2, 3] trs vezes.

10.7 8.7 Fatiamento de listas

A operao de fatiamento que vimos na Seo 7.4 tambm funciona sobre listas:
>>> lista = [a, b, c, d, e, f]
>>> lista[1:3]
[b, c]
>>> lista[:4]
[a, b, c, d]
>>> lista[3:]
[d, e, f]
>>> lista[:]
[a, b, c, d, e, f]

10.8 8.8 Listas so mutveis

Diferente das strings, as listas so mutveis, o que significa que podemos modificar seus elementos. Utilizando o
operador colchete no lado esquerdo de uma atribuio, podemos atualizar um de seus elementos:
>>> fruta = ["banana", "abacaxi", "laranja"]
>>> fruta[0] = "abacate"
>>> fruta[-1] = "tangerina"
>>> print fruta
[abacate, abacaxi, tangerina]

Com o operador de fatiamento podemos atualizar vrios elementos de uma vez:


>>> lista = [a, b, c, d, e, f]
>>> lista[1:3] = [x, y]
>>> print lista
[a, x, y, d, e, f]

Tambm podemos remover elementos de uma lista atribuindo a lista vazia a eles:
>>> lista = [a, b, c, d, e, f]
>>> lista[1:3] = []
>>> print lista
[a, d, e, f]

E podemos adicionar elementos a uma lista enfiando-os numa fatia vazia na posio desejada:

10.7. 8.7 Fatiamento de listas 77


Aprenda Computao com Python Documentation, Verso 1.1

>>> lista = [a, d, f]


>>> lista[1:1] = [b, c]
>>> print lista
[a, b, c, d, f]
>>> lista[4:4] = [e]
>>> print lista
[a, b, c, d, e, f]

10.9 8.9 Remoo em lista

Utilizando fatias para remover elementos pode ser complicado, e desta forma propenso a erro. Python fornece uma
alternativa que mais legvel.
del remove um elemento de uma lista:
>>> a = [um, dois, tres]
>>> del a[1]
>>> a
[um, tres]

Como voc deveria esperar, del trata valores negativos e causa erros de tempo de execuo se o ndice estiver fora da
faixa.
Voc tambm pode utilizar uma faixa como um ndice para del:
>>> lista = [a, b, c, d, e, f]
>>> del lista[1:5]
>>> print lista
[a, f]

Como de costume, fatias selecionam todos os elementos at, mas no incluindo, o segundo ndice.

10.10 8.10 Ojetos e valores

Se executamos estas declaraes de atribuio:


>>> a = "banana"
>>> b = "banana"

sabemos que a e b se referem a uma string com as letras banana. Mas no podemos dizer se elas apontam para a
mesma string.
Existem dois possveis estados:

Em um caso, a e b se referem a duas coisas diferentes que possuem o mesmo valor. No segundo caso, elas se referem
mesma coisa. Estas coisas possume nomes - elas so chamadas objetos. Um objeto algo ao qual uma varivel
pode se referenciar.

78 Captulo 10. Captulo 8: Listas


Aprenda Computao com Python Documentation, Verso 1.1

Todo objeto possui um identificador nico, que podemos obter com a funo id. Exibindo o identificador de a e b,
podemos dizer se elas se referem ao mesmo objeto.
>>> id(a)
135044008
>>> id(b)
135044008

De fato, obtivemos o mesmo identificador duas vezes, o que significa que Python criou apenas uma string, e tanto a
quanto b se referem a ela.
Interessantemente, listas se comportam de forma diferente. Quando criamos duas listas, obtemos dois objetos:
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a)
135045528
>>> id(b)
135041704

Ento o diagrama de estado fica assim:

a e b possuem o mesmo valor mas no se referem ao mesmo objeto.

10.11 8.11 Apelidos

Uma vez que variveis se referem a objetos, se atribuimos uma varivel a uma outra, ambas as variveis se referem ao
mesmo objeto:
>>> a = [1, 2, 3]
>>> b = a

Neste caso, o diagrama de estado se parece com isto:

Uma vez que a lista possui dois nomes diferentes, a e b, dizemos que ela est apelidada (aliased). Mudanas feitas
em um apelido afetam o outro nome:
>>> b[0] = 5
>>> print a
[5, 2, 3]

10.11. 8.11 Apelidos 79


Aprenda Computao com Python Documentation, Verso 1.1

Embora este comportamento possa ser til, ele s vezes inesperado e indesejado. Em geral, mais seguro evitar os
apelidos quando voc est trabalhando com objetos mutveis. claro, para objetos imutveis, no h problema. por
isto que Python livre para apelidar cadeias de caracteres quando v uma oportunidade de economizar.

10.12 8.12 Clonando listas

Se queremos modificar uma lista e tambm manter uma cpia da original, preciamos ter condies de fazer uma
cpia da prpria lista, no apenas uma referncia. Este processo algumas vezes chamado clonagem, para evitar a
ambigidade da palavra cpia.
A maneira mas fcil de clonar uma lista utilizar o operador de fatia:
>>> a = [1, 2, 3]
>>> b = a[:]
>>> print b
[1, 2, 3]

Pegar qualquer fatia de a cria uma nova lista. Neste caso acontece da fatia consistir da lista inteira.
Agora estamos livres para fazer alteraes a b sem nos preocuparmos coma:
>>> b[0] = 5
>>> print a
[1, 2, 3]

Como exerccio, desenhe um diagrama de estado paraa e b antes e depois desta mudana.

10.13 8.13 Lista como parmetro

Passar uma lista como um argumento passa realmente uma referncia lista, no uma cpia da lista. Por exemplo, a
funo cabeca pega uma lista como parmetro e devolve a cabea da lista, ou seja, seu primeiro elemento:
>>> def cabeca(lista):
return lista[0]

Eis como ela utilizada:


>>> numeros = [1, 2, 3]
>>> cabeca(numeros)
1

O parmetro lista e a varivel numeros so apelidos para o mesmo objeto. O diagrama de estado se parece com
isto:

Uma vez que o objeto compartilhado pelos dois quadros, o desenhamos entre eles.

80 Captulo 10. Captulo 8: Listas


Aprenda Computao com Python Documentation, Verso 1.1

Se a funo modifica um parmetro da lista, a funo chamadora v a mudana. Por exemplo, removeCabeca
remove o primeiro elemento da lista:
>>> def removecabeca(lista):
del lista[0]

Aqui est a maneira como ela utilizada:


>>> numeros = [1, 2, 3]
>>> removeCabeca(numeros)
>>> print numeros
[2, 3]

Se uma funo devolve uma lista, ela devolve uma referncia lista. Por exemplo, cauda devolve uma lista que
contm todos menos o primeiro elemento de uma determinada lista:
>>> def cauda(lista):
return lista[1:]

Aqui est a maneira como ela utilizada:


>>> numeros = [1, 2, 3]
>>> resto = cauda(numeros)
>>> print resto
[2, 3]

Uma vez que o valor de retorno foi criado com o operador de fatia, ele uma nova lista. A criao de resto, e
qualquer alterao subseqente a resto, no tem efeito sobre numeros.

10.14 8.14 Lista aninhadas

Uma lista aninhada uma lista que aparece como um elemento de uma outra lista. Nesta lista, o terceiro elemento
uma lista aninhada:
>>> lista = ["alo", 2.0, 5, [10, 20]]

Se exibimos lista[3], obtemos [10, 20]. Para extrairmos um elemento de uma lista aninhada, podemos agir
em duas etapas:
>>> elem = lista[3]
>>> elem[0]
10

Ou podemos combin-las:
>>> lista[3][1]
20

Os operadores colchete avaliam da esquerda para a direita, ento a expresso pega o terceiro elemento de lista e
extrai o primeiro elemento dela.

10.15 8.15 Matrizes

Listas aninhadas so freqentemente utilizadas para representar matrizes. Por exemplo, a matriz:

10.14. 8.14 Lista aninhadas 81


Aprenda Computao com Python Documentation, Verso 1.1

poderia ser representada como:


>>> matriz = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]

matriz uma lista com trs elementos, onde cada elemento uma linha da matriz. Podemos selecionar uma linha
inteira da matriz da maneira habitual:
>>> matriz[1]
[4, 5, 6]

Ou podemos extrair um nico elemento da matriz utilinado a forma de duplo ndice:


>>> matriz[1][1]
5

O primeiro ndice seleciona a linha, e o segundo ndice seleciona a coluna. Embora esta maneira de representar
matrizes seja comum, ela no a nica possibilidade. Uma pequena variao utilizar uma lista de colunas ao invs
de uma lista de linhas.
Mais adiante veremos uma alternativa mais radical utilizando um dicionrio.

10.16 8.16 Strings e listas

Duas das mais teis funes no mdulo string envolvem listas de strings. A funo split (separar) quebra uma
string em uma lista de palavras. Por padro, qualquer nmero de caracteres espao em branco considerado um limite
de uma palavra:
>>> import string
>>> poesia = "O orvalho no carvalho..."
>>> string.split(poesia)
[O, orvalho, no, carvalho...]

Um argumento opcional chamado um delimitador pode ser utilizado para especificar qual caracter utilizar como
limites da palavra. O exemplo a seguir utiliza a string va:
>>> string.split(poesia, va)
[O or, lho no car, lho...]

Perceba que o delimitador no aparece na lista.


A funo join (juntar) o inverso de split. Ela pega uma lista de strings e concatena os elementos com um espao
entre cada par:
>>> lista = [O, orvalho, no, carvalho...]
>>> string.join(lista)
O orvalho no carvalho...

Como split, join recebe um delimitador que inserido entre os elementos:


>>> string.join(lista, _)
O_orvalho_no_carvalho...

82 Captulo 10. Captulo 8: Listas


Aprenda Computao com Python Documentation, Verso 1.1

Como um execcio, descreva o relacionamento entre string.join(string.split(poesia)) e


poesia. Eles so o mesmo para qualquer string? Quando eles seriam diferentes?

10.17 8.17 Glossrio

lista (list) Uma coleo denominada de objetos, onde cada objeto identificado por um ndice.
ndice (index) Uma varivel inteira ou valor que indica um elemento de uma lista.
elemento (element) Um dos valores em uma lista(ou outra seqncia). O operador colchete seleciona elementos de
uma lista.
seqncia (sequence) Qualquer um dos tipos de dados que consiste de um conjunto ordenado de elementos, com
cada elemento identificado por um ndice.
lista aninhada (nested list) Uma lista que um elemento de uma outra lista.
percurso na lista (list traversal) O acesso seqencial de cada elemento em uma lista.
objeto (object) Um coisa a qual uma varivel pode se referir.
apelidos (aliases) Mltiplas variveis que contm referncias ao mesmo objeto.
clonar (clone) Criar um novo objeto que possui o mesmo valor de um objeto existente. Copiar a referncia a um
objeto cria um apelido (alias) mas no clona o objeto.
delimitador (delimiter) Um caracter uma string utilizados para indicar onde uma string deveria ser dividida(split).

10.18 Outros termos utilizados neste captulo

(XXX esta lista deve ser retirada na verso final)


XXX has, have possuir (ter?)
XXX there is, there are existir (haver?)
XXX use utilizar (usar?)
XXX string Utilizei string em itlico, por ser tratar de um termo que no em portugus.
XXX enclose envolver???
XXX provide fornecer
XXX return devolve
XXX denoted denotada XXX
XXX disappointing decepcionante (desapontador?)
XXX assign atribuir
XXX change modificar
XXX length comprimento (tamanho?)
XXX print exibir (imprimir?)
XXX membership No creio que exista uma palavra que traduza este termo. Pelo menos em ingls no encontrei
nenhum sinnimo. Vou tentar traduzir explicando o termo dependendo do contexto.
XXX boolean lgico (booleano?)

10.17. 8.17 Glossrio 83


Aprenda Computao com Python Documentation, Verso 1.1

XXX handle tratar


XXX proceed agir
XXX By default por padro
XXX notice perceber (observar?)
XXX mirabile dictu Algum tem idia do que significa isto? Meu latim no chegou l. :)
XXX traduzir os exemplos? considero melhor fazer a traduzir os exemplos sempre que possvel. S no gostaria
de tirar o esprito que levou o autor a utilizar tais exemplos. Podem haver trocadilhos, homenagens e outros
sentimentos no autor que no devemos retirar. Desta forma, estou traduzindo todos os termos que consigo
entender e encontrar palavras que exprimam a idia. Nos demais, estou mantendo os termos originais para uma
discusso futura.

84 Captulo 10. Captulo 8: Listas


CAPTULO 11

Captulo 9: Tuplas

Tpicos
Captulo 9: Tuplas
9.1 Mutabilidade e tuplas
9.2 Atribuies de tupla
9.3 Tuplas como valores de retorno
9.4 Nmeros aleatrios
9.5 Lista de nmeros aleatrios
9.6 Contando
9.7 Vrios intervalos
9.8 Uma soluo em um s passo
9.9 Glossrio

11.1 9.1 Mutabilidade e tuplas

At agora, voc tem visto dois tipos compostos: strings, que so compostos de caracteres; e listas, que so com-
postas de elementos de qualquer tipo. Uma das diferenas que notamos que os elementos de uma lista podem ser
modificados, mas os caracteres em uma string no. Em outras palavras, strings so imutveis e listas so mutveis.
H um outro tipo em Python chamado tupla (tuple) que similar a uma lista exceto por ele ser imutvel. Sintatica-
mente, uma tupla uma lista de valores separados por vrgulas:
>>> tupla = a, b, c, d, e

Embora no seja necessrio, convencional colocar tuplas entre parnteses:


>>> tupla = (a, b, c, d, e)

Para criar uma tupla com um nico elemento, temos que incluir uma vrgula final:
>>> t1 = (a,)
>>> type(t1)
<type tuple>

Sem a vrgula, Python entende (a) como uma string entre parnteses:

85
Aprenda Computao com Python Documentation, Verso 1.1

>>> t2 = (a)
>>> type(t2)
<type string>

Questes de sintaxe de lado, as operaes em tuplas so as mesmas operaes das listas. O operador ndice seleciona
um elemento da tupla.
>>> tupla = (a, b, c, d, e)
>>> tupla[0]
a

E o operador slice (fatia) seleciona uma faixa (range) de elementos.


>>> tupla[1:3]
(b, c)

Mas se tentarmos modificar um dos elementos de uma tupla, teremos um erro:


>>> tupla[0] = A
TypeError: object doesnt support item assignment

Naturalmente, mesmo que no possamos modificar os elementos de uma tupla, podemos substitu-la por uma tupla
diferente:
>>> tupla = (A,) + tupla[1:]
>>> tupla
(A, b, c, d, e)

11.2 9.2 Atribuies de tupla

De vez em quando, necessrio trocar entre si os valores de duas variveis. Com operaes de atribuio conven-
cionais, temos que utilizar uma varivel temporria. Por exemplo, para fazer a troca entre a e b:
>>> temp = a
>>> a = b
>>> b = temp

Se voc tiver que fazer isso com frequncia, esta abordagem se torna incmoda. Python fornece uma forma de
atribuio de tupla que resolve esse problema elegantemente:
>>> a, b = b, a

O lado esquedo uma tupla de variveis; o lado direito uma tupla de valores. Cada valor atribudo sua respectiva
varivel. Todas as expresses do lado direito so avaliadas antes de qualquer das atribuies. Esta caracterstica torna
as atribuies de tupla bastante versteis.
Naturalmente, o nmero de variveis na esquerda e o nmero de valores na direita deve ser igual:
>>> a, b, c, d = 1, 2, 3
ValueError: unpack tuple of wrong size

11.3 9.3 Tuplas como valores de retorno

Funes podem retornar tuplas como valor de retorno. Por Exemplo, ns poderamos escrever uma funo que troca
dois parmetros entre si:

86 Captulo 11. Captulo 9: Tuplas


Aprenda Computao com Python Documentation, Verso 1.1

def troca(x, y):


return y, x

Ento ns poderamos atribuir o valor de retorno para uma tupla com duas variveis:
a, b = troca(a, b)

Neste caso, no existe uma grande vantagem em fazer de troca (swap) uma funo. De fato, existe um perigo em
tentar encapsular troca, o qual a tentao de cometer o seguinte erro:
def troca(x, y): # versao incorreta
x, y = y, x

Se ns chamarmos esta funo desta forma:


troca(a, b)

ento a e x so apelidos para um mesmo valor. Mudar x dentro da funo troca, faz com que x se referencie a
um valor diferente, mas sem efeito sobre a dentro de __main__. Do mesmo modo, a mudana em y no tem efeito
sobre b.
Esta funo roda sem produzir uma mensagem de erro, mas ela no faz o que pretendemos. Este um exemplo de um
erro semntico.
Como exerccio, desenhe um diagrama de estado pra esta funo de modo que voc possa ver porque ela
no funciona.

11.4 9.4 Nmeros aleatrios

A maioria dos programas de computador fazem a mesma coisa sempre que so executados, ento, podemos dizer que
eles so determinsticos. Determinismo em geral uma coisa boa, se ns esperamos que um clculo d sempre o
mesmo resultado. Entretanto, para algumas aplicaes queremos que o computador se torne imprevisvel. Jogos so
um exemplo bvio, mas existem outros.
Fazer um programa realmente no-determinstico se mostra no ser to fcil, mas existem maneiras de faz-lo ao
menos parecer no-determinstico. Uma dessas maneiras gerar nmeros aleatrios e us-los para determinar o
resultado de um programa. Python tem uma funo nativa que gera nmeros pseudo aleatrios, os quais no so
verdadeiramente aleatrios no sentido matemtico, mas para os nossos propsitos eles so.
O mdulo random contm uma funo chamada random que retorna um nmero em ponto flutuante (floating-point
number) entre 0.0 e 1.0. Cada vez que voc chama random, voc recebe o prximo nmero de uma longa srie. Para
ver uma amostra, execute este loop:
import random

for i in range(10):
x = random.random()
print x

Para gerar um nmero aleatrio ente 0.0 e um limite superior, digamos superior, multiplique x por superior.
Como exerccio, gere um nmero aleatrio entre inferior e superior.
Como exerccio adicional, gere um nmero inteiro aleatrio entre inferior e superior, inclusive os dois
extremos.

11.4. 9.4 Nmeros aleatrios 87


Aprenda Computao com Python Documentation, Verso 1.1

11.5 9.5 Lista de nmeros aleatrios

O primeiro passo gerar uma lista aleatria de valores. listaAleatoria pega um parmetro inteiro e retorna uma
lista de nmeros aleatrios com o comprimento dado. Inicia-se com uma lista de n zeros. A cada iterao do loop, ele
substitui um dos elementos por um nmero aleatrio. O valor retornado uma referncia para a lista completa:
def listaAleatoria(n):
s = [0] * n
for i in range(n):
s[i] = random.random()
return s

Vamos realizar um teste desta funo com uma lista de oito elementos. Para efeitos de depurao, uma boa idia
comear com uma lista pequena.
>>> listaAleatoria(8)
0.15156642489
0.498048560109
0.810894847068
0.360371157682
0.275119183077
0.328578797631
0.759199803101
0.800367163582

Os nmeros gerados por random so supostamente uniformemente distribudos, o que significa que cada valor tem
uma probabilidade igual de acontecer.
Se ns dividirmos a faixa de valores possveis em intervalos do mesmo tamanho, e contarmos o nmero de vezes que
um determinado valor aleatrio caiu em seu respectivo intervalo, ns devemos obter o mesmo nmero aproximado de
valores em cada um dos intervalos.
Ns podemos testar esta teoria escrevendo um programa que divida a faixa de valores em intervalos e conte o nmero
de valores de cada intervalo.

11.6 9.6 Contando

Uma boa maneira de abordar problemas como esse dividir o problema em subproblemas, e encontrar um subproblema
que se enquadre em um padro de soluo computacional que voc j tenha visto antes.
Neste caso, queremos percorrer uma lista de nmeros e contar o nmero de vezes que valor se encaixa em um deter-
minado intervalo. Isso soa familiar. Na Seo 7.8, ns escrevemos um programa que percorria uma string e contava o
nmero de vezes que uma determinada letra aparecia.
Assim, podemos prosseguir copiando o programa original e adaptando-o para o problema atual. O programa original
era:
contador = 0
for letra in fruta:
if letra == a:
contador = contador + 1
print contador

O primeiro passo substituir fruta por lista e letra por numero. Isso no muda o programa, apenas o ajusta
para que ele se torne mais fcil de ler e entender.
O segundo passo mudar o teste. Ns no estamos interessados em procurar letras. Ns queremos ver se numero
est entre inferior e superior.:

88 Captulo 11. Captulo 9: Tuplas


Aprenda Computao com Python Documentation, Verso 1.1

contador = 0
for numero in lista
if inferior < numero < superior:
contador = contador + 1
print contador

O ltimo passo encapsular este cdigo em uma funo chamada noIntervalo. Os parmetros so a lista e os
valores inferior e superior:
def noIntervalo(lista, inferior, superior):
contador = 0
for numero in lista:
if inferior < numero < superior:
contador = contador + 1
return contador

Atravs da cpia e da modificao de um programa existente, estamos aptos a escrever esta funo rapidamente e
economizar um bocado de tempo de depurao. Este plano de desenvolvimento chamado de casamento de padres.
Se voc se encontrar trabalhando em um problema que voc j solucionou antes, reuse a soluo.

11.7 9.7 Vrios intervalos

Conforme o nmero de intervalos aumenta, noIntervalo torna-se intragvel. Com dois intervalos, no to ruim:
inferior = noIntervalo(a, 0.0, 0.5)
superior = noIntervalo(a, 0.5, 1)

Mas com quatro intervalos, comea a ficar desconfortvel.:


intervalo1 = noIntervalo(a, 0.0, 0.25)
intervalo2 = noIntervalo(a, 0.25, 0.5)
intervalo3 = noIntervalo(a, 0.5, 0.75)
intervalo4 = noIntervalo(a, 0.75, 1.0)

Existem aqui dois problemas. Um que temos que criar novos nomes de varivel para cada resultado. O outro que
temos que calcular os limites de cada intervalo.
Vamos resolver o segundo problema primeiro. Se o nmero de intervalos numeroDeIntervalos, ento a largura
de cada intervalo 1.0 / numeroDeIntervalos.
Vamos usar um lao (loop) para calcular a faixa, ou largura, de cada intervalo. A varivel do loop, i, conta de 0 at
numeroDeIntervalos-1:
larguraDoIntervalo = 1.0 / numeroDeIntervalos
for i in range(numeroDeIntervalos):
inferior = i * larguraDoIntervalo
superior = inferior + larguraDoIntervalo
print "do" inferior, "ao", superior

Para calcular o limite inferior (inferior) de cada intervalo, ns multiplicamos a varivel do loop (i) pela largura
do intervalo (larguraDoIntervalo). O limite superior (superior) est exatamente uma largura de intervalo
acima.
Com numeroDeIntervalos = 8, o resultado :
0.0 to 0.125
0.125 to 0.25
0.25 to 0.375

11.7. 9.7 Vrios intervalos 89


Aprenda Computao com Python Documentation, Verso 1.1

0.375 to 0.5
0.5 to 0.625
0.625 to 0.75
0.75 to 0.875
0.875 to 1.0

Voc pode confirmar que cada intervalo tem a mesma largura, que eles no se sobrepe, e que eles cobrem toda a faixa
de valores de 0.0 a 1.0.
Agora, de volta ao primeiro problema. Ns precisamos de uma maneira de guardar oito inteiros, usando a vriavel do
loop para indicar cada um destes inteiros. Voc deve estar pensando, Lista!
Ns temos que criar a lista de intervalos fora do loop, porque queremos fazer isto apenas uma vez. Dentro do loop,
ns vamos chamar noIntervalo repetidamente e atualizar o i-simo elemento da lista:
numeroDeIntervalos = 8
intervalos = [0] * numeroDeIntervalos
larguraDoIntervalo = 1.0 / numeroDeIntervalos
for i in range(numeroDeIntervalos):
inferior = i * larguraDoIntervalo
superior = inferior + larguraDoIntervalo
intervalos[i] = noIntervalo(lista, inferior, superior)
print intervalos

Com uma lista de 1000 valores, este cdigo vai produzir esta lista de quantidades de valores em cada intervalo:
[138, 124, 128, 118, 130, 117, 114, 131]

Esses nmeros esto razoavelmente pximos de 125, o que era o que espervamos. Pelo menos eles esto prximos o
bastante para nos fazer acreditar que o gerador de nmero aleatrios est funcionando.
Como exerccio, teste esta funo com algumas listas longas, e veja se o nmero de valores em cada um
dos intervalos tendem a uma distribuio nivelada.

11.8 9.8 Uma soluo em um s passo

Embora este programa funcione, ele no to eficiente quanto poderia ser. Toda vez que ele chama noIntervalo,
ele percorre a lista inteira. Conforme o nmero de intervalos aumenta, a lista ser percorrida um bocado de vezes.
Seria melhor fazer uma nica passagem pela lista e calcular para cada valor o ndice do intervalo ao qual o valor
pertena. Ento podemos incrementar o contador apropriado.
Na seo anterior, pegamos um ndice, i, e o multiplicamos pela larguraDoIntervalo para encontrar o limite
inferior daquele intervalo. Agora queremos pegar um valor entre 0.0 e 1.0 e encontrar o ndice do intervalo ao qual ele
se encaixa.
J que este problema o inverso do problema anterior, podemos imaginar que deveramos dividir por
larguraDoIntervalo em vez de multiplicar. Esta suposio est correta.
J que larguraDoIntervalo = 1.0 / numeroDeIntervalos, dividir por larguraDoIntervalo o mesmo
que multiplicar por numeroDeIntervalos. Se multiplicarmos um nmero na faixa entre 0.0 e 1.0 por
numeroDeIntervalos, obtemos um nmero na faixa entre 0.0 e numeroDeIntervalos. Se arredondarmos
este nmero para baixo, ou seja, para o menor inteiro mais prximo, obtemos exatamente o que estamos procurando -
o ndice do intervalo:
numeroDeIntervalos = 8
intervalos = [0] * numeroDeIntervalos
for i in lista:

90 Captulo 11. Captulo 9: Tuplas


Aprenda Computao com Python Documentation, Verso 1.1

indice = int(i * numeroDeIntervalos)


intervalos[indice] = intervalos[indice] + 1

Usamos a funo int para converter um nmero em ponto flutuante (float) para um inteiro.
Existe a possibilidade deste clculo produzir um ndice que esteja fora dos limites (seja negativo ou maior que
len(intervalos)-1)?
Uma lista como intervalos que contm uma contagem do nmero de valores em cada intervalo chamada de
histograma.
Como exerccio, escreva uma funo chamada histograma que receba uma lista e um nmero de
intervalos como argumentos e retorne um histograma com o nmero de intervalos solicitado.

11.9 9.9 Glossrio

tipo imutvel (immutable type) Um tipo de elemento que no pode ser modificado. Atribuies a um elemento ou
fatiamento (slices) XXX aos tipos imutveis causaro erro.
tipo mutvel (mutable type) Tipo de dados onde os elementos podem ser modificados. Todos os tipos mutveis, so
tipos compostos. Listas e dicionrios so exemplos de tipos de dados mutveis. String e tuplas no so.
tupla (tuple) Tipo sequencial similar as listas com exceo de que ele imutvel. Podem ser usadas Tuplas sempre
que um tipo imutvel for necessrio, por exemplo uma chave (key) em um dicionrio
Atribuio a tupla (tuple assignment) Atribuio a todos os elementos de uma tupla feita num nico comando de
atribuo. A atribuio aos elementos ocorre em paralelo, e no em sequncia, tornando esta operao til para
swap, ou troca recproca de valores entre variveis (ex: a,b=b,a).
determinstico (deterministic) Um programa que realiza a mesma coisa sempre que executado.
pseudo aleatrio (pseudorandom) Uma sequncia de nmeros que parecem ser aleatrios mas so na verdade o
resultado de uma computao determinstica
histograma (histogram) Uma lista de inteiros na qual cada elemento conta o nmero de vezes que algo acontece.
casamento de padro XXX (pattern matching) Um programa desenvolvido que envolve identificar um teste padro
computacional familiar e copiar a soluo para um problema similar.

11.9. 9.9 Glossrio 91


Aprenda Computao com Python Documentation, Verso 1.1

92 Captulo 11. Captulo 9: Tuplas


CAPTULO 12

Captulo 10: Dicionrios

Tpicos
Captulo 10: Dicionrios
10.1 Operaes dos Dicionrios
10.2 Mtodos dos Dicionrios
10.3 Aliasing (XXX) e Copiar
10.4 Matrizes Esparsas
10.5 Hint XXX
10.6 Inteiros Longos
10.7 Contando Letras
10.8 Glossrio

Os tipos compostos que voce aprendeu - strings, listas e tuplas - utilizam inteiros como indices. Se voce tentar utilizar
qualquer outro tipo como indice, voce receber um erro.
Dicionrios sao similiares a outros tipos compostos exceto por eles poderem user qualquer tipo imutavel de dados
como indice. Como exemplo, nos criaremos um dicionrio para traduzir palavras em Ingls para Espanhol. Para esse
dicionrio, os indices sero strings.
Uma maneira de criar um dicionario comecando com um dicionrio vazio e depois adiconando elementos. Um
dicionrio vazio denotado assim {}:
>>> ing2esp = {}
>>> ing2esp[one] = uno
>>> ing2esp[two] = dos

A primeira atribuio cria um dicionario chamado ing2esp; as outras atribuies adicionam novos elementos para
o dicionrio. Nos podemos imprimir o valor corrente de um dicionario da maneira usual:
>>> print ing2esp
{one: uno, two: dos}

Os elementos de um dicionrio aparecem em uma lista separada por vrgulas. Cada entrada contm um indice e
um valor separado por dois-pontos. Em um dicionrio, os ndices sao chamados de chaves, entao os elementos so
chamados de pares chave-valor.
Outra maneira de criar dicionrios fornecendo uma lista de pares chaves-valor utilizando a mesma sintaxe da ltima
sada.

93
Aprenda Computao com Python Documentation, Verso 1.1

>>> ing2esp = {one: uno, two: dos, three: tres}

Se nos imprimirmos o valor de ing2esp novamente, nos teremos uma surpresa:


>>> print ing2esp
{one: uno, three: tres, two: dos}

Os pares chave-valor no esto em ordem! Felizmente, no a motivos para se preocupar com a ordem, desde que os
elementos do dicionrio nunca sejam indexados com indices inteiros. Podemos usar as chaves para buscar os valores
correspondentes:
>>> print ing2esp[two]
dos

A chave two retornou o valor dos mesmo pensando que retornaria o terceiro par chave-valor.

12.1 10.1 Operaes dos Dicionrios

O comando del remove um par chave-valor de um dicionrio. Por exemplo, o dicionrio abaixo contem os nomes de
varias frutas e o numero de cada fruta em no estoque:
>>> inventario = {abacaxis: 430, bananas: 312, laranjas: 525, peras: 217}
>>> print inventario
{laranjas: 525, abacaxis: 430, peras: 217, bananas: 312}

Se alguem comprar todas as peras, podemos remover a entrada do dicionrio:


>>> del inventario[peras]
>>> print inventario
{laranjas: 525, abacaxis: 430, bananas: 312}

Ou se ns esperamos por mais peras em breve, nos podemos simplesmente trocar o valor associoado as peras:
>>> inventario[peras] = 0
>>> print inventario
{laranjas: 525, abacaxis: 430, peras: 0, bananas: 312}

A funo len tambm funciona com dicionrios; retornando o nmero de pares chave-valor:
>>> len(inventario)
4

12.2 10.2 Mtodos dos Dicionrios

Um mtodo parecido com uma funo - possui parametros e retorna valores - mas a sintaxe diferente. Por exemplo,
o metodo keys recebe um dicionrio e retorna uma lista com as chaves, mas em vez de usarmos a sintaxe de funo
keys(ing2esp), nos usamos a sintaxe de mtodo ing2esp.keys():
>>> ing2esp.keys()
[one, three, two]

Dessa forma o ponto especifica o nome da funo, keys, e o nome do objeto em que deve ser aplicada a funo,
ing2esp. Os parenteses indicam que esse mtodo no possui parameteros.
Ao invs de chamarmos um mtodo, dizemos que ele invocado, nesse caso, ns podemos dizer que ns estamos
invocando keys do objeto ing2esp.

94 Captulo 12. Captulo 10: Dicionrios


Aprenda Computao com Python Documentation, Verso 1.1

O mtodo values parecido; retorna a lista de valores de um dicionrio:


>>> ing2esp.values()
[uno, tres, dos]

O mtodo items retorna os dois, na forma de uma lista de tuplas - cada tupla com um par chave-valor:
>>> ing2esp.items()
[(one,uno), (three,tres), (two,dos)]

A sintaxe fornece uma informao util. Os colchetes indicam que isso uma lista. Os parentses indicam que os
elementos da lista so tuplas.
Se o mtodo recebe de algum parmetro, se utiliza a mesma sintaxe das funes. Por exemplo, o mtodo has_key
recebe uma chave e retorna verdadeiro (1) se a chave existe no dicionrio:
>>> ing2esp.has_key(one)
True
>>> ing2esp.has_key(deux)
False

Se voce tentar chamar um mtodo sem especificar em qual objeto, voce obter um erro. Nesse caso, a mensagem de
erro no muito til:
>>> has_key(one)
NameError: has_key

12.3 10.3 Aliasing (XXX) e Copiar

Uma vez que os dicionrios so mutveis, voce precisa saber sobre Aliasing. Sempre que duas variveis referenciarem
o mesmo objeto, quando uma alterada, afeta a outra.
Se voc quer modificar um dicionrio e continuar com uma copia original, utilize o mtodo copy. Por exemplo,
opposites um dicionrio que contm pares de antnimos:
>>> opposites = {up: down, right: wrong, true: false}
>>> alias = opposities
>>> copy = opposities.copy()

alias e opposites se referem ao mesmo objeto; copy se refere a um novo objeto igual ao dicionrio opposites. Se voc
modificar o alias, opposites tambm ser alterado.
>>> alias[right] = left
>>> opossites[right]
left

Se modificarmos copy, opposites no ser modificado:


>>> copy[right] = privilege
>>> opposites[right]
left

12.4 10.4 Matrizes Esparsas

Na seo 8.14, ns usamos uma lista de listas para representar uma matriz. Essa uma boa escolha se a matriz for
principalmente de valores diferentes de zero, mas considerando uma matriz esparsa como essa:

12.3. 10.3 Aliasing (XXX) e Copiar 95


Aprenda Computao com Python Documentation, Verso 1.1

Uma representao usando uma lista contem muitos zeros:


>>> matriz = [ [0,0,0,1,0],
[0,0,0,0,0],
[0,2,0,0,0],
[0,0,0,0,0],
[0,0,0,3,0] ]

Uma alternativa usarmos um dicionrio. Para as chaves, ns podemos usar tuplas que contm os nmeros da linha e
a coluna. Abaixo uma representao em um dicinario da mesma matriz:
>>> matriz = {(0,3): 1, (2, 1): 2, (4, 3): 3}

Ns precisamos apenas de trs pares chave-valor, cada um sendo um elemento diferente de zero da matriz. Cada chave
uma tupla, e cada valor um nmero inteiro.
Para acessarmos um elemento da matriz, nos utilizamos o operador []:
>>> matriz[0,3]
1

Note que a sintaxe da representao de um dicionrio no a mesma que a sintaxe usada pela representao pelas
listas. Em vez de usarmos dois ndices inteiros, ns usamos apenas um ndice, que uma tupla de inteiros.
Mas existe um problema. Se tentarmos buscar um elemento zero, obteremos um erro, pois no existe uma entrada no
dicionrio para a chave especificada:
>>> matriz[1,3]
KeyError: (1,3)

O mtodo get resolve esse problema:


>>> matriz.get((0,3), 0)
1

O primeiro parmetro a chave; o segundo o valor que get retornar caso no existe a chave no dicionrio:
>>> matriz.get((1,3), 0)
0

get definitivamente melhora a semntica e a sintaxe do acesso a matrizes esparsas.

12.5 10.5 Hint XXX

Se voc brincou com a funo fibonacci da seo 5.7, provvel que voc notou que quanto maior o nmero passado
para a funo, mais tempo a funo demora para executar. Alm disso, o tempo da execuo aumenta rapidamente.

96 Captulo 12. Captulo 10: Dicionrios


Aprenda Computao com Python Documentation, Verso 1.1

Em uma das nossas mquinas, fibonacci(20) executa instantaneamente, fibonacci(30) demora cerca de um segundo,
e fibonacci(40) demora uma eternidade.
Para entender o porque, considere o grfico de chamadas para fibonacci com n=4:

O grfico mostra a estrutura da funo, com linhas conectando cada execuo com a execuo que a chamou. No
topo do grfico, fibonacci tem n=4, que chama fibonacci com n=3 e n=2. Em seguida, fibonacci com n=3 chama
fibonacci com n=2 e n=1. E assim por diante.
Conte quantas vezes fibonacci(0) e fibonacci(1) so chamadas. Essa uma soluo ineficiente para o problema, e
torna-se pior quando o parmetro recebido um nmero maior.
Uma boa soluo guardar os valores que j foram calculados armazenando-os em um dicionrio. Um valor previ-
amente calculado que guardado para ser utilizado mais tarde chamado de hint. Abaixo uma implementao de
fibonacci usando hints:
>>> previous = {0:1, 1:1}
>>> def fibonacci(n):
if previous.has_key(n):
return previous[n]
else:
newValue = fibonacci(n-1) + fibonacci(n-2)
previous[n] = newValue
return newValue

O dicionrio chamado previous guarda os nmeros de Fibonacci que ns ja conhecemos. Ele comea com apenas
dois pares: 0 possui 1; e 1 possui 1.

12.5. 10.5 Hint XXX 97


Aprenda Computao com Python Documentation, Verso 1.1

Sempre que fibonacci chamada, ela verifica o dicionrio para determinar se ele j possui o resultado. Se o resultado
estiver ali, a funo pode retornar imediatamente sempre precisar fazer mais chamadas recursivas. Se o resultado no
estiver ali, ele calculado no newValue. O valor de newValue adicionado no dicionrio antes da funo retornar.
Usando essa verso de fibonacci, nossa mquina consegue calcular fibonacci(40) em um piscar de olhos. Mas quando
tentamos calcular fibonacci(50), ns veremos um problema diferente:
>>> fibonacci(50)
OverflowError: integer addition

A resposta, que voc ver em um minuto, 20.365.011.074. O problema que esse nmero muito grande para
guardarmos como um inteiro do Python 1 . Isso overflow. Felizmente, esse problema tem uma soluo simples.

12.6 10.6 Inteiros Longos

Python possui um tipo chamado long int que permite trabalharmos com qualquer tamanho de inteiros. Existem duas
maneiras de criarmos um valor long int. A primeira escrever um inteiro seguido de um L no final:
>>> type(1L)
<type long int>

A outra maneira usarmos a funo long que converte um valor para um long int. long pode receber qualquer valor
nmerico e at mesmo uma string de digitos:
>>> long(1)
1L
>>> long(3.9)
3L
>>> long(57)
57L

Todas as operaes matemticas funcionam com long int s, ento no precisamos modificar muito para adaptar fi-
bonacci:
>>> previous = {0: 1L, 1:1L}
>>> fibonacci(50)
20365011074L

Somente trocando os valores iniciais de previous, conseguimos mudar o comportamento da fibonacci. Os dois
primeiros numeros da sequncia so long ints, ento todos os nmeros subsequentes da sequncia tambm sero.
Como exerccio, converta fatorial para produzir um inteiro longo como resultado.

12.7 10.7 Contando Letras

No captulo 7, escrevemos uma funo que contava o nmero de ocorrncias de uma letra em uma string. A verso
mais comum desse problema fazer um histograma das letras da string, ou seja, quantas vezes cada letra aparece na
string.
Um histograma pode ser util para comprimir um arquivo de texto. Pois diferentes letras aparecem com diferentes
frequncias, podemos comprimir um arquivo usando pequenos cdigos para letras comuns e longos cdigos para
letras que aparecem em menor frequncia.
Dicionrios fornecem uma maneira elegante de gerar um histograma:
1 N.T. A partir do Python 2. XXX este erro no ocorre mais, pois em caso de sobrecarga o valor inteiro automaticamente promovido para o
tipo long.

98 Captulo 12. Captulo 10: Dicionrios


Aprenda Computao com Python Documentation, Verso 1.1

>>> letterCounts = {}
>>> for letter in "Mississippi":
... letterCounts[letter] = letterCounts.get(letter,0) + 1
...
>>> letterCounts
{M: 1, s: 4, p: 2, i: 4}

Comeamos com um dicionrio vazio. Para cada letra da string, achamos o contador (possivelmente zero) e o incre-
mentamos. No final, o dicionrio contem pares de letras e as suas frequncias.
mais atraente mostrarmos o histograma na ordem alfabtica. Podemos fazer isso com os mtodos items e sort:
>>> letterItems = letterCounts.items()
>>> letterItems.sort()
>>> print letterItems
[(M, 1), (i, 4), (p, 2), (s, 4)]

Voc ja tinha visto o mtodo items antes, mas sort o primeiro mtodo que voc se depara para aplicar em listas.
Existem muitos outros mtodos de listas, incluindo append, extend, e reverse. Consulte a documentao do Python
para maiores detalhes.

12.8 10.8 Glossrio

dicionrio (dictionary) Uma coleo de pares de chaves-valores que so mapeados pelas chaves, para se obter os
valores. As chaves podem ser qualquer tipo de dados imutavel, e os valores podem ser de qualquer tipo.
chave (key) Um valor que usado para buscar uma entrada em um dicionrio.
par chave-valor (key-value pair) Um dos itens de um dicionrio.
mtodo (method) Um tipo de funo que chamada com uma sintaxe diferente e invocada no contexto de um objeto.
invocar (invoke) Chamar um mtodo.
hint O armazenamento temporrio de um valor pr-computado para evitar a computao redundante.
overflow Um resultado numrico que muito grande para ser representado no formato numrico.

12.8. 10.8 Glossrio 99


Aprenda Computao com Python Documentation, Verso 1.1

100 Captulo 12. Captulo 10: Dicionrios


CAPTULO 13

Captulo 11: Arquivos e excees

Tpicos
Captulo 11: Arquivos e excees
Arquivos e excees
11.1 Arquivos texto
11.2 Gravando variveis
11.3 Diretrios
11.4 Pickling
11.5 Excees
11.6 Glossrio

13.1 Arquivos e excees

Durante a execuo de um programa, seus dados ficam na memria. Quando o programa termina, ou o computador
desligado, os dados na memria desaparecem. Para armazenar os dados permanentemente, voc tem que coloc-los
em um arquivo. Arquivos usualmente so guardados em um disco rgido (HD), num disquete ou em um CD-ROM.
Quando existe um nmero muito grande de arquivos, eles muitas vezes so organizados dentro de diretrios (tambm
chamados de ?pastas? ou ainda ?*folders*?). Cada arquivo identificado por um nome nico, ou uma combinao de
um nome de arquivo com um nome de diretrio.
Lendo e escrevendo em arquivos, os programas podem trocar informaes uns com os outros e gerar formatos im-
primveis como PDF.
Trabalhar com arquivos muito parecido com trabalhar com livros. Para utilizar um livro, voc tem que abr-lo.
Quando voc termina, voc tem que fech-lo. Enquanto o livro estiver aberto, voc pode tanto l-lo quanto escrever
nele. Em qualquer caso, voc sabe onde voc est situado no livro. Na maioria das vezes, voc l o livro inteiro em
sua ordem natural, mas voc tambm pode saltar atravs de alguns trechos (skip around).
Tudo isso se aplica do mesmo modo a arquivos. Para abrir um arquivo, voc especifica o nome dele e indica o que
voc quer, seja ler ou escrever (gravar).
Abrir um arquivo cria um objeto arquivo. Neste exemplo, a varivel f se referencia ao novo objeto arquivo.

101
Aprenda Computao com Python Documentation, Verso 1.1

>>> f = open("teste.dat", "w")


>>> print f
<open file "teste.dat", mode "w" at fe820>

A funo open recebe dois argumentos. O primeiro o nome do arquivo, e o segundo o modo. Modo ?w? significa
que estamos abrindo o arquivo para gravao (?*write*?, escrever).
Se no existir nenhum arquivo de nome teste.dat, ele ser criado. Se j existir um, ele ser substitudo pelo
arquivo que estamos gravando (ou escrevendo).
Quando executamos um comando print sobre o objeto arquivo, visualizamos o nome do arquivo, o modo e a
localizao do objeto na memria.
Para colocar dados dentro do arquivo, invocamos o mtodo write do objeto arquivo:
>>> f.write("Agora hora")
>>> f.write("de fechar o arquivo")

Fechar o arquivo diz ao sistema que terminamos de escrever (gravar) e que o arquivo est livre para ser lido:
>>> f.close()

Agora podemos abrir o arquivo de novo, desta vez para leitura, e ler o seu contedo para uma string. Desta vez, o
argumento modo ?r? para leitura (?reading?):
>>> f = open("teste.dat", "r")

Se tentarmos abrir um arquivo que no existe, temos um erro:


>>> f = open("teste.cat", "r")
IOError: [Errno 2] No such file or directory: teste.cat

Sem nenhuma surpresa, o mtodo read l dados do arquivo. Sem argumentos, ele l todo o contedo do arquivo:
>>> texto = f.read()
>>> print texto
Agora horade fechar o arquivo

No existe espao entre ?hora? e ?de? porque ns no gravamos um espao entre as strings.
read tambm pode receber um argumento que indica quantos caracteres ler:
>>> f = open("teste.dat", "r")
>>> print f.read(9)
Agora h

Se no houver caracteres suficientes no arquivo, read retorna os caracteres restantes. Quando chegamos ao final do
arquivo, read retorna a string vazia:
>>> print f.read(1000006)
orade fechar o arquivo
>>> print f.read()

>>>

A funo seguinte, copia um arquivo, lendo e gravando at cinqenta caracteres de uma vez. O primeiro argumento
o nome do arquivo original; o segundo o nome do novo arquivo:
def copiaArquivo(velhoArquivo, novoArquivo):
f1 = open(velhoArquivo, "r")
f2 = open(novoArquivo, "w")
while 1:

102 Captulo 13. Captulo 11: Arquivos e excees


Aprenda Computao com Python Documentation, Verso 1.1

texto = f1.read(50)
if texto == "":
break
f2.write(texto)
f1.close()
f2.close()
return

A comando break novo. O que ele faz saltar a execuo para fora do loop; o fluxo de execuo passa para o
primeiro comando depois do loop.
Neste exemplo, o loop while infinito porque o valor 1 sempre verdadeiro. O nico modo de sair do loop
executando o break, o que ocorre quando texto a string vazia, o que ocorre quando alcanamos o fim do arquivo.

13.2 11.1 Arquivos texto

Um arquivo texto um arquivo que contm caracteres imprimveis e espaos, organizados dentro de linhas separadas
por caracteres de nova linha. J que Pyhton especialmente projetado para processar arquivos texto, ele oferece
mtodos que tornam esta tarefa mais fcil.
Para demonstrar, vamos criar um arquivo texto com trs linhas de texto separadas por caracteres de nova linha:
>>> f = open("teste.dat", "w")
>>> f.write("linha um\nlinha dois\nlinha trs\n")
>>> f.close()

O mtodo readline l todos os caracteres at, e incluindo, o prximo caractere de nova linha:
>>> f = open("teste.dat", "r")
>>> print f.readline()
linha um

>>>

readlines retorna todas as linhas restantes como uma lista de strings:


>>> print f.readlines()
[linha dois\012, linha trs\012]

Neste caso, a sada est em formado de lista, o que significa que as strings aparecem entre aspas e o caractere de nova
linha aparece como a seqncia de escape 012.
No fim do arquivo, readline retorna a string vazia e readlines retorna a lista vazia:
>>> print f.readline()

>>> print f.readlines()


[]

A seguir temos um exemplo de um programa de processamento de linhas. filtraArquivo faz uma cpia de
velhoArquivo, omitindo quaisquer linhas que comecem por #:
def filtraArquivo(velhoArquivo, novoArquivo):
f1 = open(velhoArquivo, "r")
f2 = open(novoArquivo, "w")
while 1:
texto = f1.readline()
if texto == "":

13.2. 11.1 Arquivos texto 103


Aprenda Computao com Python Documentation, Verso 1.1

break
if texto[0] == #:
continue
f2.write(texto)
f1.close()
f2.close()
return

O comando continue termina a iterao corrente do loop, mas continua iterando o loop. O fluxo de execuo passa
para o topo do loop, checa a condio e prossegue conforme o caso.
Assim, se texto for a string vazia, o loop termina. Se o primeiro caractere de texto for o jogo da velha (? # ?), o
fluxo de execuo passa para o topo do loop. Somente se ambas as condies falharem que texto ser copiado
para dentro do novo arquivo.

13.3 11.2 Gravando variveis

O argumento de write tem que ser uma string, assim se quisermos colocar outros valores em um arquivo, temos de
convert-los para strings primeiro. A maneira mais fcil de fazer isso com a funo str:
>>> x = 52
>>> f.write(str(x))

Uma alternativa usar o operador de formatao %. Quando aplicado a inteiros, % o operador mdulo. Mas quando
o primeiro operador uma string, % o operador de formatao.
O primeiro operando a string de formatao, e o segundo operando uma tupla de expresses. O resultado uma
string que contm os valores das expresses, formatadas de acordo com a string de formatao.
Num exemplo simples, a seqncia de formatao ??%d?? significa que a primeira expresso na tupla deve ser
formatada como um inteiro. Aqui a letra d representa ?decimal?.
>>> carros = 52
>>> "%d" % carros
52

O resultado a string ?52?, que no deve ser confundida com o valor inteiro 52.
Uma seqncia de formatao pode aparecer em qualquer lugar na string de formatao, assim, podemos embutir um
valor em uma seqncia:
>>> carros = 52
>>> "Em julho vendemos %d carros." % carros
Em julho vendemos 52 carros.

A seqncia de formatao %f formata o prximo item da tupla como um nmero em ponto flutuante, e %s
formata o prximo como uma string:
>>> "Em %d dias fizemos %f milhes %s." % (34,6.1,reais)
Em 34 dias fizemos 6.100000 milhes de reais.

Por padro, o formato de ponto flutuante exibe seis casas decimais.


O nmero de expresses na tupla tem que ser igual ao nmero de seqncias de formatao na string. Alm disso, os
tipos das expresses tm que iguais aos da seqncia de formatao:
>>> "%d %d %d" % (1,2)
TypeError: not enough arguments for format string

104 Captulo 13. Captulo 11: Arquivos e excees


Aprenda Computao com Python Documentation, Verso 1.1

>>> "%d" % reais


TypeError: illegal argument type for built-in operation

No primeiro exemplo, no existem expresses suficientes; no segundo, a expresso do tipo errado.


Para um controle maior na formatao de nmeros, podemos especificar o nmero de dgitos como parte da seqncia
de formatao:
>>> "%6d" % 62
62
>>> "%12f" % 6.1
6,100000

O nmero depois do sinal de porcentagem o nmero mnimo de espaos que o valor ocupar. Se o valor fornecido
tiver um nmero menor de dgitos, espaos em branco sero adicionados antes para preencher o restante. Se o nmero
de espaos for negativo, os espaos sero adicionados depois:
>>> "%-6d" % 62
62

Para nmeros em ponto-flutuante, tambm podemos especificar o nmero de dgitos depois da vrgula:
>>> "%12.2f" % 6.1
6.10

Neste exemplo, o resultado reserva 12 espaos e inclui dois dgitos depois da vrgula. Esta formatao til para
exibir valores monetrios com os centavos alinhados.
Por exemplo, imagine um dicionrio que contm nomes de estudantes como chaves e salrios-hora como valores. Aqui
est uma funo que imprime o contedo do dicionrio como um relatrio formatado:
def relatorio(salarios):
estudantes = salarios.keys()
estudantes.sort()
for estudante in estudantes:
print "%-20s %12.02f" % (estudante, salarios[estudante])

Para testar esta funo, criaremos um pequeno dicionrio e imprimiremos o contedo:


>>> salarios = {maria: 6.23, joo: 5.45, josu: 4.25}
>>> relatorio(salarios)
joo 5.45
josu 4.25
maria 6.23

Controlando a largura de cada valor, podemos garantir que as colunas ficaro alinhadas, desde que os nomes contenham
menos que vinte e um caracteres e os salrios sejam menores do que um bilho de reais por hora.

13.4 11.3 Diretrios

Quando voc cria um novo arquivo abrindo-o e escrevendo nele, o novo arquivo fica no diretrio corrente (seja l onde
for que voc esteja quando rodar o programa). Do mesmo modo, quando voc abre um arquivo para leitura, Python
procura por ele no diretrio corrente.
Se voc quiser abrir um arquivo que esteja em algum outro lugar, voc tem que especificar o caminho (path) para o
arquivo, o qual o nome do diretrio (ou folder) onde o arquivo est localizado:

13.4. 11.3 Diretrios 105


Aprenda Computao com Python Documentation, Verso 1.1

>>> f = open("/usr/share/dict/words", "r")


>>> print f.readline()
Aarhus

Este exemplo abre um arquivo chamado words que reside em um diretrio de nome dict, o qual reside em share,
o qual reside em usr, o qual reside no diretrio de mais alto nvel do sistema, chamado /.
Voc no pode usar / como parte do nome de um arquivo; ela um caractere reservado como um delimitador entre
nomes de diretrios e nomes de arquivos.
O arquivo /usr/share/dict/words contm uma lista de palavras em ordem alfabtica, na qual a primeira
palavra o nome de uma universidade Dinamarquesa.

13.5 11.4 Pickling

Para colocar valores em um arquivo, voc tem que convert-los para strings. Voc j viu como fazer isto com str:
>>> f.write (str(12.3))
>>> f.write (str([1,2,3]))

O problema que quando voc l de volta o valor, voc tem uma string. O Tipo original da informao foi perdido.
De fato, voc no pode sequer dizer onde comea um valor e termina outro:
>>> f.readline()
?12.3[1, 2, 3]?

A soluo o pickling, assim chamado porque ?preserva? estruturas de dados. O mdulo pickel contm os coman-
dos necessrios. Para us-lo, importe pickle e ento abra o arquivo da maneira usual:
>>> import pickle
>>> f = open(?test.pck?, ?w?)

Para armazenar uma estrutura de dados, use o mtodo dump e ento feche o arquivo do modo usual:
>>> pickle.dump(12.3, f)
>>> pickle.dump([1,2,3], f)
>>> f.close()

Ento, podemos abrir o arquivo para leitura e carregar as estruturas de dados que foram descarregadas (dumped):
>>> f = open(?test.pck?, ?r?)
>>> x = pickle.load(f)
>>> x
12,3
>>> type(x)
<type ?float?>
>>> y = pickle.load(f)
>>> y
[1, 2, 3]
>>> type(y)
<type ?list?>

Cada vez que invocamos load, obtemos um nico valor do arquivo, completo com seu tipo original.

106 Captulo 13. Captulo 11: Arquivos e excees


Aprenda Computao com Python Documentation, Verso 1.1

13.6 11.5 Excees

Whenever que um erro em tempo de execuo acontece, ele gera uma exceo. Usualmente, o programa pra e Python
exibe uma mensagem de erro.
Por exemplo, dividir por zero gera uma exceo:
>>> print 55/0
ZeroDivisionError: integer division or modulo

Do mesmo modo, acessar um item de lista inexistente:


>>> a = []
>>> print a[5]
IndexError: list index out of range

Ou acessar uma chave que no est em um dicionrio:


>>> b = {}
>>> print b[?what?]
KeyError: what

Em cada caso, a mensagem de erro tem duas partes: o tipo do erro antes dos dois pontos, e especificidades do
erro depois dos dois pontos. Normalmente Python tambm exibe um ?*traceback*? de onde estava a execuo do
programa, mas ns temos omitido esta parte nos exemplos.
s vezes queremos executar uma operao que pode causar uma exceo, mas no queremos que o programa pare.
Ns podemos tratar a exceo usando as instrues try e except.
Por exemplo, podemos pedir ao usurio um nome de arquivo e ento tentar abr-lo. Se o arquivo no existe, no
queremos que o programa trave; queremos tratar a exceo:
nomedoarquivo = raw_input(?Entre com o nome do arquivo: ?)
try:
f = open (nomedoarquivo, ?r?)
except:
print ?No existe arquivo chamado?, nomedoarquivo

A instruo try executa os comandos do primeiro bloco. Se no ocorrerem excees, ele ignora a instruo except.
Se qualquer exceo acontece, ele executa os comandos do ramo except e continua.
Podemos encapsular esta habilidade numa funo: existe toma um nome de arquivo e retorna verdadeiro se o arquivo
existe e falso se no existe:
def existe(nomedoarquivo)
try:
f = open(nomedoarquivo)
f.close()
return 1
except:
return 0

Voc pode usar mltiplos blocos except para tratar diferentes tipos de excees. O Manual de Referncia de Python
(Python Reference Manual) tem os detalhes.
Se o seu programa detecta uma condio de erro, voc pode faz-lo lanar uma exceo. Aqui est um exemplo que
toma uma entrada do usurio e testa se o valor 17. Supondo que 17 no seja uma entrada vlida por uma razo
qualquer, ns lanamos uma exceo.

13.6. 11.5 Excees 107


Aprenda Computao com Python Documentation, Verso 1.1

def entraNumero():
x = input (?Escolha um nmero: ?)
if x == 17:
raise ?ErroNumeroRuim?, ?17 um nmero ruim?
return x

O comando raise toma dois argumentos: o tipo da exceo e informaes especficas sobre o erro.
ErroNumeroRuim um novo tipo de exceo que ns inventamos para esta aplicao.
Se a funo que chamou entraNumero trata o erro, ento o programa pode continuar; de outro modo, Pyhton exibe
uma mensagem de erro e sai:
>>> entraNumero()
Escolha um nmero: 17
ErroNumeroRuim: 17 um nmero ruim

A mensagem de erro inclui o tipo da exceo e a informao adicional que voc forneceu.
Como um exerccio, escreva uma funo que use entraNumero para pegar um nmero do teclado e que
trate a exceo ErroNumeroRuim.

13.7 11.6 Glossrio

arquivo (file) Uma entidade nomeada, usualmente armazenada em um disco rgido (HD), disquete ou CD-ROM, que
contm uma seqncia de caracteres.
diretrio (directory) Uma coleo nomeada de arquivos, tambm chamado de pasta ou folder.
caminho (path) Uma seqncia de nomes de diretrios que especifica a exata localizao de um arquivo.
arquivo texto (text file) Um arquivo que contm caracteres organizados em linhas separadas por caracteres de nova
linha.
comando break (break statement) Um comando que fora a atual iterao de um loop a terminar. O fluxo de exe-
cuo vai para o topo do loop, testa a condio e prossegue conforme o caso.

108 Captulo 13. Captulo 11: Arquivos e excees


CAPTULO 14

Captulo 12: Classes e objetos

Tpicos
Captulo 12: Classes e objetos
12.1 Tipos compostos definidos pelo usurio
12.2 Atributos
12.3 Instncias como parmetros
12.4 O significado de mesmo
12.5 Retngulos
12.6 Instancias como valores retornados
12.7 Objetos so mutveis
12.8 Copiando
12.9 Glossrio

14.1 12.1 Tipos compostos definidos pelo usurio

Depois de usarmos alguns tipos nativos do Python, estamos prontos para criar um tipo de dados: o Ponto.
Considere o conceito matemtico de um ponto. Em duas dimenses, um ponto um par de nmeros (coordenadas)
que so tratadas coletivamente como um objeto simples. Na notao matemtica, pontos so freqentemente escritos
entre parnteses com vrgula separando as coordenadas. Por exemplo, (0, 0) representa a origem, e (x, y) representa o
ponto x unidades direita, e y unidades acima da origem.
Uma maneira natural para representar um ponto em Python, com dois valores numricos em ponto flutuante. A
questo, ento, como agrupar estes dois valores em um objeto composto. A maneira rpida e rasteira usar uma lista
ou uma tupla, e para algumas aplicaes, esso pode ser a melhor escolha 1 .
Uma alternativa definir um novo tipo composto, tambm chamado uma classe. Esta abordagem envolve um pouco
mais de esforo, mas ela tem vantagens que logo ficaro evidentes.
Eis a definio de uma classe:
1 N.T.: A linguagem Python tambm incorpora um tipo nativo complex que representa nmeros complexos. Uma instncia de complex,

como a=3+5j possui dois valores de ponto flutuante em seus atributos a.real e a.imag, e pode ser utilizada para armazenar pontos em um
espao bi-dimensional.

109
Aprenda Computao com Python Documentation, Verso 1.1

class Ponto:
pass

Definies de classes podem aparecer em qualquer parte de um programa, mas elas costuma ficar prximas do comeo
do programa (aps os comandos import). As regras de sintaxe para a definio de classes so as mesmas de outros
comandos compostos (veja Seo 4.4).
A definio acima cria uma nova classe chamada Ponto. O comando pass no tem nenhum efeito; aqui ele
necessrio porque um comando composto precisa ter algo no seu corpo.
Quando criamos a classe Ponto, criamos um novo tipo de dado, tambm chamado Ponto. Os membros deste novo
tipo so chamados instncias deste tipo ou objetos. Criar uma nova instncia instanciar. Para instanciar o objeto
Ponto, invocamos a funo (adivinhou?) Ponto:
final = Ponto()

A varivel final agora contm uma referncia a um novo objeto da classe Ponto. Uma funo como Ponto, que
cria novos objetos, chamada construtor.

14.2 12.2 Atributos

Podemos adicionar novos dados em uma instncia usando a notao de ponto (dot notation):
>>> final.x = 3.0
>>> final.y = 4.0

Esta sintaxe similar sintaxe para acessar uma varivel de um mdulo, como math.pi ou string.uppercase.
Neste caso, porm, estamos acessando um item de dado de uma instncia. Estes itens so chamados atributos.
O seguinte diagrama de estado mostra o resultado destas atribuies:

A varivel final refere a um objeto Ponto, que contm dois atributos. Cada atributo faz referncia a um nmero
em ponto flutuante.
Podemos ler o valor de um atributo usando a mesma sintaxe:
>>> print final.y
4.0
>>> x = final.x
>>> print x
3.0

A expresso final.x significa, V ao objeto final e pegue o valor de x. Neste caso, atribumos este valor
a uma varivel cujo nome x. No h conflito entre a varivel x e o atributo x. O propsito da notao
objeto.atributo identificar a qual varivel voc est fazendo referncia de forma que no ambguo.
Voc pode usar a notao objeto.atributo como parte de qualquer expresso; assim os seguintes comandos so
vlidos:

110 Captulo 14. Captulo 12: Classes e objetos


Aprenda Computao com Python Documentation, Verso 1.1

print ( + str(final.x) + , + str(final.y) + )


distAoQuadrado = final.x * final.x + final.y * final.y

A primeira linha imprime (3.0, 4.0); a segunda linha calcula o valor 25.0.
tentador imprimir o valor do prprio objeto final:
>>> print final
<__main__.Ponto instance at 80f8e70>

O resultado indica que final uma instncia da classe Ponto e foi definida no prgrama principal: __main__.
80f8e70 o identificador nico deste objeto, escrito em hexadecimal (base 16). Esta no provavelmente a forma
mais informativa para mostrar um objeto Ponto. Logo voc ir ver como mudar isso.
Como exerccio, crie e imprima um objeto Ponto, e ento use id para imprimir o identificador nico do
objeto. Traduza a forma hexadecimal para a forma decimal e confirme se so compatveis.

14.3 12.3 Instncias como parmetros

Voc pode passar uma instncia como um parmetro da forma usual. Por exemplo:
def mostrarPonto(p):
print ( + str(p.x) + , + str(p.y) + )

A funo mostrarPonto pega o ponto (p) como um argumento e mostra-o no formato padro. Se voc chamar
mostrarPonto(final), a sada ser (3.0, 4.0).
Como um exerccio, re-escreva a funo distncia da Seo 5.2 para receber dois pontos como parmetros,
ao invs de quatro nmeros.

14.4 12.4 O significado de mesmo

O significado da palavra mesmo parece perfeitamente claro at que voc pense a respeito, e ento voc percebe que
h mais nesta palavra do que voc esperava.
Por exemplo, se voc diz Cris e eu temos o mesmo carro, voc est dizendo que o carro de Cris e o seu so do
mesmo fabricante e modelo, mas so dois carros diferentes. Se voc disser Cris e eu temos a mesma me, voc est
dizendo que a me de Cris e a sua, so a mesma pessoa 2 . Portanto a idia de semelhana diferente dependendo do
contexto.
Quando falamos de objetos, h uma ambigidade similar. Por exemplo, se dois Pontos forem os mesmos, isto quer
dizer que eles contm os mesmos dados (coordenadas) ou que so realmente o mesmo objeto?
Para verificar se duas referncias se referem ao mesmo objeto, use o operador == 3 . Por exemplo:
>>> p1 = Ponto()
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = Ponto()
2 Nem todos os idiomas tm este problema. Por exemplo, em alemo h palavras diferentes para diferentes sentidos de mesmo. Mesmo

carro nesse contexto seria gleiche Auto, e mesma me seria selbe Mutter.
3 XXX LR: Eu no diria que devemos usar == para verificar se dois objetos so o mesmo. Isto uma falha do livro que talvez se origine no

original que falava de Java. Em Python o operador is faz o mesmo que o == de Java: compara referncias, e portanto serve para determinar se
duas variveis apontam para o mesmo objeto. No entanto, a o cdigo acima est correto porque em Python a implemetao default de == (mtodo
__eq__) comparar o id das instncias, porm as classes list e dict, por exemplo, implementam __eq__ comparando os valores contidos (ex.: isto
retorna True: l1 = [1,2,3]; l2 = [1,2,3]; l1 == l2).

14.3. 12.3 Instncias como parmetros 111


Aprenda Computao com Python Documentation, Verso 1.1

>>> p2.x = 3
>>> p2.y = 4
>>> p1 == p2
False

Mesmo que p1 e p2 contenham as mesmas coordenadas, os dois no representam o mesmo objeto. Se atribuirmos p1
a p2, ento as duas variveis so pseudnimos do mesmo objeto.
>>> p2 = p1
>>> p1 == p2
True

Este tipo de igualdade chamado de igualdade rasa porque ela compara somente as referncias e no o contedo dos
objetos.
Para comparar o contedo dos objetos igualdade profunda podemos escrever uma funo chamada mesmoPonto:
def mesmoPonto(p1, p2) :
return (p1.x == p2.x) and (p1.y == p2.y)

Agora se criarmos dois diferentes objetos que contm os mesmos dados, podemos usar mesmoPonto para verificar se
eles representam o mesmo ponto.
>>> p1 = Ponto()
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = Ponto()
>>> p2.x = 3
>>> p2.y = 4
>>> mesmoPonto(p1, p2)
True

claro, se as duas variveis referirem ao mesmo objeto, elas tm igualdade rasa e igualdade profunda.

14.5 12.5 Retngulos

Digamos que desejemos uma classe para representar um retngulo. A questo , qual informao temos de prover
para especificar um retngulo? Para manter as coisas simples, assuma que o retngulo orientado verticalmente ou
horizontalmente, nunca em um ngulo.
H algumas possibilidades: poderamos especificar o centro do retngulo (duas coordenadas) e seu tamanho (largura e
altura); ou poderamos especificar um dos lados e o tamanho; ou poderamos especificar dois lados opostos. A escolha
convencional especificar o canto superior esquerdo do retngulo e o tamanho.
Novamente, vamos definir uma nova classe:
class Rectangle:
pass

E instanci-la:
box = Rectangle()
box.width = 100.0
box.height = 200.0

Este cdigo cria um novo objeto Retngulo com dois atributos ponto-flutuante. Para especificar o canto superior
esquerdo, podemos embutir um objeto dentro de um objeto!

112 Captulo 14. Captulo 12: Classes e objetos


Aprenda Computao com Python Documentation, Verso 1.1

box.corner = Ponto()
box.corner.x = 0.0;
box.corner.y = 0.0;

A expresso box.corner.x significa, v ao objeto referenciado por box e selecione o atributo corner; ento v ao
objeto corner e deste, selecione o atributo de nome x.
A figura mostra o estado deste objeto:

14.6 12.6 Instancias como valores retornados

Funes podem retornar instncias. Por exemplo, findCenter pega um Retngulo como um argumento e retorna um
Ponto que contem as coordenadas do centro do retngulo:
def findCenter(box):
p = Ponto()
p.x = box.corner.x + box.width/2.0
p.y = box.corner.y + box.height/2.0

Para chamar esta funo, passe box como um argumento e coloque o resultado em uma varivel.
>>> center = findCenter(box)
>>> print mostrarPonto(center)
(50.0, 100.0)

14.7 12.7 Objetos so mutveis

Podemos mudar o estado de um objeto fazendo uma atribuio a um dos seus atributos. Por exemplo, para mudar o
tamanho de um retngulo sem mudar sua posio, podemos modificar os valores de sua largura e altura. Veja:
box.width = box.width + 50
box.height = box.height + 100

Poderamos encapsular este cdigo em um mtodo e generaliza-lo para aumentar o tamanho deste retngulo em qual-
quer medida:
def growRect(box, dwidth, dheight) :
box.width = box.width + dwidth
box.height = box.height + dheight

14.6. 12.6 Instancias como valores retornados 113


Aprenda Computao com Python Documentation, Verso 1.1

As variveis dwidth e dheight indicam em quanto vamos aumentar o tamanho do retngulo em cada direo.
Chamando este mtodo, teramos o mesmo efeito.
Por exemplo, poderamos criar um novo Retngulo com o nome de bob e passar este nome para o mtodo growRect:
>>> bob = Rectangle()
>>> bob.width = 100.00
>>> bob.height = 200.00
>>> bob.corner.x = 0.0;
>>> bob.corner.y = 0.0;
>>> growRect(bob, 50, 100)

Enquanto growRect est sendo executado, o parmetro box um alias (apelido) para bob. Qualquer mudana feita
em box, tambm ir afetar bob.
Como exerccio, escreva uma function (mtodo) com o nome de moveRect que pega um Rectangle e dois parmetros
com o nome de dx e dy. Esta funo dever mudar a localizao do retngulo atravs da adio de dx coordenada
x e da adio de dy coordenada y.

14.8 12.8 Copiando

Ao usar alias - como fizemos na seo anterior - podemos tornar o programa um pouco difcil de ler ou entender, pois
as mudanas feitas em um local, podem afetar inesperadamente um outro objeto. E pode se tornar difcil de encontrar
todas as variveis que podem afetar um dado objeto.
Copiar um objeto freqentemente uma alternativa ao alias. O modulo copy contm uma funo chamada copy
que duplica um qualquer objeto. Veja:
>>> import copy
>>> p1 = Ponto()
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = copy.copy(p1)
>>> p1 == p2
0
>>> mesmoPonto(p1, p2)
1

Uma vez que importamos o modulo copy, podemos usar o mtodo copy para criar um outro Ponto. p1 e p2 no
representam o mesmo ponto, mas eles contem os mesmo dados.
Para copiar um simples objeto como um Ponto, que no contem nenhum objeto embutido, copy suficiente. Isto
eh chamado shallow copia.
Mas para um objeto como um Rectangle, que contem uma referencia para um Ponto, o mtodo copy no ir
executar corretamente a copia. Ele ir copiar a referencia para o objeto Ponto, portanto o que acontece aqui que os
dois Rectangle (o novo e o antigo) iro fazer referencia a um simples Ponto.
Em outras palavras, se criarmos um box, c1, utilizando a forma usual, e depois fazer uma copia, c2, usando o mtodo
copy, o diagrama de estado resultante ficar assim:

114 Captulo 14. Captulo 12: Classes e objetos


Aprenda Computao com Python Documentation, Verso 1.1

o resultado no ser o que esperamos. Neste caso, invocando growRect em um dos retngulos (c1), isto no ir
afetar o outro retngulo (c2, neste exemplo). Mas se usarmos o mtodo moveRect em qualquer um deles, isto ir
inevitavelmente afetar o outro. Este comportamento confuso e propenso a erros!
Mas felizmente o modulo copy contem um mtodo chamado deepcopy que copia no somente o objeto, mas
tambm copia todo e qualquer objeto embutido neste objeto. Por isto, voc no ficar surpreso porque este mtodo
chama-se deepcopy (copia profunda) no ? Veja como funciona:
>>> c2 = copy.deepcopy(c1)

Agora, c1 e c2 so objetos completamente separados.


Podemos usar deepcopy para re-escrever growRect sendo que ao invs de modificar um Rectangle existente, ele
cria um novo que tem a mesma localizao do outro, mas com novas dimenses:
def growRect(box, dwidth, dheight):
import copy
newBox = copy.deepcopy(box)
newBox.width = newBox.width + dwidth
newBox.height = newBox.height + dheight
return newBox

Como exerccio, re-escreva o mtodo moveRect para ele criar e retornar um novo Rectangle ao invs de apenas
modificar o antigo.

14.9 12.9 Glossrio

classe (class) Um tipo composto (XXX compound type) definido pelo usurio. Uma classe tambm pode ser visual-
izada como um molde que define a forma dos objetos que sero suas instncias.
instanciar (instantiate) Criar uma instncia de uma classe.
instncia (instance) Um objeto que pertence a uma classe.
objeto (object) Um tipo de dado composto comumente utilizado para representar uma coisa ou um conceito do mundo
real.
construtor (constructor) Um mtodo utilizado para criar novos objetos.
atributo (attribute) Um dos itens de dados nomeados que compem uma instncia.
igualdade rasa (shallow equality) Igualdade de referncias; ocorre quando duas referncias apontam para o mesmo
objeto.
igualdade profunda (deep equality) Igualdade de valores; ocorre quando duas referncias apontam para objetos que
tm o mesmo valor.

14.9. 12.9 Glossrio 115


Aprenda Computao com Python Documentation, Verso 1.1

cpia rasa (shallow copy) Ato de copiar o contedo de um objeto, incluindo as referncias a objetos embutidos (XXX
embedded); implementada pela funo copy do mdulo copy.
cpia profunda (deep copy) Ato de copiar o contedo de um objeto, bem como dos objetos embutidos (XXX em-
bedded), e dos objetos embutidos nestes, e assim por diante; implementada pela funo deepcopy do mdulo
copy.

116 Captulo 14. Captulo 12: Classes e objetos


CAPTULO 15

Captulo 13: Classes e funes

Tpicos
Captulo 13: Classes e funes
13.1 Horario
13.2 Funes Puras
13.3 Modificadores
13.4 O que melhor ?
13.5 Desenvolvimento Prototipado versus Desenvolvimento Planejamento
13.6 Generalizao
13.7 Algoritmos
13.8 Glossrio

15.1 13.1 Horario

Como exemplo de outro tipo definido pelo usurio, vamos definir uma classe chamada Horario que grava os registros
de horrio do dia. Eis a definio da classe:
class Horario:
pass

Podemos criar uma nova instncia de Horario e determinar atributos para horas, minutos e segundos:
horario = Horario()
horario.horas = 11
horario.minutos = 59
horario.segundos = 30

O diagrama de estado para o objeto Horario parece com isso:

117
Aprenda Computao com Python Documentation, Verso 1.1

Como exerccio, escreva uma funo imprimirHorario que tenha como argumento um objeto Horario e
imprima-o na forma horas:minutos:segundos.
Como um segundo exerccio, escreva uma funo booleana que tenha como argumento dois objetos Ho-
rario, h1 e h2, e retorne verdadeiro (1) se h1 vem depois de h2 cronologicamente, do contrrio, retorne
falso (0).

15.2 13.2 Funes Puras

Nas prximas sesses, vamos escrever duas verses de uma funo chamada adicionaHorario, que calcula a
soma de dois horrios. Elas vo demonstrar 2 tipos de funes: funes puras e funes modificadoras.
Segue uma verso tosca de somaHorario:
def somaHorario(h1, h2):
soma = Horario()
soma.horas = h1.horas + h2.horas
soma.minutos = h1.minutos + h2.minutos
soma.segundos = h1.segundos + h2.segundos
return soma

A funo cria um novo objeto Horario, inicializa os seus atributos, e retorna uma referncia para o novo objeto. Isso
chamado de funo pura pois ela no modifica nenhum dos objetos que so passados como parmetros e no tem
nenhum efeito colateral, como imprimir um valor ou pegar entrada do usurio.
Aqui est um exemplo de como usar esta funo. Ns vamos criar dois objetos Horario: horarioAtual, que
contm o horrio atual; e horarioDoPao, que contm a quantidade de tempo que a mquina de fazer po gasta
para fazer po. Ento vamos usar somaHorario para tentar saber quando o po estar pronto. Se voc no tiver
terminado de escrever imprimirHorario ainda, de uma olhada na seo 14.2 antes de voc continuar isso:
>>> horarioAtual = Horario()
>>> horarioAtual.horas = 9
>>> horarioAtual.minutos = 14
>>> horarioAtual.segundos = 30

>>> horarioDoPao = Horario()


>>> horarioDoPao.horas = 3
>>> horarioDoPao.minutos = 35
>>> horarioDoPao.segundos = 0

>>> horarioTermino = somaHorario(horarioAtual, horarioDoPao)


>>> imprimirHorario(horarioTermino)

A sada deste programa 12:49:30, o que correto. Por outro lado, existem casos onde o resultado no correto. Voc
pode pensar em algum ?

118 Captulo 15. Captulo 13: Classes e funes


Aprenda Computao com Python Documentation, Verso 1.1

O problema que esta funo no lida com casos onde o nmero de segundos ou minutos acrescentado em mais de
sessenta. Quando isso acontece, temos de transportar os segundos extras para a coluna dos minutos ou os minutos
extras na coluna das horas.
Aqui est a segunda verso corrigida da funo:
def somaHorario(t1, t2):
soma = Horario()
soma.horas = t1.horas + t2.horas
soma.minutos = t1.minutos + t2.minutos
soma.segundos = t1.segundos + t2.segundos

if soma.segundos >= 60:


soma.segundos = soma.segundos - 60
soma.minutos = soma.minutos + 1

if soma.minutos >= 60:


soma.minutos = soma.minutos - 60
soma.horas = soma.horas + 1

return soma

Apesar desta funo estar correta, ela est comeando a ficar grande. Depois vamos sugerir uma aproximao alterna-
tiva que rende um cdigo menor. Clique aqui para feedback

15.3 13.3 Modificadores

Existem momentos quando til para uma funo modificar um ou mais dos objetos que ela recebe como parmetro.
Usualmente, quem est chamando a funo mantm uma referncia para os objetos que ele passa, de forma que
quaisquer mudanas que a funo faz so visveis para quem est chamando. Funes que trabalham desta forma so
chamadas modificadores.
incrementar, que adiciona um nmero dado de segundos para um objeto Horario, que poderia ser escrito quase
naturalmente como um modificador. Um rascunho tosco da funo seria algo parecido com isso:
def incrementar(horario, segundos):
horario.segundos = horario.segundos + segundos

if horario.segundos >= 60:


horario.segundos = horario.segundos - 60
horario.minutos = horario.minutos + 1

if horario.minutos >= 60:


horario.minutos = horario.minutos - 60
horario.horas = horario.horas + 1

A primeira linha executa a operao bsica; o resto lida com os caso especiais que vimos antes.
Esta funo esta correta ? O que aconteceria se o parametro segundos for muito maior que sessenta ? Nesse caso, no
suficiente transportar apenas uma vez; teramos de continuar fazendo isso at que segundos seja menor que sessenta.
Uma soluo seria substituir os comando if por comandos while:
def incrementar(horario, segundos):
horario.segundos = horario.segundos + segundos

while horario.segundos >= 60:


horario.segundos = horario.segundos - 60
horario.minutos = horario.minutos + 1

15.3. 13.3 Modificadores 119


Aprenda Computao com Python Documentation, Verso 1.1

while horario.minutos >= 60:


horario.minutos = horario.minutos - 60
horario.horas = horario.horas + 1

Esta funo agora esta correta, mas no a soluo mais eficiente.


Como um exerccio, reescreva esta funo de maneira que ela no contenha nenhum loop. Como um segundo exerccio,
reescreva incrementar como uma funo pura, e escreva chamadas de funes para as duas funes. Clique aqui
para feedback

15.4 13.4 O que melhor ?

Qualquer coisa que pode ser feita com modificadores tambm podem ser feitas com funes puras. De fato, algumas
linguagens de programao permitem apenas funes puras. Existe alguma evidncia que programas que usam funes
puras so desenvolvidos mais rapidamente e so menos propensos a erros que programas que usam modificadores. No
entanto, modificadores as vezes so convenientes, e em alguns casos, programao funcional menos eficiente.
Em geral, recomendamos que voc escreva funes puras sempre que for necessrio e recorrer para modificadores so-
mente se existir uma grande vantagem. Esta aproximao poderia ser chamada de um estilo de programao funcional.
Clique aqui para feedback

15.5 13.5 Desenvolvimento Prototipado versus Desenvolvimento


Planejamento

Neste captulo, demonstramos uma aproximao para o desenvolvimento de programas que chamamos de desenvolvi-
mento prototipado. Em cada caso, escrevemos um rascunho tosco (ou prototipo) que executou os clculos bsicos e
ento, o testamos em uns poucos casos, corrigindo ento, as falhas que fomos encontrando.
Embora esta aproximao possa ser eficaz, ela pode conduzir para cdigo que desnecessariamente complicado desde
que trata de muitos casos especiais e unreliable desde que difcil saber se voc encontrou todos os erros.
An alternative is planned development, in which high-level insight into the problem can make the programming much
easier. In this case, the insight is that a Time object is really a three-digit number in base 60! The second component is
the ones column, the minute component is the sixties column, and the hourcomponent is the thirty-six hundreds
column.
When we wrote addTime and increment, we were effectively doing addition in base 60, which is why we had to carry
from one column to the next.
This observation suggests another approach to the whole problem we can convert a Time object into a single number
and take advantage of the fact that the computer knows how to do arithmetic with numbers. The following function
converts a Timeobject into an integer:
def converterParaSegundos(t):
minutos = t.horas * 60 + t.minutos
segundos = minutos * 60 + t.segundos
return segundos

Agora, tudo que precisamos uma maneira de converter de um inteiro para um objeto Horario:
def criarHorario(segundos):
horario = Time()
horario.horas = segundos/3600
segundos = segundos - horario.horas * 3600

120 Captulo 15. Captulo 13: Classes e funes


Aprenda Computao com Python Documentation, Verso 1.1

horario.minutos = segundos/60
segundos = segundos - horario.minutos * 60
horario.segundos = segundos
return horario

Voc deve ter que pensar um pouco para se convencer que esta tcnica de converter de uma base para outra correta.
Assumindo que voc est convencido, voc pode usar essas funes para reescrever somaHorario:
def somaHorario(t1, t2):
segundos = converterParaSegundos(t1) + converterParaSegundos(t2)
return criarHorario(segundos)

Esta verso muito mais curta que a original, e muito mais fcil para demonstrar que est correta (assumindo, como
sempre, que as funes que so chamadas esto corretas).
Como um exerccio, reescreva incrementar da mesma forma. Clique aqui para feedback

15.6 13.6 Generalizao

Algumas vezes, converter de base 60 para base 10 e voltar mais difcil do que simplesmente lidar com horrios.
Converso de base mais abstrata; nossa intuio para lidar com horrios melhor.
Mas se XXXX But if we have the insight to treat times as base 60 numbers and make the investment of writing the
conversion functions (converterParaSeguntos e criarHorario), ns conseguimos um programa que menor, fcil de ler
e depurar, e mais confivel.
tambm fcil para adicionar funcionalidades depois. Por exemplo, imagine subtrair dois Horarios para encontrar
a durao entre eles. Uma aproximao ingnua seria implementar subtrao com emprstimo (?? borrowing - Isso
mesmo ??). Usando as funes de converso ser mais fcil e provavelmente estar correto.
Ironicamente, algumas vezes fazer um problema mais difcil (ou mais genrico) o torna mais simples (porque existem
alguns poucos casos especiais e poucas oportunidades para errar). Clique aqui para feedback

15.7 13.7 Algoritmos

Quando voc escreve uma soluo genrica para uma classe de problemas, ao contrrio de uma soluo especfica para
um nico problema, voc escreveu um algortmo. Ns mencionamos isso antes mas no definimos cuidadosamente.
Isso no fcil para definir, ento ns vamos tentar //a couple of approaches//.
Primeiramente, considere alguma coisa que no seja um algortmo. Quando voc aprendeu a multiplicar nmeros de
um dgito, voc provavelmente memorizou a tabela de multiplicao. Como resultado, voc memorizou 100 solues
especficas. Esse tipo de conhecimento no algortmo.
Mas se voc preguioso, voc provavelmente trapaceou por ter aprendido alguns truques. Por exemplo, para
encontrar o produto de n e 9, voc pode escrever n-1 como o primeiro dgito e 10-n como o segundo dgito. Este
truque um soluo genrica para multiplicar qualquer nmero de um dgito por 9. Isso um algoritmo!
De modo parecido, as tcnicas que voc aprendeu para adicionar //com transporte//, //subtraction with borrowing//,
e diviso longa so todas algortmos. Uma das caractersticas dos algortmos que eles no requerem nenhuma
inteligncia para serem executados ( carry out ). Eles so processos mecnicos no qual cada passo segue o ltimo de
acordo com um conjunto simples de regras.
Na nossa opinio, preocupante que humanos gastem tanto tempo na escola aprendendo a executar algoritmos que,
literalmente, no requerem inteligncia.

15.6. 13.6 Generalizao 121


Aprenda Computao com Python Documentation, Verso 1.1

Por outro lado, o processo de projetar algoritmos interessante, intelectualmente desafiante, e uma parte central
daquilo que chamamos programao.
Algumas das coisas que as pessoas fazem naturalmente, sem dificuldade ou conscincia, so as mais difceis de se
expressar atravs de algoritmos. Entender a linguagem natural um bom exemplo. Todos ns fazemos isso, mas
at hoje ningum conseguiu explicar como fazemos isso, pelo menos no na forma de algoritmo. Clique aqui para
feedback.

15.8 13.8 Glossrio

funo pura (pure function) Uma funo que no modifica nenhum dos objetos que ela recebe como parmetro. A
maioria das funes puras frutfera.
modificador (modifier) Uma funo que muda um ou mais dos objetos que ela recebe como parmetros. A maioria
dos modificadores nula.
estilo de programao funcional (functional programming style) Um estilo de programao onde a maioria das
funes so puras.
desenvolvimento prototipado (prototype development) Uma maneira de desenvolver programas comeando com um
prottipo e gradualmente melhorando-o.
desenvolvimento planejado (planned development) Uma maneira de desenvolver programas que envolvem uma per-
cepo de alto nvel do problema e mais planejamento do que desenvolvimento incremental ou desenvolvimento
prototipado.
algoritmo (algorithm) Um conjunto de instrues para resolver uma classe de problemas usando um processo
mecnico, no inteligente.

122 Captulo 15. Captulo 13: Classes e funes


CAPTULO 16

Captulo 14: Classes e mtodos

Tpicos
Captulo 14: Classes e mtodos
14.1 Caractersticas da orientao a objetos
14.2 exibeHora (printTime)
14.3 Um outro exemplo
14.4 Um exemplo mais complicado
14.10 Glossrio

ATENO As referncias cruzadas a nomes em cdigos de outros captulos (especialmente 13) ainda no foram
unificadas...

16.1 14.1 Caractersticas da orientao a objetos

Python uma linguagem de programao orientada a objetos, o que significa que ela tem caractersticas que
suportam a programao orientada a objetos.
No fcil definir programao orientada a objetos, mas temos visto already algumas de suas caractersticas:
Programas so construdos sobre definies de objetos e definies de funes, e a maioria das computaes
expressa em termos de operaes sobre objetos.
Cada definio de objeto corresponde a algum objeto ou conceito do mundo real, e as funes que operam com
aqueles objetos correspondem maneira como os objetos do mundo real interagem.
Por exemplo, a classe Tempo, definida no captulo 13 corresponde maneira como as pessoas registram as horas do
dia, e as funes que definimos correspondem aos tipos de coisas que as pessoas fazem com times. Do mesmo modo,
as classes Ponto e Retngulo correspondem aos conceitos matemticos de um ponto e de um retngulo.
At aqui, no tiramos vantagem das caractersticas fornecidas por Python que suportam a programao orientada a
objetos. Estritamente falando, estas caractersticas no so necessrias. Na maior parte das vezes, elas fornecem uma
sintaxe alternativa para as coisas que j fizemos, mas em muitos casos, a alternativa mais concisa e convm mais
acuradamente estrutura do programa.
Por exemplo, no programa Time, no existe uma conexo bvia entre a definio da classe e a definio da funo
que segue. Com alguma investigao, fica aparente que toda funo toma pelo menos um objeto Time como um
parmetro.

123
Aprenda Computao com Python Documentation, Verso 1.1

Esta observao a motivao por trs dos mtodos. J temos visto alguns mtodos, tais como keys (chaves)
e values (valores), os quais foram invocados em dicionrios. Cada mtodo associado com uma classe e
intended para ser invocado em instncias daquela classe.
Mtodos so simplesmente como funes, com duas diferenas:
Mtodos so definidos dentro da definio de uma classe para tornar explcita a relao entre a classe e o mtodo.
A sintaxe para a chamada do mtodo diferente da sintaxe para a chamada de uma funo.
Nas prximas sees, vamos pegar as funes dos dois captulos anteriores e transform-las em mtodos. Esta trans-
formao puramente mecnica: voc pode consegu-la simplesmente seguindo uma seqncia de passos. Se voc se
sentir confortvel convertendo de uma forma para a outra, voc estar apto para escolher a melhor forma para seja o
l o que for que voc estiver fazendo.

16.2 14.2 exibeHora (printTime)

No captulo 13, definimos uma classe chamada Horrio (Time) e voc escreveu uma funo chamada exibeHora
(printTime), que deve ter ficado mais ou menos assim:
class Horario:
pass

def exibeHora(time)
print str(time.horas) + ?:? + \
str(time.minutos) + ?:? + \
str(time.segundos)

Para chamar esta funo, passamos um objeto Time como um parmetro:


>>> horaCorrente = Hora()
>>> horaCorrente.horas = 9
>>> horaCorrente.minutos = 14
>>> horaCorrente.segundos = 30
>>> exibeHora(horaCorrente)

Para fazer de exibeHora um mtodo, tudo o que temos a fazer mover a definio da funo para dentro da definio
da classe. Note a mudana na endentao:
class Horario:
def exibeHora(time):
print str(time.horas) + ?:? + \
str(time.minutos) + ?:? + \
str(time.segundos)

Agora podemos chamar exibeHora usando a natao de ponto:


>>> horaCorrente.exibeHora()

Como usual, o objeto no qual o mtodo invocado aparece antes do ponto e o nome do mtodo aparece depois do
ponto.
O objeto no qual o mtodo invocado atribudo ao primeiro parmetro, ento, neste caso, horaCorrente
atribudo ao parmetro time.
Por conveno, o primeiro parmetro de um mtodo chamado self. A razo para isto um pouco convoluted, mas
baseada numa metfora til.
A sintaxe para uma chamada de funo, exibeHora(horaCorrente), sugere que a funo um agente ativo.
Diz algo como, ?Ei, exibeHora! Aqui est um objeto para voc exibir.?

124 Captulo 16. Captulo 14: Classes e mtodos


Aprenda Computao com Python Documentation, Verso 1.1

Na programao orientada a objetos, os objetos so agentes ativos. Uma chamado do tipo


horaCorrente.exibeHora() diz ?Ei, horaCorrente! Por favor exiba-se a si mesmo!?
Esta mudana de perspectiva pode ser mais polida, mas no fica bvio que seja til. Nos exemplos que temos visto
at aqui, pode ser que no seja. Mas s vezes, deslocar a responsabilidade das funes para cima dos objetos torna
possvel escrever funes mais versteis, e torna mais fcil manter e reutilizar o cdigo.

16.3 14.3 Um outro exemplo

Vamos converter incremento (da Seo 13.3) em um mtodo. Para poupar espao, deixaremos de fora mtodos
definidos previamente(anteriormente?), mas voc deve mant-los em sua verso:
class Time:
#previous method definitions here...

def increment(self, segundos):


self.seconds = seconds + self.seconds

while self.segundos >= 60:


self.seconds = self.segundos - 60
self.minutes = self.minutos + 1

while self.minutes >= 60:


self.minutes = self.minutos - 60
self.hours = self.horas + 1

A transformao puramente mecnica ? movemos a definio do mtodo para dentro da definio da classe e
mudamos o nome do primeiro parmetro.
Agora podemos chamar incremento como um mtodo:
horaCorrente.incremento(500)

De novo, o objeto no qual o mtodo chamado gets atribui ao primeiro parmetro, self. O segundo parmetro,
segundo toma(gets) o valor 500.
Como um exerccio, converta ?converteParaSegundos? (da Seo 13.5) para um mtodo na classe
?Time?.

16.4 14.4 Um exemplo mais complicado


...

16.5 14.10 Glossrio

linguagem orientada a objetos Uma linguagem que prov caractersticas tais como classes definidas pelo usurio e
herana, que facilitam a programao orientada a objetos.
programao orientada a objetos Um estilo de programao na qual os dados e as operaes que os manipulam
esto organizados em classes e mtodos.
mtodo Uma funo que definida dentro de uma definio de classe e chamada em instncias desta classe.

16.3. 14.3 Um outro exemplo 125


Aprenda Computao com Python Documentation, Verso 1.1

override (sem traducao; termo consagrado) Substituir uma definio j pronta. Exemplos incluem substituir um
parmetro padro por um argumento particular e substituir um mtodo padro, fornecendo um novo mtodo
com o mesmo nome.
mtodo de inicializao (tambem chamado de construtor) Um mtodo especial que invocado automaticamente
quando um novo objeto criado e que inicializa os atributos deste objeto.
sobrecarga de operador Estender a funcionalidade dos operadores nativos (+, -, *, >, <, etc.) de forma que eles
funcionem tambm com tipos definidos pelo usurio.
produto escalar Operao definida na lgebra linear que multiplica dois pontos (com coordenadas (x,y,z)) e retorna
um valor numrico.
multiplicao por escalar Operao definida na lgebra linear que multiplica cada uma das coordenadas de um ponto
por um valor numrico.
polimrfica Uma funo que pode operar com mais de um tipo. Se todas as operaes de uma funo pode ser
aplicadas a um certo tipo, ento a funo pode ser aplicada a este tipo.

126 Captulo 16. Captulo 14: Classes e mtodos


CAPTULO 17

Captulo 15: Conjuntos de objetos

Tpicos
Captulo 15: Conjuntos de objetos
15.1 Composio
15.2 Objetos Carta
15.3 Atributos de classe e o mtodo __str__
15.4 Comparando cartas
15.5 Baralhos
15.6 Imprimindo o baralho
15.7 Embaralhando
15.8 Removendo e distribuindo cartas
15.9 Glossrio

17.1 15.1 Composio

At agora, voc vio diversos exemplos de composio. Um dos primeiros exemplos foi o uso de uma invocao
de mtodo como parte de uma expresso. Outro exemplo a estrutura aninhada dos comandos: voc pode pr um
comando if dentro de um lao while, dentro de outro comando if, e assim por diante.
Tendo visto este padro, e tendo aprendido a respeito de listas e objetos, voc no deveria ficar surpreso em aprender
que voc pode criar listas de objetos. Voc tambm pode criar obejtos que contm listas (como atritos); voc pode
criar listas que contm listas; voc pode criar objetos que contm objetos; e assim por diante.
Neste captulo e no prximo, voc ir ver alguns exemplos destas combinaes, usando objetos Carta como exemplo.

17.2 15.2 Objetos Carta

Se voc no estiver familiarizado com jogos de cartas, agora um bom momento para conseguir um baralho, ou ento
esse captulo pode no fazer muito sentido. H 52 cartas em um baralho, cada uma das quais pertence a um dos quatro
naipes e a uma das treze posies. Os naipes so Espadas, Copas, Ouros e Paus (em ordem descendente no bridge).
As posies so s, 2, 3, 4, 5, 6, 7, 8, 9, 10, Valete, Rainha e Rei. Dependendo do jogo, a posio do s pode ser
maior do que a do Rei ou menor do que a do 2.

127
Aprenda Computao com Python Documentation, Verso 1.1

Se quisermos definir um novo objeto para representar uma carta, bvio que os atributos devem ser posicao e
naipe. No to bvio so os tipos aos quais devem pertencer os atributos. Uma possibilidade usar strings contendo
palavras como Espada para naipes e Rainha para posies. Um problema com esta implementao que no
seria fcil comparar cartas para ver qual possui o maior naipe ou posio.
Uma alternativa usar inteiros para codificar as posies e naipes. Codificar, neste caso, no significa o mesmo
que as pessoas normalmente pensam, que criptografar ou traduzir para um cdigo secreto. O que um cientista da
computao quer dizer com codificar definir um mapeamento entre uma seqncia de nmeros e os itens que eu
quero representar. Por exemplo:
Espadas -> 3
Copas -> 2
Ouros -> 1
Paus -> 0
Uma caracterstica bvia deste mapeamento que os naipes so mapeados para inteiros na ordem, de modo que ns
podemos comparar naipes pela comparao de inteiros. O mapeamento de posies bastante bvio. Cada uma das
posies numricas mapeia para o inteiro correspondente e, as cartas com figura so mapeadas conforme abaixo:
Valete -> 11
Rainha -> 12
Rei -> 13
O motivo pelo qual ns estamos usando notao matemtica para estes mapeamentos que eles no so parte do
programa Python. Eles so parte do projeto do programa, mas eles nunca aparecem explicitamente no cdigo. A
definio de classe para o tipo Carta fica parecida com esta:
class Carta:
def __init__(self, naipe=0, posicao=0):
self.naipe = naipe
self.posicao = posicao

Como sempre, ns fornecemos um mtodo de inicializao que recebe um parmetro opcional para cada atributo.
Para criar um objeto que representa o 3 de Paus, usa-se este comando:
tresDePaus = Carta(0, 3)

O primeiro argumento, 0, representa o naipe de Paus.

17.3 15.3 Atributos de classe e o mtodo __str__

Para imprimir objetos Carta de uma maneira que as pessoas possam facilmente ler, ns gostaramos de mapear os
cdigos inteiros para palavras. Uma forma natural de fazer isso usar listas de strings. Ns atribumos estas listas
para atributos de classe no topo da definio de classe:
class Carta:
listaDeNaipes = ["Paus", "Ouros", "Copas", "Espadas"]
listaDePosicoes = ["narf", "s", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Valete", "Rainha", "Rei"]

# mtodo init omitido

def __str__(self):

128 Captulo 17. Captulo 15: Conjuntos de objetos


Aprenda Computao com Python Documentation, Verso 1.1

return (self.listaDePosicoes[self.posicao] + " de " +


self.ListaDeNaipes[self.naipe])

Um atributo de classe definido fora de qualquer mtodo, e ele pode ser acessado por quaisquer mtodos da classe.
Dentro de __str__, ns podemos usar listaDeNaipes e listaDePosicoes para mapear os valores numri-
cos de naipe e posicao para strings. Por exemplo, a expresso self.listaDeNaipes[self.naipe] sig-
nifica use o atributo naipe do objeto self como um ndice para o atributo de classe chamado listaDeNaipes,
e selecione a string apropriada.
O motivo para o narf no primeiro elemento em listaDePosicoes preencher o lugar do 0-simo elemento
da lista, que nunca ser usado. As nicas posies vlidas so de 1 a 13. Este item desperdiado no inteiramente
necessrio. Ns poderamos ter iniciado com 0, como normal. Porm, menos confuso codificar 2 como 2, 3 como
3, e assim por diante.
Com os mtodos que ns temos at agora, ns podemos criar e imprimir cartas:
>>> carta1 = Carta(1, 11)
>>> print carta1
Valete de Ouros

Atributos de classe como listaDeNaipes so compartilhados por todos os objetos Carta. A vantagem disso
que ns podemos usar qualquer objeto Carta para acessar os atributos de classe:
>>> carta2 = Carta(1, 3)
>>> print carta2
3 de Ouros
>>> print carta2.listaDeNaipes[1]
Ouros

A desvantagem que se ns modificarmos um atributo de classe, isso afetar cada instncia da classe. Por exemplo, se
ns decidirmos que Valete de Ouros deveria realmente se chamar Valete de Baleias Rodopiantes, ns poderamos
fazer isso:
>>> carta1.listaDeNaipes[1] = "Baleias Rodopiantes"
>>> print carta1
Valete de Baleias Rodopiantes

O problema que todos os Ouros se tornam Baleias Rodopiantes:


>>> print carta2
Valete de Baleias Rodopiantes

Normalmente, no uma boa idia modificar atributos de classe.

17.4 15.4 Comparando cartas

Para tipos primitivos, existem operadores condicionais (<, >, ==, etc.) que comparam valores e determinam quando um
maior que, menor que ou igual a outro. Para tipos definidos pelo usurio, ns podemos sobrescrever o comportamento
dos operadores pr-definidos fornecendo um mtodo __cmp__. Por conveno, __cmp__ recebe dois parmetros,
self e other, e retorna 1 se o primeiro objeto for maior, -1 se o segundo objeto for maior, e 0 se eles forem iguais.
Alguns tipos so totalmente ordenados, o que significa que ns podemos comparar quaisquer dois elementos e dizer
qual o maior. Por exemplo, os inteiros e os nmeros de ponto flutuante so totalmente ordenados. Alguns conjuntos
so no-ordenados, o que significa que no existe maneira significativa de dizer que um elemento maior que o outro.
Por exemplo, as frutas so no-ordenadas, e por isso que no podemos comparar mas e laranjas.

17.4. 15.4 Comparando cartas 129


Aprenda Computao com Python Documentation, Verso 1.1

O conjunto de cartas de jogo parcialmente ordenado, o que significa que s vezes voc pode comparar cartas, e s
vezes no. Por exemplo, voc sabe que o 3 de Paus maior do que o 2 de Paus, e que o 3 de Ouros maior do que o 3
de Paus. Mas qual o melhor, o 3 de Paus ou o 2 de Ouros? Um tem uma posio maior, mas o outro tem um naipe
maior.
Para tornar as cartas comparveis, voc tem que decidir o que mais importante: posio ou naipe. Para ser honesto,
a escolha arbitrria. Por questo de escolha, ns iremos dizer que naipe mais importante, porque um baralho de
cartas novo vem ordenado com todas as cartas de Paus juntas, seguidas pelas de Ouros, e assim por diante.
Com essa deciso, ns podemos escrever __cmp__:
def __cmp__(self, other):
# verificar os naipes
if self.naipe > other.naipe: return 1
if self.naipe < other.naipe: return -1
# as cartas tm o mesmo naipe... verificar as posies
if self.posicao > other.posicao: return 1
if self.posicao < other.posicao> return -1
# as posies so iguais... um empate
return 0

Nesta ordenao, Ases so menores do que 2.


Como um exerccio, modifique __cmp__, de modo que os Ases sejam maiores do que os Reis.

17.5 15.5 Baralhos

Agora que ns temos objetos para representar Cartas, o prximo passo lgico definir uma classe para representar
um Baralho. claro que um baralho formado por cartas; portanto, cada objeto Baralho ir conter uma lista de
cartas como um atributo.
A seguir, damos uma definio para a classe Baralho. O mtodo de inicializao cria o atributo cartas e gera o
conjunto padro de 52 cartas:
classe Baralho
def __init__(self):
self.cartas = []
for naipe in range(4):
for posicao in range(1, 14):
self.cartas.append(Carta(naipe, posicao))

A maneira mais fcil de popular o baralho com um lao aninhado. O lao externo enumera os naipes de 0 at 3.
O lao interno enumera as posies de 1 at 13. Como o lao externo repete quatro vezes e o lao interno 13 vezes,
o nmero total de vezes que o corpo executado 52 (13 vezes quatro). Cada iterao cria uma nova instncia de
Carta com o naipe e posio atuais e a inclui na lista cartas.
O mtodo append trabalha sobre listas mas no, obviamente, sobre tuplas.

17.6 15.6 Imprimindo o baralho

Como sempre, quando ns definimos um novo tipo de objeto, ns gostaramos de ter um mtodo para imprimir o
contedo de um objeto. Para imprimir um Baralho, ns percorremos a lista e imprimimos cada Carta:
class Baralho:
...
def imprimirBaralho(self):

130 Captulo 17. Captulo 15: Conjuntos de objetos


Aprenda Computao com Python Documentation, Verso 1.1

for carta in self.cartas:


print carta

Aqui, e a partir daqui, as reticncias (...) indicam que ns omitimos os outros mtodos da classe.
Como uma alternativa a imprimirBaralho, ns poderamos escrever um mtodo __str__ para a classe
Baralho. A vantagem de __str__ que ela mais flexvel. Em vez de apenas imprimir o contedo de um
objeto, ela gera uma representao em string que outras partes do programa podem manipular antes de imprimir ou
armazenar para uso posterior.
Abaixo, uma verso de __str__ que devolve uma representao em string de um Baralho. Para adicionar um
pouco de estilo, ela distribui as cartas em uma cascata, na qual cada carta indentada um espao a mais do que a carta
anterior:
class Baralho:
...
def __str__(self):
s = ""
for i in range(len(self.cartas)):
s = s + " "*i + str(self.cartas[i]) + "\n"
return s

Este exemplo demonstra diversas caractersticas. Primeiro, em vez de percorrer self.cartas e atribuir cada carta
a uma varivel, ns estamos usando i como uma varivel de lao e um ndice para a lista de cartas.
Segundo, ns estamos usando o operador de multiplicao de strings para indentar cada carta com um espao adicional
com relao anterior. A expresso " "*i produz um nmero de espaos igual ao valor atual de i.
Terceiro, em vez de usar o comando print para imprimir as cartas, ns usamos a funo str. Passar um objeto
como um argumento para str equivale a invocar o mtodo __str__ sobre o objeto.
Finalmente, ns estamos usando a varivel s como um acumulador. Inicialmente, s a string vazia. A cada repetio
do lao, uma nova string gerada e concatenada com o valor antigo de s para obter um novo valor. Quando o lao
termina, s contm a representao em string completa do Baralho, que se parece com:
>>> baralho = Baralho()
>>> print Baralho
s de Paus
2 de Paus
3 de Paus
4 de Paus
5 de Paus
6 de Paus
7 de Paus
8 de Paus
9 de Paus
10 de Paus
Valete de Paus
Rainha de Paus
Rei de Paus
s de Ouros

E assim por diante. Mesmo que o resultado aparea em 52 linhas, uma string longa que contm newlines.

17.7 15.7 Embaralhando

Se um baralho estiver perfeitamente embaralhado, ento cada carta tem a mesma probabilidade de aparecer em qual-
quer lugar no baralho, e qualquer localizao no baralho tem a mesma probabilidade de conter qualquer carta.

17.7. 15.7 Embaralhando 131


Aprenda Computao com Python Documentation, Verso 1.1

Para embaralhar as cartas, ns usaremos a funo randrange do mdulo random. Com dois argumentos inteiros,
a e b, randrange escolhe um inteiro aleatrio no intervalo a <= x < b. Como o limite superior estritamente
menor que b, ns podemos usar o comprimento de uma lista como o segundo parmetro, e ns garantimos que o ndice
sempre ser vlido. Por exemplo, esta expresso escolhe o ndice de uma carta aleatria em um baralho:
random.randrange(0, len(self.cartas))

Uma maneira fcil de embaralhar as cartas percorrer a lista e trocar cada carta por outra escolhida aleatoriamente.
possvel que a carta seja trocada por ela mesma, mas isso no problema. Na verdade, se ns exclussemos essa
possibilidade, a ordem das cartas no seria totalmente aleatria:
class Baralho:
...
def embaralhar(self):
import random
nCartas = len(self.cartas)
for i in range(nCartas):
j = random.randrange(i, nCartas)
self.cartas[i], self.cartas[j] = self.cartas[j], self.cartas[i]

Em vez de assumir que existem 52 cartas no baralho, ns obtivemos o comprimento real da lista e o guardamos na
varivel nCartas.
Para cada carta no baralho, ns escolhemos uma carta aleatria dentre as cartas que ainda no foram embaralhadas.
Ento, ns trocamos a carta atual (i) pela carta selecionada (j). Para trocar as cartas, ns usamos uma atribuio de
tupla, como visto na Seo 9.2:
self.cartas[i], self.cartas[j] = self.cartas[j], self.cartas[i]

Como exerccio, reescreva esta linha de cdigo sem usar uma atribuio de seqncia.

17.8 15.8 Removendo e distribuindo cartas

Outro mtodo que pode ser til para a classe Baralho removerCarta. Ele recebe uma carta como parmetro,
remove-a do baralho e retorna verdadeiro (1), se a carta estava no baralho e falso (0), caso contrrio:
class Baralho:
...
def removerCarta(self, carta):
if carta in self.cartas:
self.cartas.remove(carta)
return 1
else
return 0

O operador in retorna verdadeiro se o primeiro operando estiver contido no segundo, que deve ser uma lista ou
uma tupla. Se o primeiro operando for um objeto, Python usa o mtodo __cmp__ do objeto para determinar igual-
dade com os itens da lista. Como o mtodo __cmp__ da classe Carta verifica por igualdade profunda, o mtodo
removerCarta tambm testa por igualdade profunda.
Para distribuir as cartas, ns iremos remover e devolver a carta do topo. O mtodo de lista pop fornece uma maneira
conveniente de fazer isso:
class Baralho:
...
def distribuirCarta(self):
return self.cards.pop()

132 Captulo 17. Captulo 15: Conjuntos de objetos


Aprenda Computao com Python Documentation, Verso 1.1

Na verdade, pop remove a ltima carta da lista. Portanto, ns estamos realmente distribuindo as cartas do fim para o
incio do baralho.
Uma ltima operao que ns poderamos querer a funo booleana estahVazio, que retorna verdadeiro se o
baralho no contm cartas:
class Baralho:
...
def estahVazio(self):
return (len(self.cartas) == 0)

17.9 15.9 Glossrio

codificar (encode) Representar um conjunto de valores usando outro conjunto de valores, construindo um mapea-
mento entre eles.
atributo de classe (class atribute) Uma varivel que definida dentro de uma definio de classe, mas fora de qual-
quer mtodo. Atributos de classe podem ser acessados a partir de qualquer mtodo da classe e so compartilha-
dos por todas as instncias da classe.
acumulador (accumulator) Uma varivel usada em um lao para acumular uma srie de valores, para, por exemplo,
concaten-los em uma string ou som-los a uma soma em andamento.

17.9. 15.9 Glossrio 133


Aprenda Computao com Python Documentation, Verso 1.1

134 Captulo 17. Captulo 15: Conjuntos de objetos


CAPTULO 18

Capitulo 16: Herana

Tpicos
Capitulo 16: Herana
16.1 Herana
16.2 Uma mo de cartas
16.3 Dando as cartas
16.4 Exibindo a mao
16.5 A classe JogoDeCartas
16.6 Classe MaoDeMico
16.7 Classe Mico
16.8 Glossrio

18.1 16.1 Herana

Uma das caractersticas mais marcantes das linguagens orientadas a objetos a herana. Herana a habilidade de
definir uma nova classe que uma verso modificada de uma classe existente.
A principal vantagem dessa caracterstica que voc pode adicionar novos mtodos a uma classe sem ter que modificar
a classe existente. Chama-se herana porque a nova classe herda todos os mtodos da classe existente. Ampliando
a metfora, podemos dizer que a classe existente s vezes chamada de classe me (parent). A nova classe pode ser
chamada de classe filha ou, simplesmente, subclasse.
A herana uma caracterstica poderosa. Alguns programas que seriam complicados sem herana podem ser escritos
de forma simples e concisa graas a ela. E a herana tambm pode facilitar o reuso do cdigo, uma vez que voc
pode adaptar o comportamento de classes existentes sem ter que modific-las. Em alguns casos, a estrutura da herana
reflete a natureza real do problema, tornando o programa mais fcil de entender.
Por outro lado, a herana pode tornar um programa seja difcil de ler. Quando um mtodo invocado, s vezes no
est claro onde procurar sua definio. A parte relevante do cdigo pode ser espalhada em vrios mdulos. E, tambm,
muitas das coisas que podem ser feitas utilizando herana tambm podem ser feitas de forma igualmente elegante (ou
at mais) sem ela. Se a estrutura natural do problema no se presta a utilizar herana, esse estilo de programao pode
trazer mais problemas que vantagens.
Nesse captulo, vamos demonstrar o uso de herana como parte de um programa que joga uma variante de Mico. Um
dos nossos objetivos escrever um cdigo que possa ser reutilizado para implementar outros jogos de cartas.

135
Aprenda Computao com Python Documentation, Verso 1.1

18.2 16.2 Uma mo de cartas

Para quase todos os jogos de baralho, preciso representar uma mo de cartas. Uma mo de cartas similar a um
mao de baralho. Porque ambos so formados por uma srie de cartas e ambos requerem operaes, como, adicionar
e remover cartas. Fora isso, a habilidade de embaralhar a mo e o baralho tambm so teis.
Mas, ao mesmo tempo, a mo tambm diferente do baralho. Dependendo do jogo que est sendo jogado, precisamos
realizar algumas operaes nas mos de cartas que no fazem sentido para o baralho inteiro. Por exemplo, no pquer,
podemos classificar uma mo (trinca, flush, etc.) ou compar-la com outra mo. No jogo de bridge, podemos querer
computar a quantidade de pontos que h numa mo, a fim de fazer um lance.
Essa situao sugere o uso de herana. Se Mao uma subclasse de Baralho, ter todos os mtodos de Baralho, e
novos mtodos podem ser adicionados.
Na definio de classe, o nome da classe pai aparece entre parnteses:
class Mao(Baralho):
pass

Esse comando indica que a nova classe Mao herda da classe existente Baralho.
O construtor de Mao inicializa os atributos da mo, que so nome e cartas. A string nome identifica essa mo,
provavelmente pelo nome do jogador que est segurando as cartas. O nome um parmetro opcional com a string
vazia como valor default. cartas a lista de cartas da mo, inicializada com uma lista vazia
class Mao(Baralho):
def __init__(self, nome=""):
self.cartas = []
self.nome = nome

Em praticamente todos os jogos de cartas, necessario adicionar e remover cartas do baralho. Remover cartas j est
resolvido, uma vez que Mao herda removerCarta de Baralho. Mas precisamos escrever adicionarCarta:
class Mao(Baralho):
#...
def adicionarCarta(self,carta):
self.cartas.append(carta)

De novo, a elipse indica que omitimos outros mtodos. O mtodo de listas append adiciona a nova carta no final da
lista de cartas.

18.3 16.3 Dando as cartas

Agora que temos uma classe Mao, queremos distribuir cartas de Baralho para mos de cartas. No imediata-
mente bvio se esse mtodo deve ir na classe Mao ou na classe Baralho, mas como ele opera num nico baralho e
(possivelmente) em vrias mos de cartas, mais natural coloc-lo em Baralho.
O mtodo distribuir deve ser bem geral, j que diferentes jogos tero diferentes requerimentos. Podemos querer
distribuir o baralho inteiro de uma vez s ou adicionar uma carta a cada mo.
distribuir recebe dois argumentos, uma lista (ou tupla) de mos e o numero total de cartas a serem dadas. Se no
houver cartas suficientes no baralho, o mtodo d todas as cartas e pra:
class Baralho:
#...
def distribuir(self, maos, nCartas=999):
nMaos = len(maos)
for i in range(nCartas):

136 Captulo 18. Capitulo 16: Herana


Aprenda Computao com Python Documentation, Verso 1.1

if self.estahVazia(): break # interromper se acabaram as cartas


carta = self.pegarCarta() # pegar a carta do topo
mao = maos[i % nMaos] # quem deve receber agora?
mao.adicionarCarta(carta) # adicionar a carta mao

O segundo parmetro, nCartas, opcional; o default um nmero grande, o que na prtica significa que todas as
cartas do baralho sero dadas se este parmetro for omitido.
A varivel do lao i vai de 0 a nCartas-1. A cada volta do lao, uma carta removida do baralho, usando o mtodo
de lista pop, que remove e retorna o ltimo item na lista.
O operador mdulo (%) permite dar cartas em ao redor da mesa (uma carta de cada vez para cada mo). Quando i
igual ao numero de mos na lista, a expresso i % nMaos volta para o comeo da lista (ndice 0).

18.4 16.4 Exibindo a mao

Para exibir o contedo de uma mo, podemos tirar vantagem dos mtodos exibirBaralho e __str__ herdados
de Baralho. Por exemplo:
>>> baralho = Baralho()
>>> baralho.embaralhar()
>>> mao = Mao("fabio")
>>> baralho.distribuir([mao], 5)
>>> print mao
Mo fabio contm
2 de espadas
3 de espadas
4 de espadas
s de copas
9 de paus

Nao l uma grande mo, mas tem potencial para um straight flush.
Embora seja conveniente herdar os mtodos existentes, h outras informacoes num objeto Mao que podemos querer
incluir quando ao exib-lo. Para fazer isso, podemos fornecer um mtodo __str__ para a classe Mao que sobrescreva
o da classe Baralho:
class Mao(Baralho)
#...
def __str__(self):
s = "Mao " + self.nome
if self.estahVazia():
return s + " est vazia\n"
else:
return s + " contm\n" + Baralho.__str__(self)

Inicialmente, s uma string que identifica a mo. Se a mo estiver vazia, o programa acrescenta as palavras est
vazia e retorna o resultado.
Se no, o programa acrescenta a palavra contm e a representao de string do Baralho, computada pela invocao
do mtodo __str__ na classe Baralho em self.
Pode parecer estranho enviar self, que se refere Mao corrente, para um mtodo Baralho, mas isso s at voce se
lembrar que um Mao um tipo de Baralho. Objetos Mao podem fazer tudo que os objetos Baralho fazem, entao,
permitido passar uma instncia de Mao para um mtodo Baralho.
Em geral, sempre permitido usar uma instncia de uma subclasse no lugar de uma instncia de uma classe me.

18.4. 16.4 Exibindo a mao 137


Aprenda Computao com Python Documentation, Verso 1.1

18.5 16.5 A classe JogoDeCartas

A classe JogoDeCartas toma conta de algumas tarefas bsicas comuns a todos os jogos, como, criar o baralho e
embaralh-lo:
class JogoDeCartas:
def __init__(self):
self.baralho = Baralho()
self.baralho.embaralhar()

Este o primeiro dos casos que vimos at agora em que o mtodo de inicializao realiza uma computao significa-
tiva, para alm de inicializar atributos.
Para implementar jogos especficos, podemos herdar de JogoDeCartas e adicionar caracteristicas para o novo jogo.
Como exemplo, vamos escrever uma simulao de Mico.
O objetivo do jogo livrar-se das cartas que estiverem na mo. Para fazer isso, preciso combinar cartas formando
pares ou casais que tenham a mesma cor e o mesmo nmero ou figura. Por exemplo, o 4 de paus casa com o 4
de espadas porque os dois naipes so pretos. O Valete de copas combina com o Valete de ouros porque ambos so
vermelhos.
Antes de mais nada, a Dama de paus removida do baralho, para que a Dama de espadas fique sem par. A Dama
de espadas ento faz o papel do mico. As 51 cartas que sobram so distribuidas aos jogadores em ao redor da mesa
(uma carta de cada vez para cada mo). Depois que as cartas foram dadas, os jogadores devem fazer todos os casais
possveis que tiverem na mo, e em seguida descart-los na mesa.
Quando ningum mais tiver nenhum par para descartar, o jogo comea. Na sua vez de jogar, o jogador pega uma carta
(sem olhar) do vizinho mais proximo esquerda, que ainda tiver cartas. Se a carta escolhida casar com uma carta que
ele tem na mo, ele descarta esse par. Quando todos os casais possveis tiverem sido feitos, o jogador que tiver sobrado
com a Dama de espadas na mo perde o jogo.
Em nossa simulao computacional do jogo, o computador joga todas as mos. Infelizmente, algumas nuances do
jogo presencial se perdem. Num jogo presencial, o jogador que est com o mico na mo pode usar uns truques para
induzir o vizinho a pegar a carta, por exemplo, segurando-a mais alto que as outras, ou mais baixo, ou se esforando
para que ela no fique em destaque. J o computador simplesmente pega a carta do vizinho aleatoriamente...

18.6 16.6 Classe MaoDeMico

Uma mo para jogar Mico requer algumas habilidades para alem das habilidades gerais de uma Mao. Vamos definir
uma nova classe, MaoDeMico, que herda de Mao e prov um mtodo adicional chamado descartarCasais:
class MaoDeMico(Mao):
def descartarCasais(self):
conta = 0
cartasIniciais = self.cartas[:]
for carta in cartasIniciais:
casal = Carta(3 - carta.naipe, carta.valor)
if casal in self.cartas:
self.cartas.remove(carta)
self.cartas.remove(casal)
print "Mao %s: %s casais %s" % (self.nome,carta,casal)
conta = conta + 1
return conta

Comeamos fazendo uma cpia da lista de cartas, para poder percorrer a cpia enquanto removemos cartas do original.
Uma vez que self.cartas modificada no lao, no queremos us-la para controlar o percurso. Python pode ficar
bem confuso se estiver percorrendo uma lista que est mudando!

138 Captulo 18. Capitulo 16: Herana


Aprenda Computao com Python Documentation, Verso 1.1

Para cada carta na mo, verificamos qual a carta que faz par com ela e vamos procur-la. O par da carta tem o
mesmo valor (nmero ou figura) e naipe da mesma cor. A expresso 3 - carta.naipe transforma um paus
(naipe 0) numa espadas (naipe 3) e um ouros (naipe 1) numa copas (naipe 2). Voc deve analisar a frmula at se
convencer de que as operaes opostas tambm funcionam. Se o par da carta tambem estiver na mo, ambas as cartas
so removidas.
O exemplo a seguir demonstra como usar descartarCasais:
>>> jogo = JogoDeCartas()
>>> mao = MaoDeMico("fabio")
>>> jogo.baralho.distribuir([mao], 13)
>>> print mao
mo fabio contm
s de espadas
2 de ouros
7 de espadas
8 de paus
6 de copas
8 de espadas
7 de paus
Rainha de paus
7 de ouros
5 de paus
Valete de ouros
10 de ouros
10 de copas

>>> mao.descartarCasais()
Mo fabio: 7 de espadas faz par com 7 de paus
Mo fabio: 8 de espadas faz par com 8 de paus
Mo fabio: 10 de ouros faz par com 10 de copas
>>> print mao
Mo fabio contm
s de espadas
2 de ouros
6 de copas
Rainha de paus
7 de ouros
5 de paus
Valete de ouros

Observe que no existe um mtodo __init__ para a classe MaoDeMico. Ele herdado de Mao.

18.7 16.7 Classe Mico

Agora podemos focar nossa ateno no jogo em si. Mico uma subclasse de JogoDeCartas com um novo mtodo
chamado jogar que recebe uma lista de jogadores como argumento.
J que __init__ herdado de JogoDeCartas, um novo objeto Mico contm um novo baralho embaralhado:
class Mico(JogoDeCartas):
def jogar(self, nomes):
# remover a Dama de paus
self.baralho.removerCarta(Carta(0,12))

# fazer uma mo para cada jogador


self.maos = []

18.7. 16.7 Classe Mico 139


Aprenda Computao com Python Documentation, Verso 1.1

for nome in nomes :


self.maos.append(MaoDeMico(nome))

# distribuir as cartas
self.baralho.distribuir(self.maos)
print "---------- As cartas foram dadas"
self.exibirMaos()

# remover casais iniciais


casais = self.removerTodosOsCasais()
print "---------- Os pares foram descartados, o jogo comea"
self.exibirMaos()

# jogar at que 25 casais se formem


vez = 0
numMaos = len(self.maos)
while casais < 25:
casais = casais + self.jogarVez(vez)
vez = (vez + 1) % numMaos

print "---------- Fim do jogo"


self.exibirMaos()

Algumas etapas do jogo foram separadas em mtodos. removerTodosOsCasais percorre a lista de mos e invoca
descartarCasais em cada uma:
class Mico(JogoDeCartas):
#...
def removerTodosOsCasais(self):
conta = 0
for mao in self.maos:
conta = conta + mao.descartarCasais()
return conta

Como exerccio, escreva exibirMaos que percorre self.maos e exibe cada mo.

conta uma acumulador que soma o nmero de pares em cada mo e retorna o total.
Quando o nmero total de pares alcana 25, 50 cartas foram removidas das mos, o que significa que sobrou s uma
carta e o jogo chegou ao fim.
A varivel vez mantm controle sobre de quem a vez de jogar. Comea em 0 e incrementa de um em um; quando
atinge numMaos, o operador mdulo faz ela retornar para 0.
O mtodo jogarVez recebe um argumento que indica de quem a vez de jogar. O valor de retorno o nmero de
pares feitos durante essa rodada:
class Mico(JogoDeCartas):
#...
def jogarVez(self, i):
if self.maos[i].estahVazia():
return 0
vizinho = self.buscarVizinho(i)
novaCarta = self.maos[vizinho].pegarCarta()
self.maos[i].adicionarCarta(novaCarta)
print "Mao", self.maos[i].nome, "pegou", novaCarta
conta = self.maos[i].descartarCasais()
self.maos[i].embaralhar()
return conta

140 Captulo 18. Capitulo 16: Herana


Aprenda Computao com Python Documentation, Verso 1.1

Se a mo de um jogador estiver vazia, ele est fora do jogo, ento, ele no faz nada e retorna 0.
Do contrrio, uma jogada consiste em achar o primeiro jogador esquerda que tenha cartas, pegar uma carta dele, e
tentar fazer pares. Antes de retornar, as cartas na mo so embaralhadas, para que a escolha do prximo jogador seja
aleatria.
O mtodo buscarVizinho comea com o jogador imediatamente esquerda e continua ao redor da mesa at
encontrar um jogador que ainda tenha cartas:
class Mico(JogoDeCartas):
#...
def buscarVizinho(self, i):
numMaos = len(self.maos)
for next in range(1,numMaos):
vizinho = (i + next) % numMaos
if not self.maos[vizinho].estahVazia():
return vizinho

Se buscarVizinho alguma vez circulasse pela mesa sem encontrar cartas, retornaria None e causaria um erro em
outra parte do programa. Felizmente, podemos provar que isso nunca vai acontecer (desde que o fim do jogo seja
detectado corretamente).
No mencionamos o mtodo exibirBaralhos. Esse voc mesmo pode escrever.
A sada a seguir produto de uma forma reduzida do jogo, onde apenas as 15 cartas mais altas do baralho (do 10 para
cima) foram dadas, para trs jogadores. Com esse baralho reduzido, a jogada pra depois que 7 combinaes foram
feitas, ao invs de 25:
>>> import cartas
>>> jogo = cartas.Mico()
>>> jogo.jogar(["Alice","Jair","Clara"])
---------- As cartas foram dadas
Mo Alice contm
Rei de copas
Valete de paus
Rainha de espadas
Rei de espadas
10 de ouros

Mo Jair contm
Rainha de copas
Valete de espadas
Valete de copas
Rei de ouros
Rainha de ouros

Mo Clara contm
Valete of ouros
Rei de paus
10 de espadas
10 de copas
10 de paus

Mo Jair: Dama de copas faz par com Dama de ouros


Mo Clara: 10 de espadas faz par com 10 de paus
---------- Os pares foram descartados, o jogo comea
Mo Alice contm
Rei de copas
Valete de paus
Rainha de espadas

18.7. 16.7 Classe Mico 141


Aprenda Computao com Python Documentation, Verso 1.1

Rei de espadas
10 de ouros

Mo Jair contm
Valete de espadas
Valete de copas
Rei de ouros

Mo Clara contm
Valete de ouros
Rei de paus
10 de copas

Mo Alice pegou o Rei de ouros


Mo Alice: Rei de copas faz par com Rei de ouros
Mo Jair pegou 10 de copas
Mo Clara pegou Valete de paus
Mo Alice pegou Valete de copas
Mo Jair pegou Valete de ouros
Mo Clara pegou Dama de espadas
Mo Alice pegou Valete de ouros
Mo Alice: Valete de copas faz par com Valete de ouros
Mo Jair pegou Rei de paus
Mo Clara pegou Rei de espadas
Mo Alice pegou 10 de copas
Mo Alice: 10 de ouros faz par com 10 de copas
Mo Jair pegou Dama de espadas
Mo Clara pegou Valete de espadas
Mo Clara: Valete de paus faz par com Valete de espadas
Mo Jair pegou Rei de espadas
Mo Jeff: Rei de paus faz par com Rei de espadas
---------- Fim do jogo
Mo Alice est vazia

Mo Jair contm
Rainha de espadas

Mo Clara est vazia

Ento, o Jair perdeu.

18.8 16.8 Glossrio

herana (inheritance) Habilidade de definir uma nova classe que a verso modificada de uma classe definida ante-
riormente.
classe me (parent class) A classe de quem a classe filha herda.
classe filho (child class) Um nova classe criada herdando de uma classe existente; tambm chamada de subclasse.

142 Captulo 18. Capitulo 16: Herana


CAPTULO 19

Captulo 17: Listas encadeadas

Tpicos
Captulo 17: Listas encadeadas
17.1 Referncias Embutidas
17.2 A classe No (Node)
17.3 Listas como Colees
17.4 Listas e Recorrncia
17.5 Listas Infinitas
17.6 O Teorema da Ambigidade Fundamental
17.7 Modificando Listas
17.8 Envoltrios e Ajudadores
17.9 A Classe ListaLigada
17.10 Invariantes
17.11 Glossrio

19.1 17.1 Referncias Embutidas

Ns temos visto exemplos de atributos que referenciam outros objetos, que so chamados referncias embutidas
(veja a Seo 12.8). Uma estrutura de dados comum, a lista ligada, tira vantagem desta caracterstica.
Listas ligadas so constitudas de ns (nodos), onde cada n contm uma referncia para o prximo n na lista. Alm
disto, cada n contm uma unidade de dados chamada a carga.
Uma lista ligada considerada uma estrutura de dados recorrente porque ela tem uma definio recorrente.
Uma lista ligada :
Uma lista vazia, representada por None, ou
Um n que contm um objeto carga e uma referncia para uma lista ligada.
Estruturas de dados recorrentes so adequadas para mtodos recorrentes.

143
Aprenda Computao com Python Documentation, Verso 1.1

19.2 17.2 A classe No (Node)

Como usual quando se escreve uma nova classe, ns comearemos com os mtodos de inicializao e __str__ de
modo que podemos testar o mecanismo bsico de se criar e mostrar o novo tipo:
class No:
def __init__(self, carga=None, proximo=None):
self.carga = carga
self.proximo = proximo

def __str__(self):
return str(self.carga)

Como de costume, os parmetros para o mtodo de inicializao so opcionais. Por omisso (default), ambos, a carga
e a ligao, proximo, so definidas como None.
A representao string de um n simplesmente a representao string da carga. Como qualquer valor pode ser
passado para a funo str, ns podemos armazenar qualquer valor em uma lista.
Para testar a implementao at agora, ns criamos um No e o imprimimos:
>>> no = No("teste")
>>> print no
teste

Para ficar interessante, ns precisamos uma lista com mais do que um n:


>>> no1 = No(1)
>>> no2 = No(2)
>>> no3 = No(3)

Este cdigo cria trs ns, mas ns ainda no temos uma lista ainda porque os ns no esto ligados. O diagrama de
estado parecido com este:

Para ligar os ns, temos que fazer o primeiro n da lista referir ao segundo e o segundo n referir ao terceiro:
>>> no1.proximo = no2
>>> no2.proximo = no3

A referncia do terceiro n None, que indica que ele o final da lista. Agora o diagrama de estado se parece com:

144 Captulo 19. Captulo 17: Listas encadeadas


Aprenda Computao com Python Documentation, Verso 1.1

Agora voc sabe como criar ns e lig-los em uma lista. O que pode estar menos claro neste ponto por qu.

19.3 17.3 Listas como Colees

Listas so teis porque elas provm um modo de montar mltiplos objetos em uma nica entidade, algumas vezes
chamada uma coleo. No exemplo, o primeiro n da lista serve como uma referncia para toda a lista.
Para passar uma lista como um parmetro, voc apenas tem que passar uma referncia ao primeiro n. Por exemplo, a
funo imprimeLista toma um nico n como um argumento. Iniciando com o cabea da lista, ela imprime cada
n at que chegue ao fim:
def imprimeLista(no):
while no:
print no,
no = no.proximo
print

Para chamar este mtodo, ns passamos uma referncia ao primeiro no:


>>> imprimeLista(no1)
1 2 3

Dentro de imprimeLista ns temos uma referncia para o primeiro n da lista, mas no h variveis que refiram
aos outros ns. Ns temos que usar o valor proximo de cada n para alcanar o prximo n.
Para percorrer uma lista ligada, comum usar uma varivel lao como no para referir a cada um dos ns sucessiva-
mente.
Este diagrama mostra o valor de lista e os valores que no assume:

Por conveno, listas so freqentemente impressas em braquetes com vrgulas entre os elementos, como em [1, 2, 3].
Como um exerccio, modifique imprimeLista para que ela gere uma sada neste formato.

19.3. 17.3 Listas como Colees 145


Aprenda Computao com Python Documentation, Verso 1.1

19.4 17.4 Listas e Recorrncia

natural expressar muitas operaes de listas utilizando mtodos recorrentes. Por exemplo, o seguinte um algoritmo
recorrente para imprimir uma lista de trs para frente.
1. Separe a lista em dois pedaos: o primeiro n (chamado a cabea); e o resto (chamado o rabo).
2. Imprima o rabo de trs para frente.
3. Imprima a cabea.
Logicamente, o Passo 2, a chamada recorrente, assume que ns temos um modo de imprimir a lista de trs para frente.
Mas se ns assumimos que a chamada recorrente funciona o passo de f ento podemos nos convencer de que o
algoritmo funciona.
Tudo o que precisamos so um caso base e um modo de provar que para qualquer lista, ns iremos, ao final, chegar no
caso base. Dada a definio recorrente de uma lista, um caso base natural a lista vazia, representada por None:
def imprimeDeTrasParaFrente(lista):
if lista == None : return
cabeca = lista
rabo = lista.proximo
imprimeDeTrasParaFrente(rabo)
print cabeca,

A primeira linha trata o caso base fazendo nada. As prximas duas linhas dividem a lista em cabeca e rabo. As
duas ltimas linhas imprimem a lista. A vrgula no final da ltima linha impede o Python de imprimir uma nova linha
aps cada n.
Ns invocamos este mtodo como invocamos o imprimeLista:
>>> imprimeDeTrasParaFrente(no1)
3 2 1

O resultado a lista de trs para frente.


Voc pode se perguntar por qu imprimeLista e imprimeDeTrasParaFrente so funes e no mtodos da
classe No. A razo que ns queremos usar None para representa a lista vazia e no legal invocar um mtodo sobre
None. Esta limitao torna complicado escrever cdigo de manipulao de lista em estilo orientado a objeto limpo.
Podemos provar que imprimeDeTrasParaFrente sempre termina? Em outras palavras, ir ela sempre atingir o
caso base? De fato, a resposta no. Algumas listas faro este mtodo falhar.

19.5 17.5 Listas Infinitas

No h nada que impea um n de referenciar de volta um n anterior na lista, incluindo ele mesmo. Por exemplo,
esta figura mostra uma lista com dois ns, um dos quais refere-se a si mesmo:

146 Captulo 19. Captulo 17: Listas encadeadas


Aprenda Computao com Python Documentation, Verso 1.1

Se ns invocarmos imprimeLista nesta lista, ele ficar em lao para sempre. Se ns invocarmos
imprimeDeTrasParaFrente, ele recorrer infinitamente. Este tipo de comportamento torna as listas infinitas
difceis de se lidar.
A despeito disto, elas ocasionalmente so teis. Por exemplo, podemos representar um nmero como uma lista de
dgitos e usar uma lista infinita para representar uma frao repetente.
Mesmo assim, problemtico que no possamos provar que imprimeLista e imprimeDeTrasParaFrente
terminem. O melhor que podemos fazer a afirmao hipottica, Se a lista no contm laos, ento este mtodo
terminar. Este tipo de hiptese chamado uma pr-condio. Ele impe uma limitao sobre um dos parmetros e
descreve o comportamento do mtodo se a limitao satisfeita. Voc ver mais exemplos em breve.

19.6 17.6 O Teorema da Ambigidade Fundamental

Uma parte de imprimeDeTrasParaFrente pode ter gerado surpresa:


cabeca = lista
rabo = lista.proximo

Aps a primeira atribuio, cabeca e lista tm o mesmo tipo e o mesmo valor. Ento por que ns criamos uma
nova varivel?
A razo que as duas variveis tm diferentes papis. Quando pensamos em cabeca, pensamos como uma referncia
a um nico n, e quando pensamos em lista o fazemos como uma referncia ao primeiro n da lista. Estes papis
no so parte do programa; eles esto na mente do programador.
Em geral no podemos dizer olhando para o programa qual o papel que uma varivel tem. Esta ambigidade pode ser
til, mas tambm pode tornar os programas difceis de serem lidos. Usamos freqentemente nomes de variveis como
no e lista para documentar como pretendemos usar uma varivel e algumas vezes criamos variveis adicionais para
remover a ambigidade.
Poderamos ter escrito imprimeDeTrasParaFrente sem cabeca e rabo, que a tornaria mais concisa mas
possivelmente menos clara:
def imprimeDeTrasParaFrente(lista):
if lista == None : return
imprimeDeTrasParaFrente(lista.proximo)
print lista,

Olhando para as duas chamadas de funo, temos que lembrar que imprimeDeTrasParaFrente trata seu argu-
mento como uma coleo e print trata seu argumento como um objeto nico.
O teorema da ambigidade fundamental descreve a ambigidade que inerente referncia a um n:

19.6. 17.6 O Teorema da Ambigidade Fundamental 147


Aprenda Computao com Python Documentation, Verso 1.1

Uma varivel que refere a um n pode tratar o n como um objeto nico ou como o primeiro em
uma lista de ns.

19.7 17.7 Modificando Listas

Existem duas maneiras de se modificar uma lista ligada. Obviamente, podemos modificar a carga dos ns, mas as
operaes mais interessantes so aquelas que adicionam, removem ou reordenam os ns.
Como um exemplo, vamos escrever um mtodo que remove o segundo n na lista e retorna uma referncia ao n
removido:
def removeSegundo(lista):
if lista == None : return
primeiro = lista
segundo = lista.proximo
# faz o primeiro no referir ao terceiro
primeiro.proximo = segundo.proximo
# separa o segundo no do resto da lista
segundo.proximo = None
return segundo

Novamente, estamos usando variveis temporrias para tornar o cdigo mais fcil de ser lido. Aqui est como usar
este mtodo:
>>> imprimeLista(no1)
1 2 3
>>> removido = removeSegundo(no1)
>>> imprimeLista(removido)
2
>>> imprimeLista(no1)
1 3

Este diagrama de estado mostra o efeito da operao:

O que acontece se voc invocar este mtodo e passar uma lista com somente um elemento (um singleton)? O que
acontece se voc passar a lista vazia como um argumento? Existe uma pr-condio para este mtodo? Se houver,
corrija o mtodo para tratar uma violao da pr-condio de modo razovel.

19.8 17.8 Envoltrios e Ajudadores

Freqentemente til dividir uma operao de lista em dois mtodos. Por exemplo, para imprimir uma lista de trs
para frente no formato convencional de lista [3, 2, 1], podemos usar o mtodo imprimeDeTrasParaFrente para

148 Captulo 19. Captulo 17: Listas encadeadas


Aprenda Computao com Python Documentation, Verso 1.1

imprimir 3, 2, mas queremos um metodo separado para imprimir os braquetes e o primeiro n. Vamos cham-lo de
imprimeDeTrasParaFrenteLegal:
def imprimeDeTrasParaFrenteLegal(lista):
print "[",
if lista != None :
cabeca = lista
rabo = lista.proximo
imprimeDeTrasParaFrente(rabo)
print cabeca,
print "]",

Novamente, uma boa idia verificar mtodos como este para ver se eles funcionam com casos especiais como uma
lista vazia ou um singleton.
Quando usamos este mtodo em algum lugar no programa, invocamos imprimeDeTrasParaFrenteLegal
diretamente, e ele invoca imprimeDeTrasParaFrente por ns. Neste sentido,
imprimeDeTrasParaFrenteLegal atua como um envoltrio, e usa imprimeDeTrasParaFrente
como um ajudador.

19.9 17.9 A Classe ListaLigada

Existem alguns problemas sutis com o modo que implementamos listas. Em um inverso de causa e efeito, proporemos
uma implementao alternativa primeiro e ento explicaremos qual problema ela resolve.
Primeiro, criaremos uma nova classe chamada ListaLigada. Seus atributos so um inteiro que contm o compri-
mento da lista e uma referncia para o primeiro n. Objetos do tipo ListaLigada servem como cabos (handles)
para se manipular listas de objetos No:
class ListaLigada:
def __init__(self):
self.comprimento = 0
self.cabeca = None

Uma coisa legal acerca da classe ListaLigada que ela prov um lugar natural para se colocar funes envoltrias
como imprimeDeTrasParaFrenteLegal, que podemos transformar em um mtodo da classe ListaLigada:
class ListaLigada:
...
def imprimeDeTrasParaFrente(self):
print "[",
if self.cabeca != None :
self.cabeca.imprimeDeTrasParaFrente()
print "]",

class No:
...
def imprimeDeTrasParaFrente(self):
if self.proximo != None:
rabo = self.proximo
rabo.imprimeDeTrasParaFrente()
print self.carga,

Apenas para tornar as coisas confusas, mudamos o nome de imprimeDeTrasParaFrenteLegal.


Agora existem dois mtodos chamados imprimeDeTrasParaFrente: um na classe No (o aju-
dador); e um na classe ListaLigada(o envoltrio). Quano o envoltrio invoca

19.9. 17.9 A Classe ListaLigada 149


Aprenda Computao com Python Documentation, Verso 1.1

self.cabeca.imprimeDeTrasParaFrente, ele est invocando o ajudador, porque self.cabeca


um objeto No.
Outro benefcio da classe ListaLigada que ela torna mais fcil adicionar e remover o primeiro elemento de uma
lista. Por exemplo, adicionaPrimeiro um mtodo para ListaLigada; ele toma um item de carga como
argumento e o coloca no incio da lista:
class ListaLigada:
...
def adicionaPrimeiro(self, carga):
no = No(carga)
no.proximo = self.cabeca
self.cabeca = no
self.comprimento = self.comprimento + 1

Como de costume, voc deve conferir cdigos como este para ver se eles tratam os casos especiais. Por exemplo, o
que acontece se a lista est inicialmente vazia?

19.10 17.10 Invariantes

Algumas listas so bem formadas; outras no o so. Por exemplo, se uma lista contm um lao, ela far muitos de
nossos mtodos falharem, de modo que podemos querer requerer que listas no contenham laos. Outro requerimento
que o valor de comprimento no objeto ListaLigada seja igual ao nmero real de ns da lista.
Requerimentos como estes so chamados de invariantes porque, idealmente, eles deveriam ser verdade para cada
objeto o tempo todo. Especificar invariantes para objetos um prtica de programao til porque torna mais fcil
provar a correo do cdigo, verificar a integridade das estruturas de dados e detectar erros.
Uma coisa que algumas vezes confusa acerca de invariantes que existem momentos em que eles so violados.
Por exemplo, no meio de adicionaPrimeiro, aps termos adicionado o n mas antes de termos incrementado
comprimento, o invariante violado. Este tipo de violao aceitvel; de fato, freqentemente impossvel
modificar um objeto sem violar um invariante por, no mnimo, um pequeno instante. Normalmente, requeremos que
cada mtodo que viola um invariante deve restaurar este invariante.
Se h qualquer aumento significativo de cdigo no qual o invariante violado, importante tornar isto claro nos
comentrios, de modo que nenhuma operao seja feita que dependa daquele invariante.

19.11 17.11 Glossrio

referncia embutida (embedded reference) Uma referncia armazenada/associada em/a um atributo de um objeto.
lista ligada (linked list) Uma estrutura de dados que implementa uma coleo usando uma sequncia de ns ligados.
n ou nodo (node) Um elemento de uma lista, usualmente implementado como um objeto que contm uma referncia
para outro objeto do mesmo tipo.
carga (cargo) Um item de dado contido em um n.
ligao (link) Uma referncia embutida usada para ligar/conectar um objeto a outro.
pr-condio (precondition) Uma assero que precisa/deve ser verdadeira para que um mtodo trabalhe correta-
mante.
teorema da ambigidade fundamental (fundamental ambiguity theorem) Uma referncia para um n de uma lista
pode ser tratada como um objeto nico ou como o primeiro em uma lista de ns.
singleton (singleton) Uma lista ligada com somente um n.

150 Captulo 19. Captulo 17: Listas encadeadas


Aprenda Computao com Python Documentation, Verso 1.1

envoltrio (wrapper) Um mtodo que atua como um intermedirio (middleman) entre um chamador e um mtodo
ajudador (helper), freqentemente tornando a invocao do mtodo mais fcil ou menos propensa a erros.
ajudador (helper) Um mtodo que no invocado diretamente pelo chamador (caller) mas usado por outro mtodo
para realizar parte de uma operao.
invariante (invariant) Uma assero que deveria ser verdadeira sempre para um objeto (exceto talvez enquanto o
objeto estiver sendo modificado).

19.11. 17.11 Glossrio 151


Aprenda Computao com Python Documentation, Verso 1.1

152 Captulo 19. Captulo 17: Listas encadeadas


CAPTULO 20

Captulo 18: Pilhas

Tpicos
Captulo 18: Pilhas
18.1 Tipos abstratos de dados
18.2 O TAD Pilha
18.3 Implementando pilhas com listas de Python
18.4 Empilhando e desempilhando
18.5 Usando uma pilha para avaliar expresses ps-fixas
18.6 Anlise sinttica
18.7 Avaliando em ps-fixo.
* 18.9 Glossrio

20.1 18.1 Tipos abstratos de dados

Os tipos de dados que voc viu at agora so todos concretos, no sentido que ns especificamos completamente como
eles so implementados. Por exemplo, a classe Card(XXX ver como foi traduzido) representa uma carta utilizando
dois inteiros. Como discutimos no momento, esta no a nica maneira de representar uma carta; existem muitas
implementaes alternativas.
Um tipo abstrato de dado, ou TAD, especifica um conjunto de operaes (ou mtodos) e a semntica das operaes
(o que elas fazem), mas no especifica a implementao das operaes. Isto o que o faz abstrato.
Por que isto til?
Simplifica a tarefa dde especificar um algoritmo se voc pode XXXdenotar(denote) as operaes que voc
precisa sem ter que pensar, ao mesmo tempo, como as operaes so executadas.
Uma vez que existem geralmente muitas maneiras de implementar um TAD, pode ser til escrever um algritmo
que pode ser usado com qualquer das possveis implementaes.
TADs bastante conhecidos, como o TAD Pilha deste captulo, j esto implementados em bibliotecas padro,
ento eles podem ser escritos uma vez e usado por muitos programadores.
As operaes em TADs provm uma linguagem de alto nvel comum para especificar e falar sobre algoritmos.
Quando falamos sobre TADs, geralmente distinguimos o cdigo que usa o TAD, chamado cliente, do cdigo que
implementa o TAD, chamado cdigo fornecedor.

153
Aprenda Computao com Python Documentation, Verso 1.1

20.2 18.2 O TAD Pilha

Neste captulo, iremos olhar um TAD comum, a pilha. Uma pilha uma coleo, ou seja, uma estrutura de dados
que contei mltiplos elementos. Outras colees que vimos incluem dicionrios e listas.
Um TAd definido pelo conjunto de operaes que podem ser executadas nele, que chamado interface. A interface
para uma pilha consiste nestas operaes:
__init__ : Inicializa uma nova pilha vazia.
push : Adiciona um novo item na pilha
pop : Remove um tem da pilha e o retorna, O tem que retornadao sempre o ltimo adicionado.
isEmpty : Verifica se a pilha est vazia.
Uma s vezes chamada uma estrutura de dados last in, first out ou LIFO, porque o ltimo tem adicionad o
primeiro a ser removido.

20.3 18.3 Implementando pilhas com listas de Python

As operaes de lista que Python oferecem so similares s operaes que definem uma pilha. A interface no
exatamente o que se supe ser, mas podemos escrever um cdigo para traduzir do TAD Pilha para as operaes
nativas.
Este cdigo chamado uma implementao do TAD Pilha. Geralmente, uma implementaa um conjunto de
mtodos que satisfazem os requisitos sintticos e semnticos de uma interface.
Aqui est uma implementao do TAD Pilha que usa uma lista do Python:
class Stack :
def __init__(self) :
self.items = []

def push(self, item) :


self.items.apend(item)

def pop(self) :
return self.items.pop()

def isEmpty(self) :
return (self.items == [])

Um objeto Stack contm um atributo chamado items que uma lista de tens na pilha. O mtodo de inicializao
define items como uma lista vazia.
Para adicionar um novo tem na pilha, push o coloca em items. Para remover um tem da pilha, pop usa o mtodo
de lista homnimo para remover e retornar um ltimo tem da lista.
Finalmente, para verificar se a pilha est vazia, isEmpty comprara items a uma lista vazia.
Uma implementao como esta, na qual os mtodos consistem de simples invocaes de mtodos existentes,
chamado revestimento. Na vida real, revestimento uma fina camada de madeira de boa qualidade usado em
XXX*furniture-making* para esconder madeira de menor qualidade embaixo. Cientistas da Computao usam esta
metfora para descrever um pequeno trecho de cdigo que esconde os detalhes de uma implementao e fornece uma
interface mais simples, ou mais padronizada.

154 Captulo 20. Captulo 18: Pilhas


Aprenda Computao com Python Documentation, Verso 1.1

20.4 18.4 Empilhando e desempilhando

Uma pilha uma estrutura de dados genrica, o que significa que podemos adicionar qualquer tipo de tem a ela. O
exemplo a seguir empilha dois inteiros e uma XXXstring na pilha:
>>> s = Stack()
>>> s.push(54)
>>> s.push(45)
>>> s.push("+")

Podemos usar isEmpty e pop para remover e imprimir todos os tens da pilha:
while not s.isEmpty() : priint s.pop()
A sada + 45 54. Em outras palavras, usamos a pilha para imprimir os tens ao contrrio! Sabidamente, este no o
formato padro de imprimir uma lista, mas, usando uma pilha, foi notavelmente fcil de fazer.
Voc deve comparar este trecho de cdigo com a implementao de printBackward na seo 17.4. Existe um paralelo
natura entre a verso recursiva de printBackward e o algoritmo de pilha aqui. A diferen que printBackward usa a
pilha de execuo para XXXmanter a trilha(keep track) dos ns enquanto percorre a lista, e ento imprime-a no retorno
da recurso. o algoritmo de pilha faz a mesma coisa, exceto que usa o objeto Stack ao invs da pilha de execuo.

20.5 18.5 Usando uma pilha para avaliar expresses ps-fixas

Em muitas linguagens de programao, expresses matemticas so executadas com o poerador entre os roid operan-
dos, como em 1 + 2. Este formato chamado notao infixa. Uma alternativa usada por algumas calculadoras
chamada notao ps-fixa. Em notao ps-fixa, o operador segue os operandos, como em 1 2 +.
A razo pela qual a notao ps-fixa til algumas vezes que existe uma maneira natural de avaliar uma expresso
ps-fixa usando uma pilha:
comeando no incio da expresso, peque um termo (operador ou operando) de cada vez.
Se o termo um operando, empilhe-o
Se o termo um operador, desempilhe dois operandos, execute a operao neles, e empilhe o resul-
tado.
Quando chegar ao fim da expresso, deve existir exatamente um operando sobrando na pilha. Este
operando o resultado.
Como um exerccio, aplique este algoritmo expresso 1 2 + 3 * .
Este exemplo demonstra uma das vantagens da notao ps-fixa - no necessrio usar parnteses para controlar a
ordem das operaes. Para ter o mesmo resultado em notao infixa, deveramos escrever (1 + 2) * 3.
Como um exerccio, escreva a expresso ps-fixa que equivalente a 1 + 2 * 3.

20.6 18.6 Anlise sinttica

Para implementar o algoritmo anterior, necessitamos estar prontos para percorrer uma string e quebr-la em operandos
e operadores. Este process um exemplo de XXXparsing, e o resultado - os pedaos da string - so chamados
XXXtokens. Voc deve lembrar estas palavras do captulo 1.
Python fornece um mtodo split nos mdulos string e re (expresses regulares). A funo string.split separa
uma string numa lista usando um nico caracter como delimitador. Por exemplo:

20.4. 18.4 Empilhando e desempilhando 155


Aprenda Computao com Python Documentation, Verso 1.1

>>> import string


>>> string.split ("Now is the time", " ")
[Now, is, the, time]

Neste caso, o delimitador o caracter de espao, ento a string dividida a cada espao.
A funo re.split mais poderosa, permitindo-nos fornecer uma expreso regular ao invs de um delimitador.
Uma expresso regular uma maneira de especificar um conjunto de strings. Por exemplo, [A-z] o conjunto de todas
as letras e [0-9] o conjunto de todos os dgitos. O operador ^nega um conunto, ento [^0-9] o conjunto de tudo o
que no nmero, que exatamente o que queremos para dividir expresses ps-fixas.
>>> import re
>>> re.split ("[^0-9]", "123+456*/")
[123, +, 456, *, , /, ]

Note que a ordem dos argumentos diferente de string.split, o delimitador vem antes da string.
A lista resultante inclui os operandos 123 e 456, e os operadores * e /. Tambm inclui duas strings vazias que so
inseridas depois dos operadores.

20.7 18.7 Avaliando em ps-fixo.

Para avaliar uma expresso ps-fixa, usaremos o parser da seo anterior e o algoritmo da seo anterior a ela. Para
manter as coisas simples, comearemos com um avaliador que implementa somente os operadores + e .
def evalPostfix (expr) :
import re
tokenList = re.split ("([^0-9])", expr)
stack = Stack()
for token in tokenList
if token == or token = :
continue
if token == + :
sum = stack.pop() + stack.pop()
stack.push(sum)
if token == * :
product = stack.pop() * stack.pop()
stack.push(product)
else:
stack.push(int(token))
return stack.pop()

A primeira condio cuida de espaos e strings vazias. As duas prximas condies manipulam os operadores. Ns
assumimos, agora que qualquer coisa um operador. claro, seria melhor chegar por entrada errnea e enviar uma
mensagem de erro, mas faremos isto depois.
Vamos test-lo avaliando a forma ps-fixa de (56 + 47) * 2
>>> print evalPostfix("56 47 + 2 *")
206

XXXthats close enough


18.8 Clientes de fornecedores.
Um dos objetivos de um TAD separar os interesses do fornecedor, quem escreve o cdigo que implementa o TAD, e
o cliente, que usa o TAD. O fornecedor tem que se preocupar apenas se a implementao est correta - de acordo com
a especificao do TAD - e no como ele ser usado.

156 Captulo 20. Captulo 18: Pilhas


Aprenda Computao com Python Documentation, Verso 1.1

Inversamente, o cliente assume que a implementao do TAD est correta e no se preocupa com os detalhes. Quando
voc est usando um tipo nativo do Python, tem o luxo de pensar exclusivamente como um cliente.
claro, quanto voc implementa um TAD, voc tambm tem que escrever cdigo cliente para test-lo. Neste caso,
voc faz os dois papis, o que pode ser confuso. Voc deve fazer algum esfor para manter a trilha do papel que est
fazendo a cada momento.

20.7.1 18.9 Glossrio

tipo abstrato de dados (TAD) (abstract data type(ADT)): Um tipo de dado(geralmente uma coleo de objetos) que
definidopor um conjunto de operaes, que podem ser implementadas de vrias maneiras.
interface (interface): o conjunto de operaes que definem um TDA.
implementao (implementation): Cdigo que satisfaz(preenche?) os requisitos sintticos e semnticos de uma in-
terface.
cliente (client): Um programa (ou o programador que o escreveu) que faz utilizao de um TDA.
fornecedor (provider): Cdigo (ou o programador que o escreveu) que implementa um TDA.
revestimento (veneer): Definio de classe que implementa um TDA com definies de mtodos que so chamadas
a outros mtodos, s vezes com pequenas modificaes. A lmina faz um trabalho insignificante, mas melhora
ou padroniza a interface dada ao cliente.
estrutura de dados genrica (generic data structure): Tipo de estrutura de dados que contem data de um tipo qual-
quer(tipo genrico).
infixa (infix): Notao matemtica em que os operadores se situam entre os operandos.
ps-fixa (postfix): Notao matemtica em que os operadores se situam aps os operandos.
XXX parse (parse): Ler um conjunto de caracteres(string de caracteres) ou tokens(smbolos atmicos) e analisar sua
estrutura gramatical.
XXX token (token): Conjunto de caracteres que so tratados como uma unidade atmica para fins de anlise gramat-
ical, como as palavras na linguagem natural.
delimitador (delimiter): Um caracter que utilizado para separar os smbolos atmicos(tokens), como a pontuao
na linguagem natural.

20.7. 18.7 Avaliando em ps-fixo. 157


Aprenda Computao com Python Documentation, Verso 1.1

158 Captulo 20. Captulo 18: Pilhas


CAPTULO 21

Captulo 19: Filas

Este captulo apresenta dois TDAs: Fila e Fila por Prioridade. Na nossa vida diria, fila um alinhamento de con-
sumidores aguardando algum tipo de servio. Na maioria dos casos, o primeiro da fila o primeiro a ser atendido.
Mas h excees. No aeroporto, passageiros cujo vo vai decolar logo, s vezes so chamados primeiro ao balco do
check-in, mesmo que estejam no meio da fila. No supermercado, comum na fila do caixa algum deixar passar na
frente uma pessoa que chega fila s com um ou dois produtos na mo.
A regra que determina quem o prximo da fila chama-se poltica de enfileiramento. A poltica de enfileiramento
mais simples chama-se FIFO, sigla de first-in-first-out: primeiro a entrar, primeiro a sair. A poltica de enfileiramento
mais geral o enfileiramento por prioridade, em que se atribui uma prioridade a cada pessoa da fila e a que tiver maior
prioridade vai primeiro, independente da sua ordem de chegada. Dizemos que essa a poltica mais geral de todas,
porque a prioridade pode ser baseada em qualquer coisa: hora de partida do vo; quantos produtos a pessoa vai passar
pelo caixa; o grau de prestgio da pessoa. claro que nem todas as polticas de enfileiramento so justas, mas o que
justo depende do ponto de vista.
O TDA Fila e o TDA Fila por Prioridade tm o mesmo conjunto de operaes. A diferena est na semntica das oper-
aes: a fila usa a poltica FIFO; e a fila por prioridade (como o prprio nome sugere) usa a poltica de enfileiramento
por prioridade.

21.1 19.1 Um TDA Fila

O TDA Fila definido pelas seguintes operaes:


__init__ Inicializar uma nova fila vazia.
insert Adicionar um novo item fila.
remove Remover e retornar um item da fila. O item retornado o que foi adicionado primeiro.
isEmpty Checar se a fila est vazia.

21.2 19.2 Fila encadeada

A primeira implementao que vamos ver de um TDA Fila chama-se fila encadeada porque feita de objetos Ns
encadeados. A definio da classe a seguinte:

159
Aprenda Computao com Python Documentation, Verso 1.1

class Queue:
def __init__(self):
self.length = 0
self.head = None

def isEmpty(self):
return (self.length == 0)

def insert(self, cargo):


node = Node(cargo)
node.next = None
if self.head == None:
# if list is empty the new node goes first
self.head = node
else:
# find the last node in the list
last = self.head
while last.next: last = last.next
# append the new node
last.next = node
self.length = self.length + 1

def remove(self):
cargo = self.head.cargo
self.head = self.head.next
self.length = self.length - 1
return cargo

Os mtodos isEmpty e remove so idnticos aos mtodos isEmpty e removeFirst de LinkedList. O


mtodo insert novo e um pouco mais complicado.
Queremos inserir novos itens no fim da lista. Se a fila estiver vazia, basta fazer head apontar ao novo n. Se no,
percorremos a lista at o ltimo n e l penduramos o novo n. possvel identificar o ltimo n porque o seu atributo
next None.
Existem duas invariantes para um objeto Fila bem formado: o atributo length deve ser o nmero de ns na fila, e o
ltimo n deve ter seu atributo next igual a None. Estude o mtodo at ficar convencido de que ele preserva ambas
invariantes.

21.3 19.3 Caractersticas de performance

Quando invocamos um mtodo, normalmente no estamos preocupados com os detalhes da sua implementao.
Porm, h um certo detalhe que pode ser bom conhecer: as caractersticas de performance do mtodo. Quanto
tempo leva, e como o tempo de execuo muda medida em que aumenta o nmero de itens da coleo?
Primeiro, olhe para remove. No h laos ou chamadas de funo aqui, o que sugere que o tempo de execuo desse
mtodo sempre o mesmo, toda vez. Um mtodo assim chamado de operao de tempo constante. Na verdade,
o mtodo pode ser ligeiramente mais rpido quando a lista est vazia, uma vez que ele pula o corpo da condicional,
mas essa diferena no significativa. XXX: o condicional s aparece na re-implementao do mtodo na classe
ImprovedQueue, p.200; essa inconsistncia pode ser conferida tambm nas pginas 198-199 do livro original (PDF e
impresso).
A performance de insert muito diferente. No caso geral, temos de percorrer a lista para achar o ltimo elemento.
Este percurso leva um tempo proporcional extenso da lista. Uma vez que o tempo de execuo uma funo linear
da extenso, dizemos que este mtodo opera em tempo linear. Isso bem ruim, se comparado com o tempo constante.

160 Captulo 21. Captulo 19: Filas


Aprenda Computao com Python Documentation, Verso 1.1

21.4 19.4 Fila encadeada aprimorada

Queremos uma implementao do TDA Fila que possa realizar todas as operaes em tempo constante. Uma maneira
de fazer isso modificar a classe Fila, de modo que ela mantenha a referncia tanto ao primeiro quanto ao ltimo n,
como mostra a figura:

A implementao de ImprovedQueue tem essa cara:


class ImprovedQueue:
def __init__(self):
self.length = 0
self.head = None
self.last = None

def isEmpty(self):
return (self.length == 0)

At agora, a nica mudana o atributo last. Ele usado nos mtodos insert e remove:
class ImprovedQueue:
# ...
def insert(self, cargo):
node = Node(cargo)
node.next = None
if self.length == 0:
# if list is empty, the new node is head and last
self.head = self.last = node
else:
# find the last node
last = self.last
# append the new node
last.next = node
self.last = node
self.length = self.length + 1

Uma vez que last no perde de vista o ultimo n, no necessrio busc-lo. Como resultado, esse mtodo tem
tempo constante.
Mas essa rapidez tem preo. preciso adicionar um caso especial a remove, para configurar last para None
quando o ultimo n removido:
class ImprovedQueue:
#...
def remove(self):
cargo = self.head.cargo
self.head = self.head.next
self.length = self.length - 1
if self.length == 0:

21.4. 19.4 Fila encadeada aprimorada 161


Aprenda Computao com Python Documentation, Verso 1.1

self.last = None
return cargo

Essa implementao mais complicada que a primeira, e mais difcil de se demonstrar que est correta. A vantagem
que o objetivo foi atingido tanto insert quanto remove so operaes de tempo constante.
Como exerccio, escreva uma implementao do TDA Fila usando uma lista nativa do Python. Compare
a performance dessa implementao com a de ImprovedQueue, para filas de diversos comprimentos.

21.5 19.5 Fila por prioridade

O TDA Fila por Prioridade tem a mesma interface que o TDA Fila, mas semntica diferente. Mais uma vez, a interface
a seguinte:
__init__ Inicializar uma nova fila vazia.
insert Adicionar um novo item fila.
remove Remover e retornar um item da fila. O item retornado aquele que tiver maior prioridade.
isEmpty Checar se a fila est vazia.
A diferena semntica que o item removido da fila no necessariamente o que foi includo primeiro e, sim, o que
tem maior prioridade. Que prioridades so essas e como elas se comparam umas com as outras no especificado pela
implementao Fila por Prioridade. Isso depende de quais itens esto na fila.
Por exemplo, se os itens da fila tiverem nome, podemos escolh-los por ordem alfabtica. Se for a pontuao de
um jogo de boliche, podemos ir da maior para a menor, mas se for pontuao de golfe, teramos que ir da menor
para a maior. Se possvel comparar os itens da fila, possvel achar e remover o que tem maior prioridade. Essa
implementao da Fila por Prioridade tem como atributo uma lista Python chamada items, que contm os itens da
fila.
class PriorityQueue:
def __init__(self):
self.items = []

def isEmpty(self):
return self.items == []

def insert(self, item):


self.items.append(item)

O mtodo de inicializao, isEmpty, e insert so apenas uma fachada para operaes bsicas de lista. O nico
mtodo interessante remove:
class PriorityQueue:
# ...
def remove(self):
maxi = 0
for i in range(1,len(self.items)):
if self.items[i] > self.items[maxi]:
maxi = i
item = self.items[maxi]
self.items[maxi:maxi+1] = []
return item

No incio de cada iterao, maxi armazena o ndice do maior item (a prioridade mais alta de todas) que vimos at
agora. A cada volta do lao, o programa compara o i-simo item ao campeo. Se o novo item for maior, maxi recebe
o valor de i.

162 Captulo 21. Captulo 19: Filas


Aprenda Computao com Python Documentation, Verso 1.1

Quando o comando for se completa, maxi o ndice do maior item. Esse item removido da lista e retornado.
Vamos testar a implementao:
>>> q = PriorityQueue()
>>> q.insert(11)
>>> q.insert(12)
>>> q.insert(14)
>>> q.insert(13)
>>> while not q.isEmpty(): print q.remove()
14
13
12
11

Se a fila contm nmeros ou strings simples, eles so removidas em ordem numrica decrescente ou alfabtica invertida
(de Z at A). Pyhton consegue achar o maior inteiro ou string porque consegue compar-los usando os operadores de
comparao nativos.
Se a fila contm objetos de outro tipo, os objetos tm que prover um mtodo __cmp__. Quando remove usa o
operador > para comparar dois itens, o mtodo __cmp__ de um dos itens invocado, recebendo o segundo item
como argumento. Desde que o mtodo __cmp__ funcione de forma consistente, a Fila por Prioridade vai funcionar.

21.6 19.6 A classe Golfer

Como exemplo de um objeto com uma definio no-usual de prioridade, vamos implementar uma classe chamada
Golfer (golfista), que mantm registro dos nomes e da pontuao de golfistas. Como sempre, comeamos definindo
__init__ e __str__:
class Golfer:
def __init__(self, name, score):
self.name = name
self.score= score

def __str__(self):
return "%-16s: %d" % (self.name, self.score)

O mtodo __str__ usa o operador de formato para colocar nomes e pontuaes em colunas arrumadas.
Em seguida, definimos uma verso de __cmp__, ma qual a pontuao mais baixa fica com prioridade mxima. Como
sempre, __cmp__ retorna 1 se self maior que other, -1 se self menor que other, e 0 se eles so iguais.
class Golfer:
#...
def __cmp__(self, other):
if self.score < other.score: return 1 # less is more
if self.score > other.score: return -1
return 0

Agora estamos prontos para testar a fila por prioridade com a classe Golfer:
>>> tiger = Golfer("Tiger Woods", 61)
>>> phil = Golfer("Phil Mickelson", 72)
>>> hal = Golfer("Hal Sutton", 69)
>>>
>>> pq = PriorityQueue()
>>> pq.insert(tiger)
>>> pq.insert(phil)

21.6. 19.6 A classe Golfer 163


Aprenda Computao com Python Documentation, Verso 1.1

>>> pq.insert(hal)
>>> while not pq.isEmpty(): print pq.remove()
Tiger Woods : 61
Hal Sutton : 69
Phil Mickelson : 72

Como exerccio, escreva uma implementao do TDA Fila por Prioridade usando uma lista encadeada.
Mantenha a lista em ordem para que a remoo seja uma operao de tempo constante. Compare a
performance dessa implementao com a implementao usando uma lista nativa do Python.

21.7 19.7 Glossrio

fila (queue) Conjunto de objetos ordenados esperando algum tipo de servio.


Fila (Queue) TAD (Tipo Abstrato de Dado) que realiza operaes comuns de acontecerem em uma fila.
poltica de enfileiramento (queueing policy) As regras que determinam qual membro de uma fila o prximo a ser
removido.
FIFO First In, First Out, (primeiro a entrar, primeiro a sair) poltica de enfileiramento em que o primeiro membro
a chegar o primeiro a ser removido.
fila por prioridade (priority queue) Poltica de enfileiramento em que cada membro tem uma prioridade, determi-
nada por fatores externos. O membro com a maior prioridade o primeiro a ser removido.
Fila por Prioridade (Priority Queue) TAD que define as operaes comuns de acontecerem em uma fila por priori-
dade.
fila encadeada (linked queue) Implementao de uma fila usando uma lista encadeada.
tempo constante (constant time) Operao cujo tempo de execuo no depende do tamanho da estrutura de dados.
tempo linear (linear time) Operao cujo tempo de execuo uma funo linear do tamanho da estrutura de dados.

164 Captulo 21. Captulo 19: Filas


CAPTULO 22

Captulo 20: rvores

Tpicos
Captulo 20: rvores
20.1 Construindo rvores
20.2 Percorrendo rvores
20.3 rvores de expresses
20.4 Percurso de rvores
20.5 Construindo uma rvore de expresso
20.6 Manipulando erros
20.7 A rvore dos animais
20.8 Glossrio

Nota: Veja a discusso sobre o vocabulrio usado no fim da pgina.

Como listas ligadas, rvores so constitudas de clulas. Uma espcie comum de rvores a rvore binria, em
que cada clula contm referncias a duas outras clulas (possivelmente nulas). Tais referncias so chamadas de
subrvore esquerda e direita. Como as clulas de listas ligadas, as clulas de rvores tambm contm uma carga. Um
diagrama de estados para uma rvore pode aparecer assim:

165
Aprenda Computao com Python Documentation, Verso 1.1

Figura 1

Para evitar a sobrecarga da figura, ns frequentemente omitimos os Nones.


O topo da rvore (a clula qual o apontador tree se refere) chamada de raiz. Seguindo a metfora das rvores, as
outras clulas so chamadas de galhos e as clulas nas pontas contendo as referncias vazia so chamadas de folhas.
Pode parecer estranho que desenhamos a figura com a raiz em cima e as folhas em baixo, mas isto nem ser a coisa
mais estranha.
Para piorar as coisas, cientistas da computao misturam outra metfora alm da metfora biolgica - a rvore ge-
nealgica. Uma clula superior pode ser chamada de pai e as clulas a que ela se refere so chamadas de seus filhos.
Clulas com o mesmo pai so chamadas de irmos.
Finalmente, existe tambm o vocabulrio geomtrico para falar de rvores. J mencionamos esquerda e direita, mas
existem tambm as direes para cima (na direo da raiz) e para baixo (na direo dos filhos/folhas). Ainda nesta
terminologia, todas as clulas situadas mesma distncia da raiz constituem um nvel da rvore.
Provavelmente no precisamos de trs metforas para falar de rvores, mas a elas esto.
Como listas ligadas, rvores so estruturas de dados recursivas j que elas so definidas recursivamente:
Uma rvore
a rvore vazia, representada por None, ou
uma clula que contm uma referncia a um objeto (a carga da clula) e duas referncias a rvores.

22.1 20.1 Construindo rvores

O processo de montar uma rvore similar ao processo de montar uma lista ligada. cada invocao do construtor cria
uma clula.

166 Captulo 22. Captulo 20: rvores


Aprenda Computao com Python Documentation, Verso 1.1

class Tree :
def __init__(self, cargo, left=None, right=None) :
self.cargo = cargo
self.left = left
self.right = right

def __str__(self) :
return str(self.cargo)

A carga pode ser de qualquer tipo, mas os parmetros left e right devem ser clulas. left e right so
opcionais; o valor default None.
Para imprimir uma clula, imprimimos apenas a sua carga.
Uma forma de construir uma rvore de baixo para cima. Aloque os filhos primeiro:
left = Tree(2)
right = Tree(3)

Em seguida crie a clula pai e ligue ela a seus filhos:


tree = Tree(1, left, right);

Podemos escrever este cdigo mais concisamente encaixando as invocaes do construtor:


>>> tree = Tree(1, Tree(2), Tree(3))

De qualquer forma, o resultado a rvore que apareceu no incio do captulo.

22.2 20.2 Percorrendo rvores

Cada vez que Voc v uma nova estrutura de dados, sua primeira pergunta deveria ser Como eu percorro esta estru-
tura? A forma mais natural de percorrer uma rvore fazer o percurso recursivamente. Por exemplo, se a rvore
contm inteiros na carga, a funo abaixo retorna a soma das cargas:
def total(tree) :
if tree == None : return 0
return total(tree.left) + total(tree.right) + tree.cargo

O caso base a rvore vazia, que no contm nenhuma carga, logo a soma das cargas 0. O passo recursivo faz
duas chamadas recursivas para achar a soma das cargas das subrvores dos filhos. Ao finalizar a chamada recursiva,
adicionamos a carga do pai e devolvemos o valor total.

22.3 20.3 rvores de expresses

Uma rvore uma forma natural para representar a estrutura de uma expresso. Ao contrrio de outras notaes,
a rvore pode representar a computao de forma no ambgua. Por exemplo, a expresso infixa 1 + 2 * 3
ambgua, a menos que saibamos que a multiplicao feita antes da adio.
A rvore de expresso seguinte representa a mesma computao:

22.2. 20.2 Percorrendo rvores 167


Aprenda Computao com Python Documentation, Verso 1.1

Figura 2

As clulas de uma rvore de expresso podem ser operandos como 1 e 2 ou operaes como + e *. As clulas
contendo operandos so folhas; aquelas contendo operaes devem ter referncias aos seus operandos. (Todos os
nossos operandos so binrios, significando que eles tem exatamente dois operandos.)
Podemos construir rvores assim:
>>> tree = Tree(+, Tree(1), Tree(*, Tree(2), Tree(3)))

Examinando a figura, no h dvida quanto ordem das operaes; a multiplicao feita primeiro para calcular o
segundo operando da adio.
rvores de expresso tem muitos usos. O exemplo neste captulo usa rvores para traduzir expresses para as notaes
psfixa, prefixa e infixa. rvores similares so usadas em compiladores para analisar sintaticamente, otimizar e
traduzir programas.

22.4 20.4 Percurso de rvores

Podemos percorrer uma rvore de expresso e imprimir o seu contedo como segue:
def printTree(tree) :
if tree == None : return
print tree.cargo,
printTree(tree.left)
printTree(tree.right)

168 Captulo 22. Captulo 20: rvores


Aprenda Computao com Python Documentation, Verso 1.1

Em outras palavras, para imprimir uma rvore, imprima primeiro o contedo da raiz, em seguida imprima toda a
subrvore esquerda e finalmente imprima toda a subrvore direita. Esta forma de percorrer uma rvore chamada de
prordem, porque o contedo da raiz aparece antes dos contedos dos filhos. Para o exemplo anterior, a sada :
>>> tree = Tree(+, Tree(1), Tree(*, Tree(2), Tree(3)))
>>> printTree(tree)
+ 1 * 2 3

Esta notao diferente tanto da notao psfixa quanto da infixa; uma notao chamada de prefixa, em que os
operadores aparecem antes dos seus operandos.
Voc pode suspeitar que se Voc percorre a rvore numa ordem diferente, Voc produzir expresses numa notao
diferente. Por exemplo, se Voc imprime subrvores primeiro e depois a raiz, Voc ter:
def printTreePostorder(tree) :
if tree == None : return
printTreePostorder(tree.left)
printTreePostorder(tree.right)
print tree.cargo,

O resultado, 1 2 3 * +, est na notao psfixa! Esta ordem de percurso chamada de psordem.


Finalmente, para percorrer uma rvore em inordem, Voc imprime a subrvore esquerda, depois a raiz e depois a
subrvore direita:
def printTreeInorder(tree) :
if tree == None : return
printTreeInorder(tree.left)
print tree.cargo,
printTreeInorder(tree.right)

O resultado 1 + 2 * 3, que a expresso na notao infixa.


Para sermos justos, devemos lembrar que acabamos de omitir uma complicao importante. algumas vezes quando
escrevemos expresses na notao infixa devemos usar parntesis para prescrever a ordem das operaes. Ou seja, um
percurso em inordem no suficiente para gerar a expresso infixa.
Ainda assim, com alguns aperfeioamentos, a rvore de expresso e os trs modos recursivos de percurso resultam em
algoritmos para transformar expresses de uma notao para outra.
Como um exerccio, modifique printTreeInorder de modo que ele coloque parntesis em volta de cada
operador e par de operandos. A sada correta e no ambgua? Os parntesis so sempre necessrios?
Se percorrermos uma rvore em inordem e acompanharmos em qual nvel na rvore estamos, podemos gerar uma
representao grfica da rvore:
def printTreeIndented(tree, level=0) :
if tree == None : return
printTreeIndented(tree.right, level+1)
print *level + str(tree.cargo)
printTreeIndented(tree.left, level+1)

O parmetro level registra aonde estamos na rvore. Por default, o nvel inicialmente zero. A cada chamada
recursiva repassamos level+1 porque o nvel do filho sempre um a mais do que o nvel do pai. Cada item
indentado dois espaos por nvel. Para o nosso exemplo obtemos:
>>> printTreeIndented(tree)
3
*
2

22.4. 20.4 Percurso de rvores 169


Aprenda Computao com Python Documentation, Verso 1.1

+
1

Se Voc deitar a sada acima Voc enxerga uma verso simplificada da figura original.

22.5 20.5 Construindo uma rvore de expresso

Nesta seo analisamos expresses infixas e construmos as rvores de express correspondentes. Por exemplo, para a
expresso (3+7)*9 resultar a seguinte rvore:

Figura 3

Note que simplificamos o diagrama omitindo os nomes dos campos.


O analisador que escreveremos aceitar expresses que incluam nmeros, parntesis e as operaes + e *. Vamos
supor que a cadeia de entrada j foi tokenizada numa lista do Python. A lista de tokens para a expresso (3+7)*9 :
[(, 3, +, 7, ), *, 9, end]
O token final end prtico para prevenir que o analisador tente buscar mais dados aps o trmino da lista.
A ttulo de um exerccio, escreva uma funo que recebe uma expresso na forma de uma cadeia e devolve
a lista de tokens.
A primeira funo que escreveremos getToken que recebe como parmetros uma lista de tokens e um token
esperado. Ela compara o token esperado com o o primeiro token da lista: se eles batem a funo remove o token da
lista e devolve um valor verdadeiro, caso contrrio a funo devolve um valor falso:
def getToken(tokenList, expected) :
if tokenList[0] == expected :
tokenList[0:1] = [] # remove the token
return 1
else :
return 0

170 Captulo 22. Captulo 20: rvores


Aprenda Computao com Python Documentation, Verso 1.1

J que tokenList refere a um objeto mutvel, as alteraes feitas aqui so visveis para qualquer outra varivel que
se refira ao mesmo objeto.
A prxima funo, getNumber, trata de operandos. Se o primeiro token na tokenList for um nmero ento
getNumber o remove da lista e devolve uma clula folha contendo o nmero; caso contrrio ele devolve None.
def getNumber(tokenList) :
x = tokenList[0]
if type(x) != type(0) : return None
del tokenList[0]
return Tree(x, None, None)

Antes de continuar, convm testar getNumber isoladamente. Atribumos uma lista de nmeros a tokenList,
extramos o primeiro, imprimimos o resultado e imprimimos o que resta na lista de tokens:
>>> tokenList = [9, 11, end]
>>> x = getNumber(tokenList)
>>> printTreePostorder(x)
9
>>> print tokenList
[11, end]

Em seguida precisaremos da funo getProduct, que constri uma rvore de expresso para produtos. Os dois
operandos de um produto simples so nmeros, como em 3 * 7.
Segue uma verso de getProduct que trata de produtos simples.
def getProduct(tokenList) :
a = getNumber(tokenList)
if getToken(tokenList, *) :
b = getNumber(tokenList)
return Tree(*, a, b)
else :
return a

Supondo que a chamada de getNumber seja bem sucedida e devolva uma rvore de uma s clula atribumos o
primeiro operando a . Se o prximo caractere for *, vamos buscar o segundo nmero e construir a rvore com a, b
e o operador.
Se o caractere seguinte for qualquer outra coisa, ento simplesmente devolvemos uma clula folha com a. Seguem
dois exemplos:
>>> tokenList = [9, *, 11, end]
>>> tree = getProduct(tokenList)
>>> printTreePostorder(tree)
9 11 *

>>> tokenList = [9, +, 11, end]


>>> tree = getProduct(tokenList)
>>> printTreePostorder(tree)
9

O segundo exemplo sugere que ns consideramos um operando unitrio como uma espcie de produto. Esta definio
de produto talvez no seja intuitiva, mas ela ser til.
Agora tratamos produtos compostos, como 3 * 5 * 13. Encaramos esta expresso como um produto de produtos,
mais precisamente como 3 * (5 * 13). A rvore resultante :

22.5. 20.5 Construindo uma rvore de expresso 171


Aprenda Computao com Python Documentation, Verso 1.1

Figura 4

Com uma pequena alterao em getProduct, podemos acomodar produtos arbitrariamente longos:
def getProduct(tokenList) :
a = getNumber(tokenList)
if getToken(tokenList, *) :
b = getProduct(tokenList) # this line changed
return Tree(*, a, b)
else :
return a

Em outras palavras, um produto pode ser um singleton ou uma rvore com * na raiz, que tem um nmero como filho
esquerdo e um produto como filho direito. Este tipo de definio recursiva devia comear a ficar familiar.
Testemos a nova verso com um produto composto:
>>> tokenList = [2, *, 3, *, 5 , *, 7, end]
>>> tree = getProduct(tokenList)
>>> printTreePostorder(tree)
2 3 5 7 * * *

A seguir adicionamos o tratamento de somas. De novo, usamos uma definio de soma que ligeiramente no
intuitiva. Para ns, uma soma pode ser uma rvore com + na raiz, que tem um produto como filho esquerdo e uma
soma como filho direito. Ou, uma soma pode ser simplesmente um produto.
Se Voc est disposto a brincar com esta definio, ela tem uma propriedade interessante: podemos representar qual-
quer expresso (sem parntesis) como uma soma de produtos. Esta propriedade a base do nosso algoritmo de anlise
sinttica.
getSum tenta construir a rvore com um produto esquerda e uma soma direita. Mas, se ele no encontra uma +,
ele simplesmente constri um produto.
def getSum(tokenList) :
a = getProduct(tokenList)
if getToken(tokenList, +) :
b = getSum(tokenList)
return Tree(+, a, b)

172 Captulo 22. Captulo 20: rvores


Aprenda Computao com Python Documentation, Verso 1.1

else :
return a

Vamos testar o algoritmo com 9 * 11 + 5 * 7:


>>> tokenList = [9, *, 11, +, 5, *, 7, end]
>>> tree = getSum(tokenList)
>>> printTreePostorder(tree)
9 11 * 5 7 * +

Quase terminamos, mas ainda temos que tratar dos parntesis. Em qualquer lugar numa expresso onde podemos
ter um nmero, podemos tambm ter uma soma inteira envolvida entre parntesis. Precisamos, apenas, modificar
getNumber para que ela possa tratar de subexpresses:
def getNumber(tokenList) :
if getToken(tokenList, () :
x = getSum(tokenList) # get subexpression
getToken(tokenList, )) # eat the closing parenthesis
return x
else :
x = tokenList[0]
if type(x) != type(0) : return None
tokenList[0:1] = [] # remove the token
return Tree(x, None, None) # return a leaf with the number

Testemos este cdigo com 9 * (11 + 5) * 7:


>>> tokenList = [9, *, (, 11, +, 5, ), *, 7, end]
>>> tree = getSum(tokenList)
>>> printTreePostorder(tree)
9 11 5 + 7 * *

O analisador tratou os parntesis corretamente; a adio feita antes da multiplicao.


Na verso final do programa, seria uma boa idia dar a getNumber um nome mais descritivo do seu novo papel.

22.6 20.6 Manipulando erros

Ao longo do analisador sinttico tnhamos suposto que as expresses (de entrada) so bem formadas. Por exemplo,
quando atingimos o fim de uma subexpresso, supomos que o prximo caractere um facha parntesis. Caso haja um
erro e o prximo caractere seja algo diferente, devemos tratar disto.
def getNumber(tokenList) :
if getToken(tokenList, () :
x = getSum(tokenList)
if not getToken(tokenList, )):
raise BadExpressionError, missing parenthesis
return x
else :
# the rest of the function omitted

O comando raise cria uma exceo; neste caso criamos um novo tipo de exceo, chamada de
BadExpressionError. Se a funo que chamou getNumber, ou uma das outras funes no traceback, ma-
nipular a exceo, ento o programa pode continuar. caso contrrio Python vai imprimir uma mensagem de erro e
terminar o processamento em seguida.
A ttulo de exerccio, encontre outros locais nas funes criadas onde erros possam ocorrer e adiciona
comandos raise apropriados. Teste seu cdigo com expresses mal formadas.

22.6. 20.6 Manipulando erros 173


Aprenda Computao com Python Documentation, Verso 1.1

22.7 20.7 A rvore dos animais

Nesta seo, desenvolvemos um pequeno programa que usa uma rvore para representar uma base de conhecimento.
O programa interage com o usurio para criar uma rvore de perguntas e de nomes de animais. Segue uma amostra da
funcionalidade:
Are you thinking of an animal? y
Is it a bird? n
What is the animals name? dog
What question would distinguish a dog from a bird? Can it fly
If the animal were dog the answer would be? n

Are you thinking of an animal? y


Can it fly? n
Is it a dog? n
What is the animals name? cat
What question would distinguish a cat from a dog? Does it bark
If the animal were cat the answer would be? n

Are you thinking of an animal? y


Can it fly? n
Does it bark? y
Is it a dog? y
I rule!

Are you thinking of an animal? n

Aqui est a rvore que este dilogo constri:

Figura 5

No comeo de cada rodada, o programa parte do topo da rvore e faz a primeira pergunta. Dependendo da resposta,
ele segue pelo filho esquerdo ou direito e continua at chegar numa folha. Neste ponto ele arrisca um palpite. Se o
palpite no for correto, ele pergunta ao usurio o nome de um novo animal e uma pergunta que distingue o palpite
errado do novo animal. A seguir, adiciona uma clula rvore contendo a nova pergunta e o novo animal.

174 Captulo 22. Captulo 20: rvores


Aprenda Computao com Python Documentation, Verso 1.1

Aqui est o cdigo:


def animal() :
# start with a singleton
root = Tree("bird")

# loop until the user quits


while 1 :
print
if not yes("Are you thinking of an animal? ") : break

# walk the tree


tree = root
while tree.getLeft() != None :
prompt = tree.getCargo() + "? "
if yes(prompt):
tree = tree.getRight()
else:
tree = tree.getLeft()

# make a guess
guess = tree.getCargo()
prompt = "Is it a " + guess + "? "
if yes(prompt) :
print "I rule!"
continue

# get new information


prompt = "What is the animal\s name? "
animal = raw_input(prompt)
prompt = "What question would distinguish a %s from a %s? "
question = raw_input(prompt % (animal,guess))

# add new information to the tree


tree.setCargo(question)
prompt = "If the animal were %s the answer would be? "
if yes(prompt % animal) :
tree.setLeft(Tree(guess))
tree.setRight(Tree(animal))
else :
tree.setLeft(Tree(animal))
tree.setRight(Tree(guess))

A funo yes um auxiliar; ele imprime um prompt e em seguida solicita do usurio uma entrada. Se a resposta
comear com y ou Y, a funo devolve um valor verdadeiro:
def yes(ques) :
from string import lower
ans = lower(raw_input(ques))
return (ans[0:1] == y)

A condio do lao externo 1, que significa que ele continuar at a execuo de um comando break, caso o
usurio no pense num animal.
O lao while interno caminha na rvore de cima para baixo, guiado pelas respostas do usurio.
Quando uma nova clula adicionada rvore, a nova pergunta substitui a carga e os dois filhos so o novo animal e
a carga original.
Uma falha do programa que ao sair ele esquece tudo que lhe foi cuidadosamente ensinado!

22.7. 20.7 A rvore dos animais 175


Aprenda Computao com Python Documentation, Verso 1.1

A ttulo de exerccio, pense de vrias jeitos para salvar a rvore do conhecimento acumulado num ar-
quivo. Implemente aquele que Voc pensa ser o mais fcil.

22.8 20.8 Glossrio

rvore binria (binary tree) Uma rvore em que cada clula tem zero, um ou dois descendentes.
raiz (root) A clula mais alta de uma rvore, a (nica) clula de uma rvore que no tem pai.
folha (leaf ) Uma clula mais baixa numa rvore; uma clula que no tem descendentes.
pai (parent) A clula que aponta para uma clula dada.
filho (child) Uma clula apontada por uma clula dada.
irmos (siebling) Clulas que tem o mesmo pai.
nvel (level) Um conjunto de clulas equidistantes da raiz.
operador binrio (binary operator) Um operador sobre dois operandos.
subexpresso (subexpression) Uma expresso entre parntesis que se comporta como um operando simples numa
expresso maior.
pr-ordem (preorder) Uma forma de percorrer uma rvore visitando cada clula antes dos seus filhos.
notao prefixa (prefix notation) Uma forma de escrever uma expresso matemtica em que cada operador aparece
antes dos seus operandos.
ps-ordem (postorder) Uma forma de percorrer uma rvore visitando os filhos de cada clula antes da prpria clula.
in-ordem (inorder) Uma forma de percorrer uma rvore visitando a subrvore esquerda, seguida da raiz e finalmente
da subrvore direita.

176 Captulo 22. Captulo 20: rvores


CAPTULO 23

Apndice A: Depurao

Tpicos
Apndice A: Depurao
A.1 Erros de sintaxe
* A.1.1 Eu no consigo fazer meu programa executar no importa o que eu faa
A.2 Erros de tempo de execuo
* A.2.1 Meu programa no faz absolutamente nada
* A.2.2 Meu programa trava
Lao Infinito
Recurso Infinita
Fluxo de Execuo
* A.2.3 Quando eu executo o programa, recebo uma exceo
* A.2.4 Eu adicionei tantas declaraes print que a sada do programa ficou bagunada
A.3 Erros de semntica
* A.3.1 Meu programa no funciona
* A.3.2 Eu tenho uma grande expresso cabeluda e ela no faz o que eu espero
* A.3.3 Eu tenho uma funo ou mtodo que no retorna o que eu espero
* A.3.4 Eu estou empacado mesmo e eu preciso de ajuda
* A.3.5 No, eu preciso mesmo de ajuda

Diferentes tipos de erros podem acontecer em um programa, e til distinguir entre eles para os localizar mais
rapidamente:
Erros de sintaxe so produzidos por Python quando o interpretador est traduzindo o cdigo fonte em bytecode.
Estes erros geralmente indicam que existe algo errado com a sintaxe do programa. Exemplo: Omitir o sinal de
dois pontos (:) no final de uma declarao def produz a mensagem um tanto redundante SintaxError:
invalid sintax (Erro de sintaxe: sintaxe invlida).
Erros de tempo de execuo so produzidos se algo de errado acontece enquanto o programa est em execuo.
A maioria das mensagens de tempo de execuo incluem informao sobre onde o erro ocorreu e que funo
estava em execuo. Exemplo: Uma recurso infinita eventualmente causa um erro em tempo de execuo iden-
tificado como maximum recursion depth exceeded (Excedida a mxima profundidade de recurso).
Erros de semntica, chamado por alguns autores de erros de lgica, so problemas com um programa que
compila e executa mas no tem o resultado esperado. Exemplo: Uma expresso pode no ser avaliada da forma
que voc espera, produzindo um resultado inesperado.

177
Aprenda Computao com Python Documentation, Verso 1.1

O primeiro passo na depurao descobrir com que tipo de erro voc est lidando. Embora as sees a seguir estejam
organizadas por tipo de erro, algumas tcnicas so aplicveis em mais de uma situao.

23.1 A.1 Erros de sintaxe

Erros de sintaxe so geralmente fceis de corrigir, bastando apenas que voc descubra onde eles esto. Infelizmente,
as mensagens de erro geralmente ajudam pouco. As mensagens mais comuns so: SyntaxError: invalid
syntax (Erro de sintaxe: sintaxe invlida) e SyntaxError: invalid token (Erro de sintaxe: objeto in-
vlido), nenhuma das duas muito informativa.
Por outro lado, a mensagem diz a voc onde, no cdigo do programa, ocorreu o problema. Na verdade, ela diz a
voc onde o Python encontrou o problema, que no necessariamente onde o erro est. s vezes o erro anterior
localizao da mensagem de erro, geralmente na linha precedente.
Se voc est construindo o programa incrementalmente, voc ter uma boa ideia sobre onde estar o erro. Estar na
ltima linha adicionada.
Se voc est copiando cdigo de um livro, comece comparando seu cdigo ao cdigo do livro de forma muito cuida-
dosa. Verifique cada caracter. Ao mesmo tempo, lembre-se que o livro pode estar errado, ento voc pode perfeita-
mente encontrar um erro de sintaxe em um livro.
Aqui esto algumas maneiras de evitar os erros de sintaxe mais comuns:
1. Certifique-se que voc no est utilizando uma palavra reservada de Python para um nome de varivel.
2. Verifique a existncia do sinal de dois pontos no final do cabealho de cada declarao composta, incluindo as
declaraes for, while, if, e def.
3. Verifique se a endentao est consistente. Voc pode endentar com espaos ou com tabulaes, mas melhor
no mistur-los. Cada nvel deve ser aninhado com a mesma quantidade.
4. Assegure-se de que cada string no cdigo tenha as aspas correspondentes.
5. Se voc tem strings de multilinhas criadas usando trs aspas (simples ou duplas), assegure-se de que voc
terminou a string apropriadamente. Uma string terminada de forma inapropriada ou no terminada pode gerar
um erro de invalid token (objeto invlido) no final do seu programa, ou ele pode tratar a parte seguinte
do programa como uma string at chegar prxima string. No segundo caso, pode ser que o interpretador nem
mesmo produza uma mensagem de erro!
6. Um conjunto de parnteses, colchetes ou chaves no fechados corretamente faz com que o Python continue com
a prxima linha como parte da declarao anterior. Geralmente, um erro ocorre quase imediatamente na linha
seguinte.
7. Verique o clssico = ao invs de == dentro de uma condicional.
Se nada funcionar, v para a prxima seo.

23.1.1 A.1.1 Eu no consigo fazer meu programa executar no importa o que eu


faa

Se o compilador diz que existe um erro e voc no o v, isto pode ser por que voc e o compilador no esto olhando
para o mesmo cdigo. Verifique seu ambiente para se assegurar que o programa que voc est editando o mesmo
que o Python est tentando executar. Se voc no est certo, tente colocar um erro de sintaxe bvio e deliberado no
incio do programa. Agora execute (ou importe) o programa novamente. Se o compilador no encontrar o novo erro,
provavelmente existe algo de errado com a maneira como o ambiente est configurado.

178 Captulo 23. Apndice A: Depurao


Aprenda Computao com Python Documentation, Verso 1.1

Se isto acontecer, uma abordagem iniciar novamente com um novo programa como Hello World!, e se assegurar
de que voc consegue colocar um programa conhecido para executar. Ento gradualmente adicione as partes do novo
programa ao programa que est funcionando.

23.2 A.2 Erros de tempo de execuo

Uma vez que seu programa est sintaticamente correto, o interpretador do Python pode import-lo e comear a execut-
lo. O que poderia dar errado?

23.2.1 A.2.1 Meu programa no faz absolutamente nada

Este o problema mais comum quando um arquivo consiste de funes e classes mas no chama nada realmente
para iniciar a execuo. Isto pode ser intencional se voc planeja apenas importar este mdulo para fornecer classes e
funes.
Se isto no intencional, assegure-se de que voc est chamando uma funo para iniciar a execuo ou execute uma
manualmente do prompt interativo. Veja tambm a seo Fluxo de Execuo abaixo.

23.2.2 A.2.2 Meu programa trava

Se um programa para e parece no estar fazendo nada, dizemos que ele travou. Geralmente isto significa que ele foi
pego num lao infinito ou numa recurso infinita.
Se existe um lao em particular aonde voc suspeita estar o problema, adicione uma declarao print ime-
diatamente antes do lao que diga entrando no lao e uma outra imediatamente depois que diga saindo do
lao. Execute o programa. Se voc receber a primeira mensagem e no a segunda, voc tem um lao infinito.
V para a seo Lao Infinito abaixo.
Na maioria das vezes, uma recurso infinita far com que o programa execute por um tempo e ento ele pro-
duzir um erro do tipo Runtime Error: Maximum recursion depth exceeded (Erro de tempo
de execuo: Excedida a profundidade mxima de recurso). Se isto acontecer, v para a seo Recurso
Infinita abaixo. Se voc no est recebendo este erro, mas suspeita que h um problema com um mtodo ou
funo recursiva, voc ainda pode utilizar as tcnicas da seo Recurso Infinita.
Se nenhum destes passos funcionar, comecea testar outros laos ou mtodos ou funes recursivas.
Se isso no funcionar, ento possvel que voc no entenda o fluxo de execuo do seu programa. V para a
seo Fluxo de Execuo abaixo.

Lao Infinito

Se voc acha que tem um lao infinito e desconfia de qual seja lao causador do problema, adicione uma declarao
print no final do lao que imprima os valores das variveis na condio e o valor da condio.
Por exemplo:
>>> while x > 0 and y < 0:
# faz algo para x
# faz algo para y
print "x: ", x
print "y: ", y
print "condio: ", (x > 0 and y < 0)

23.2. A.2 Erros de tempo de execuo 179


Aprenda Computao com Python Documentation, Verso 1.1

Agora, quando voc executar o programa, sero exibidas trs linhas de sada para cada execuo do lao. Na ltima
execuo do lao, a condio deveria ser False (falso). Se o lao continuar, voc ter condies de ver os valores de
x e y, podendo, assim, descobrir o porqu das variveis no serem atualizadas corretamente.

Recurso Infinita

Na maioria das vezes, uma recurso infinita far com que um programa execute por um determinado tempo e ento
produza um erro de Maximum recursion depth exceeded (Excedida a profundidade mxima de recurso).
Se voc suspeita que uma funo ou mtodo est causando uma recurso infinita, comece verificando para se assegurar
que exista um caso bsico. Em outras palavras, deve existir alguma condio que faa com que a funo ou mtodo
finalize sem fazer uma chamada recursiva. Se no existe tal condio, voc precisa repensar o algoritmo e identificar
um caso base.
Se existe um caso base mas o programa parece no estar alcanando-o, adicione uma declarao print no incio
da funo ou mtodo que imprime o(s) parmetro(s). Agora, quando voc executar o programa, voc ver umas
poucas linhas de sada todas as vezes que a funo ou mtodo for executado, e voc ver o(s) parmetro(s). Se o(s)
parmetro(s) no est(o) se movendo em direo ao caso base, voc ter ideias de por que no, e poder ento corrigir
o problema.

Fluxo de Execuo

Se voc no est certo de como o seu programa est fluindo, adicione declaraes print ao incio de cada funo
com uma mensagem semelhante a entrando na funo foo, onde foo o nome da funo.
Agora quando voc executar o programa, ser exibido um rastro de cada funo medida em que ela invocada.

23.2.3 A.2.3 Quando eu executo o programa, recebo uma exceo

Se algo vai errado durante a execuo, o Python exibe uma mensagem que inclui o nome da exceo, a linha do cdigo
do programa onde o problema ocorre, e dados para investigao do erro, onde descrita a pilha de execuo de funes
e mtodos.
Tais dados identificam a funo que est sendo executada no momento, e ento a funo que a invocou, e ento a
funo que invocou aquela, e assim por diante (a pilha de execuo de funes). Em outras palavras, ele traa o
caminho das invocaes da funo que te levou at onde voc est. Ele tambm inclui o nmero da linha no respectivo
arquivo onde cada uma dessas chamadas ocorre.
O primeiro passo examinar o lugar no programa onde ocorreu o erro e tentar descobrir o que aconteceu. Esses so
alguns dos erros de tempo de execuo mais comuns:
NameError (Erro de Nome): Voc est tentando utilizar uma varivel que no existe no ambiente atual. Lembre-se
que variveis locais so locais. Voc no pode referenci-la fora da funo onde ela foi definida.
TypeError (Erro de Tipo): Existem vrias causas possveis:
Voc est tentando utilizar um valor de forma imprpria. Exemplo: indexando uma string, lista ou tupla com
alguma coisa que no um inteiro.
H uma incompatibilidade entre os itens em um formato de string e os itens passados para converso. Isto pode
acontecer se o nmero de itens no for igual ou se uma converso invlida chamada. Por exemplo: Passar uma
string para a formatao de converso %f.
Voc est passando o nmero errado de argumentos para uma funo ou mtodo. Para mtodos, verifique sua
definio e confira se o primeiro parmetro chama-se self. Ento verifique a chamada ao mtodo; certifque-se
de que voc est chamando o mtodo em um objeto com o tipo correto e fornecendo os argumentos adequados.

180 Captulo 23. Apndice A: Depurao


Aprenda Computao com Python Documentation, Verso 1.1

KeyError (Erro de Chave): Voc est tentando acessar um elemento de um dicionrio utilizando um valor de chave
que o dicionrio no contm.
AttributeError (Erro de Atributo): Voc est tentando acessar um atributo ou mtodo que no existe em um objeto.
IndexError (Erro de ndice): O ndice que voc est usando para acessar uma lista, string ou tupla no existe
no objeto, ou seja, maior que seu comprimento menos um. Imediatamente antes do ponto do erro, adicione uma
delarao print para mostrar o valor do ndice e o comprimento do objeto. O objeto do tamanho correto? O ndice
est com o valor adequado?

23.2.4 A.2.4 Eu adicionei tantas declaraes print que a sada do programa ficou
bagunada

Um dos problemas com o uso de declaraes print para a depurao que a sada pode ficar confusa, dificultando a
depurao, ao invs de facilitar. H duas coisas que podem ser feitas: simplificar a sada ou simplificar o programa.
Para simplificar a sada, voc pode remover ou comentar as declaraes print que no esto ajudando, ou combin-las,
ou, ainda, formatar a sada para facilitar o entendimento.
Para simplificar o programa, existem vrias coisas que voc pode fazer: Primeiro, reduza o problema no qual o
programa est trabalhando. Por exemplo, se voc est ordenando um array, ordene um * array* pequeno. Se o
programa recebe entrada do usurio, d a ele a entrada mais simples capaz de causar o problema.
Segundo, limpe o programa. Remova cdigo intil e reorganize o programa para torn-lo to fcil de ler quanto
possvel. Por exemplo, se voc suspeita que o problema est numa parte profundamente aninhada do programa, tente
reescrever aquela parte com uma estrutura mais simples. Se voc suspeita de uma funo longa, tente dividi-la em
funes menores e test-las separadamente.
Muitas vezes o processo de encontrar o caso de teste mnimo leva voc ao erro. Se voc descobrir que o programa
funciona em uma situao, mas no em outra, voc j tem uma boa dica a respeito do que est acontecendo.
De forma semelhante, reescrever pedaos de cdigo pode ajuda a encontrar erros sutis. Se voc faz uma alterao que
voc pensa que no afeta o programa, e ela afeta, voc tambm tem uma dica.

23.3 A.3 Erros de semntica

De certa forma, os erros de semntica so os mais difceis de depurar, porque o compilador e o sistema de tempo
de execuo no fornecem informaes sobre o que est errado. Somente voc sabe o que o programa deve fazer, e
somente voc sabe que ele no est fazendo isto.
O primeiro passo fazer uma conexo entre o texto do programa e o comportamento que voc est vendo. Voc
precisa de uma hiptese sobre o que o programa est realmente fazendo. Uma das coisas que dificultam que os
computadores trabalham muito rpido.
Voc sempre desejar que a velocidade do programa pudesse ser diminuda para a velocidade humana, e com alguns
depuradores voc pode. Mas o tempo que leva para inserir umas poucas declaraes print bem colocadas geral-
mente mais curto quando comparado a configurar um depurador, inserir e remover breakpoints, e caminhar pelo
programa at onde o erro ocorre.

23.3.1 A.3.1 Meu programa no funciona

Voc deveria se fazer as seguintes perguntas:


H alguma coisa que o programa deveria fazer, mas que no parece que estar acontecendo?

23.3. A.3 Erros de semntica 181


Aprenda Computao com Python Documentation, Verso 1.1

No est acontecendo alguma coisa que no deveria acontecer? Encontre o cdigo no seu programa que executa
a funo e veja se ele est executando no momento errado ou de forma errada.
Uma parte do cdigo est produzindo o efeito esperado? Cetifique-se que voc entende o cdigo em questo,
especialmente se ele envolve chamadas de funes ou mtodos em outros mdulos da linguagem. Leia a docu-
mentao das funes e mdulos que voc est utilizando. Teste as funes escrevendo casos simples de teste e
verificando os resultados.
Para programar, voc precisa ter um modelo mental de como seus programas trabalham. Se voc escreve um programa
que no faz aquilo que voc espera, muito comum que o problema no esteja no programa, mas sim no seu modelo
mental.
A melhor maneira de corrigir seu modelo mental quebrar o programa em seus componentes (geralmente as funes
e mtodos) e testar cada componente de forma independente. Uma vez que voc tenha encontrado a diferena entre
seu modelo e a realidade, voc pode resolver o problema.
Obviamente, componentes devem ser desenvolvidos e testado medida que o seu programa vai ganhando vida. Se
voc encontra um problema, haver uma pequena quantidade de novo cdigo com funcionamento incerto.

23.3.2 A.3.2 Eu tenho uma grande expresso cabeluda e ela no faz o que eu es-
pero

Escrever expresses complexas legal se elas forem legveis, mas pode ser difcil de depurar. Geralmente uma boa
ideia quebrar uma expresso complexa em uma srie de atribuies para variveis temporrias.
Por exemplo:
>>> self.mao[i].adicionaCarta(self.mao[self.encontraVizinho(i)].popCarta())

Isto pode ser escrito como:


>>> vizinho = self.encontraVizinho(i)
>>> cartaPega = self.mao[vizinho].popCarta()
>>> self.mao[i].adicionaCarta(cartaPega)

A verso explcita mais fcil de ler, pois os nomes das variveis fornecem documentao adicional, e mais fcil
depurar, j que voc pode verificar os tipos das variveis intermedirias e mostrar seus valores.
Um outro problema que pode ocorrer com expresses longas que a ordem de avaliao pode no ser o que voc
espera. Por exemplo, se voc est traduzido a expresso x / 2pi (XXX fazer a equao matemtica) para Python, voc
poderia escrever:
>>> y = x / 2 * math.pi

Isto est correto por que a multiplicao e a diviso possuem a mesma precedncia e so avalidadas da esquerda pra
direita. Ento a expresso calcula *x*pi/2 (XXX fazer a equao matemtica).
Uma boa maneira de depurar expresses adicionar parnteses para tornar a ordem de avaliao explcita:
>>> y = x / (2 * math.pi)

Sempre que voc no estiver seguro sobe a ordem de avaliao, utilize parnteses. No apenas o programa estar
correto(no sentido de fazer aquilo que voc tinha a inteno), ele tambm ser mais legvel por outras pessoas que no
tenham memorizado as regras de precedncia.

182 Captulo 23. Apndice A: Depurao


Aprenda Computao com Python Documentation, Verso 1.1

23.3.3 A.3.3 Eu tenho uma funo ou mtodo que no retorna o que eu espero

Se voc possui uma declarao return com uma expresso complexa, voc no tem a chance de exibir o valor de return
antes que ele seja devolvido. Novamente, voc pode utilizar uma variavel temporria. Por exemplo, ao invs de:
>>> def pega_encontrados(self):
return self.mao[i].devolveEncontrados()

voc poderia escrever:


>>> def pega_encontrados(self):
qtEncontrados = self.mao[i].devolveEncontrados()
return qtEncontrados

Agora voc tem a oportunidade de mostrar o valor de qtEncontrados antes de devolv-lo.

23.3.4 A.3.4 Eu estou empacado mesmo e eu preciso de ajuda

Primeiro,tente sair da frente do computador por alguns minutos. Computadores emitem ondas que afetam o crebro,
causando estes efeitos:
Frustao e/ou raiva.
Crenas superticiosas (o computador me odeia) e pensamentos mgicos (o prorama s funciona quando eu
coloco meu chapu de trs pra frente).
Programao pelo caminhar aleatrio (a tentativa de programar escrevendo cada programa possvel e escolhendo
aquele que faz a coisa certa).
Se voc estiver sofrendo de qualquer um destes sintomas, levante-se e v dar uma caminhada. Quando voc estiver
calmo, pense no programa. O que ele est fazendo? Quais so as possveis causas do comportamento inadequado?
Quando foi a ltima vez que voc teve um programa funcionando, e o que voc fez depois disto?
s vezes uma questo de tempo para encontrar um erro. Ns geralmente encontramos os erros quando estamos
longe do computador e deixamos nossa mente vaguear. Alguns dos melhores lugares para encontrar erros so trens,
chuveiros e na cama, logo antes de pegar no sono.

23.3.5 A.3.5 No, eu preciso mesmo de ajuda

Isto acontece. Mesmo os melhores programadores empacam de vez em quando. s vezes voc trabalha num programa
por tanto tempo que no consegue ver o erro. Um par fresco de olhos o que se precisa.
Antes de trazer mais algum, certifique-se de que voc tenha esgotado as tcnicas descritas aqui. Seu programa deve
ser to simples quanto possvel, e voc deve estar trabalhando com a mais simples das entradas que causam o erro.
Voc deve ter declaraes print nos lugares apropriados (sem comprometer a compreensividade da sada do programa).
Voc tem que entender o problema o suficiente para descrev-lo concisamente.
Quando voc trouxer algum pra ajudar, assegure-se de dar a este algum a informao que ele precisa:
Se existe uma mensagem de erro, o que ela e que parte do programa ela indica?
Qual foi a ltima coisa que voc fez antes deste erro acontecer? Quais foram as ltimas linhas de cdigo que
voc escreveu, ou qual o novo caso de teste que falha?
O que voc j tentou at o momento, e o que voc aprendeu?
Quando voc encontrar um erro, gaste um segundo para pensar sobre o que voc poderia fazer para encontr-lo mais
rpido. Da prxima vez que voc ver algo similar, voc ter condies de encontrar o erro mais rapidamente.

23.3. A.3 Erros de semntica 183


Aprenda Computao com Python Documentation, Verso 1.1

Lembre-se, o objetivo no apenas fazer o programa funcionar. O objetivo aprender como fazer o programa fun-
cionar.

184 Captulo 23. Apndice A: Depurao


CAPTULO 24

Apndice B: Criando um novo tipo de


dado

Tpicos
Apndice B: Criando um novo tipo de dado
B.1 Multiplicao de fraes
B.2 Soma de fraes
B.3 Simplificando fraes: O algoritmo de Euclides
B.4 Comparando fraes
B.5 Indo mais alm...
* B.5.1 Exerccio
B.6 Glossrio

Em linguagens com suporte orientao a objetos, programadores podem criar novos tipos de dados que se comportam
de forma semelhante aos tipos de dados built-in. Vamos explorar esse recurso criando uma classe chamada Fracao.
Esta classe ter comportamento muito semelhante aos tipos numricos da linguagem: int, long e float.
Fraes, tambm conhecidas como nmeros racionais, so valores que podem ser expressos como uma razo de dois
nmeros inteiros, por exemplo, 5/6. No exemplo fornecido, o 5 representa o numerador, o nmero que fica em cima,
que dividido, e o 6 representa o denominador, o nmero que fica embaixo, pelo qual a diviso feita. A frao 5/6
pode ser lida cinco dividido por seis.
O primeiro passo definir a classe Fracao com o mtodo __init__ que recebe como parmetros o numerador e o
denominador, sendo ambos do tipo int:
class Fracao:
def __init__(self, numerador, denominador=1):
self.numerador = numerador
self.denominador = denominador

A passagem do denominador opcional. Uma Fracao com apenas um parmetro representa um nmero inteiro. Sendo
o numerador n, a frao construda ser n/1.
O prximo passo escrever o mtodo __str__ que exibe as fraes corretamente: a forma numerador/denominador.
class Fracao:
...

185
Aprenda Computao com Python Documentation, Verso 1.1

def __str__(self):
return "%d/%d" %(self.numerador, self.denominador)

Para testar o que foi feito at aqui, salve a classe Fracao em um arquivo chamado Fracao.py e importe-a no
interpretador interativo. Criaremos uma instncia da classe e imprimiremos ele na tela:
>>> from Fracao import Fracao
>>> numero = Fracao(5, 6)
>>> print "A frao ", numero
A frao 5/6

Como de costume, o comando print chama implicitamente o mtodo __str__.

24.1 B.1 Multiplicao de fraes

interessante que nossas fraes possam ser somadas, subtradas, multiplicadas, divididas, etc. Enfim, todas as
operaes matemticas das fraes. Para que isso seja possvel, vamos usar o recurso de sobrecarga de operadores.
Comearemos pela multiplicao por que a operao mais fcil de ser implementada. Para multiplicar duas fraes,
criamos uma nova frao, onde o numerador o produto dos numeradores das fraes multiplicadas e o denominador
o produto dos numeradores das fraes multiplicadas. O mtodo utilizado em Python para sobrecarga do operador
* chama-se __mul__:
class Fracao:
...
def __mul__(self, other):
return Fracao(self.numerador * other.numerador,
self.denominador * ohter.denominador)

Vamos testar este mtodo criando e multiplicando duas fraes:


>>> print Fracao(5, 6) * Fracao(3, 4)
15/24

O mtodo funciona, mas pode ser aprimorado! Podemos melhorar o mtodo visando possibilitar a multiplicao de
uma frao por um inteiro. Usaremos a funo isinstance para verificar se o objeto other um inteiro, para em
seguida convert-lo em uma frao.
class Fracao:
...
def __mul__(self, other):
if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador * other.numerador,
self.denominador * ohter.denominador)

Agora conseguimos multiplicar funes por inteiros, mas s se a frao estiver esquerda do operador *. Vejamos um
exemplo em que nossa multiplicao funciona e outro no qual ela no funciona:
>>> print Fracao(5, 6) * 4
20/6
>>> print 4 * Fracao(5, 6)
TypeError: __mul__ nor __rmul__ defined for these operands

O erro nos da uma dica: no mexemos em nenhum __rmul__.


Para realizar a multiplicao, busca no elemento esquerda do operador * o mtodo __mul__ compatvel com a
multiplicao realizada (no nosso caso, que receba um inteiro e uma frao, nesta ordem). Se o mtodo no for encon-

186 Captulo 24. Apndice B: Criando um novo tipo de dado


Aprenda Computao com Python Documentation, Verso 1.1

trado, o Python buscar no elemento direita do operador * o mtodo __rmul__ compatvel com a multiplicao
realizada (que ento deve ser lida da direita para a esquerda). Como a multiplicao lida da direita para a esquerda,
temos que o nosso mtodo __rmul__ deve ser igual ao mtodo __mul__ implementado anteriormente.:
class Fracao:
...
__rmul__ = __mul__

Fazendo assim, dizemos que o mtodo __rmul__ funciona da mesma forma que o mtodo __mul__. Agora, quando
multiplicarmos 4 * Fracao(5, 6), o interpretador Python chamar o mtodo __rmul__ do objeto Fracao,
passando o 4 como parmetro.
>>> print 4 * Fracao(5, 6)
20/6

Como o mtodo __rmul__ tambm o mtodo __mul__, e o mtodo __mul__ consegue trabalhar com parmetro
do tipo inteiro, nossa multiplicao est completa.

24.2 B.2 Soma de fraes

Somar mais complicado do que multiplicar, pelo menos quando estamos somando fraes e temos que implementar
isso em uma linguagem de programao. Mas no se assuste, no to complicado assim. A soma de a/b com c/d
(a*d+c*b)/(b*d).
Tomando a multiplicao como base, podemos facilmente implementar os mtodos __add__ e __radd__:
class Fracao:
...
def __add__(self, other):
if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador * other.denominador +
self.denominador * other.numerador,
self.denominador * other.denominador)

__radd__ = __add__

Podemos testar o mtodo usando fraes e inteiros:


>>> print Fracao(5, 6) + Fracao(5, 6)
60/36
>>> print Fracao(5, 6) + 3
23/6
>>> print 2 + Fracao(5, 6)
17/6

Os dois primeiros exemplos chamam o mtodo __add__, enquanto o ltimo exemplo chama o mtodo __radd__.

24.3 B.3 Simplificando fraes: O algoritmo de Euclides

No exemplo anterior, calculamos a soma de 5/6 com 5/6 e obtivemos o resultado 60/36. O resultado est correto,
porm no est representado na melhor forma possvel. O ideal simplificarmos a frao. Para simplificar ao mximo
esta frao, devemos dividir o numerador e o denominador pelo mximo divisor comum (MDC) deles, que 12.
Fazendo isso, chegamos forma mais simples da frao, que 5/3.

24.2. B.2 Soma de fraes 187


Aprenda Computao com Python Documentation, Verso 1.1

De forma geral, sempre que um objeto do tipo Fracao for criado, a frao deve ser simplificada, atravs da diviso
do numerador e do denominador pelo seu MDC. Quando a frao j est em sua forma mais simples, o MDC vale 1.
Euclides de Alexandria (aprox. 325 a. C. 365 a. C.) desenvolveu um algoritmo para encontrar o MDC de dois
inteiros m e n:
Se n mltiplo de m, ento n o MDC. Caso contrrio, o MDC o MDC de n e o resto da diviso de m
por n.
Esta definio recursiva pode ser representada de forma concisa pela funo:
def mdc(m, n):
if m % n == 0:
return n
else:
return mdc(n, m % n)

Na primeira linha da funo, utilizamos o operador de mdulo para checar se m divisvel por n. Na ltima linha,
usamos o mesmo operador para obter o resto da diviso de m por n.
J que todas as operaes que escrevemos criam um novo objeto do tipo Fracao, podemos utilizar a funo mdc no
mtodo __init__ de nossa classe:
class Fracao:
def __init__(self, numerador, denominador=1):
m = mdc(numerador, denominador)
self.numerador = numerador / m
self.denominador = denominador / m

Agora, sempre que criarmos uma frao, ela ser reduzida:


>>> Fracao(100, -36)
-25/9

Sempre que o denominador negativo, o sinal negativo deve passar para o numerador. O interessante que, ao usarmos
o Algoritmo de Euclides, esta operao ocorre de forma transparente.
Antes de seguirmos para o prximo passo, vamos ver como est nossa classe Fracao completa?
class Fracao:
def __init__(self, numerador, denominador=1):
m = mdc(numerador, denominador)
self.numerador = numerador / m
self.denominador = denominador / m

def __str__(self):
return "%d/%d" %(self.numerador, self.denominador)

def __mul__(self, other):


if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador * other.numerador,
self.denominador * ohter.denominador)

__rmul__ = __mul__

def __add__(self, other):


if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador * other.denominador +
self.denominador * other.numerador,

188 Captulo 24. Apndice B: Criando um novo tipo de dado


Aprenda Computao com Python Documentation, Verso 1.1

self.denominador * other.denominador)

__radd__ = __add__

24.4 B.4 Comparando fraes

Suponha que tenhamos duas fraes (instncias da classe Fracao), a e b, e ns fazemos a comparao a == b. A
implementao padro do operador == realiza um teste raso, ou seja, verifica se a e b so o mesmo objeto.
Queremos personalizar este retorno, de forma que a comparao retorne True se a e b tiverem o mesmo valor, o que
chamado de teste profundo.
Temos que ensinar s fraes como elas devem se comparar. Como foi visto na seo 15.4, todos os operadores de
comparao podem ser sobrecarregados por apenas um mtodo: __cmp__.
Por conveno, o mtodo __cmp__ retorna um nmero negativo se self for menor que other, zero se eles forem
iguais e um nmero positivo se self for maior que other.
A forma mais simples de comparar fraes atravs da multiplicao cruzada (denominador * numerador e vice-
versa). Se a/b > c/d, ento ad > bc. Tendo isso em mente, vamos criar o __cmp__:
class Fracao:
...
def __cmp__(self, other):
diferenca = (self.numerador * other.denominador -
self.denominador * other.numerador)
return diferenca

Se self for maior que other, a diferenca ser positiva. Se other for maior, a diferenca ser negativa. Se
os dois forem iguais, a diferenca ser zero.

24.5 B.5 Indo mais alm...

Obviamente, no terminamos de representar uma frao. Ainda temos que implementar a subtrao sobrescrevendo o
mtodo __sub__ e a diviso sobrescrevendo o mtodo __div__.
Uma forma de tratar tais operaes sobrescrever os mtodos de negao (__neg__) e de inverso (__invert__).
Assim, podemos fazer a subtrao atravs da negao do elemento direita do operador e somando, e podemos fazer
a diviso atravs da inverso do elemento direita do operador e multiplicando.
Depois, temos que implementar os mtodos __rsub__ e __rdiv__. Infelizmente, no podemos utilizar o mesmo
macete utilizado para multiplicao e soma, por que a diviso e a subtrao no so comutativas, ou seja, a ordem
dos fatores altera o resultado final.
As negaes unrias, que representam o uso do sinal de negao com apenas um elemento, so implementadas atravs
da sobrescrita do mtodo __neg__.
Potncias podem ser calculadas atravs do mtodo __pow__, mas a implementao um pouco complicada. Se o
expoente da potncia no for um inteiro, o resultado provavelmente no poder ser representado como uma frao. Por
exemplo, Fracao(2) ** Fracao(2) a raiz quadrada de 2, que um nmero irracional, e nmeros irracionais
no pode ser representados por fraes. Logo, uma tarefa complicada implementar uma verso genrica do mtodo
__pow__.
Existe, ainda, uma outra extenso para a classe Fracao que pode vir mente. At aqui, assumimos que o numerador
e o denominador so nmeros inteiros.

24.4. B.4 Comparando fraes 189


Aprenda Computao com Python Documentation, Verso 1.1

24.5.1 B.5.1 Exerccio

Como exerccio, finalize a implementao da classe Fracao, tornando-a capaz de tratar subtrao, diviso e potenci-
ao.

24.6 B.6 Glossrio

mximo divisor comum (MDC) O maior inteiro positivo que tem como mltiplo o numerador e o denominador de
uma frao.
negao unria a operao que calcula a inverso de um elemento, usualmente representada com um sinal de
menos - esquerda do elemento. chamada unria pelo contraste com a operao binria que usa o sinal de
menos, a subtrao.
simplificar Transformar uma frao em sua equivalente com o MDC valendo 1

190 Captulo 24. Apndice B: Criando um novo tipo de dado


CAPTULO 25

Apndice C: Leituras recomendadas

Tpicos
Apndice C: Leituras recomendadas
C.1 Recomendaes para leitura
C.2 Sites e livros sobre Python
C.3 Livros de cincia da computao recomendados

25.1 C.1 Recomendaes para leitura

E agora, para onde voc vai? Existem diversas direes que podem ser seguidas, aumentando o seu conhecimento
especificamente em Python e/ou na cincia da computao em geral.
Os exemplos contidos neste livro foram deliberadamente simples, ou seja, eles podem no ter mostrado todo o poten-
cial do Python. Abaixo uma lista de extenses e sugestes para projetos que usem Python:
Programar utilizando interfaces grficas (GUI - graphical user interface) permite ao seu programa usar um
ambiente de janelas para interagir com o usurio e exibir contedos grficos (janelas, imagens, etc.) A biblioteca
grfica mais antiga para Python o Tkinter, que baseado no Tcl criado por Jon Ousterhout e na linguagem
de script Tk. O Tkinter est incluso na distribuio padro do Python, ou seja, quando instalamos o Python, o
mdulo do Tkinter instalado tambm.
Outra biblioteca famosa o wxPython, que essencialmente uma folheagem do Python sobre o wxWindows,
uma biblioteca C++ que, por sua vez, implementa janelas usando a interfaces nativas nas plataformas Windows
e Unix (incluindo Linux). As janelas e controles no wxPython tendem a ter um visual mais nativo do que no
Tkinter e so mais um pouco mais simples de usar.
Em qualquer biblioteca GUI que voc usar, voc usar a programao orientada a eventos, onde o usurio, e no
o programador, determina o fluxo de execuo. Este estilo de programao exige um novo costume que, por
vezes, o obrigar a repensar toda a estrutura de um programa.
A programao web um modelo de programao que integra o Python com a Internet. Por exemplo, voc pode
criar um cliente web que abre e l uma pgina remota (quase) to facilmente como voc pode abrir um arquivo
local. Existem, ainda, mdulos para Python que permitem acesso remoto a arquivos utilizando FTP, e mdulos
que permitem voc enviar e receber e-mails. Python tambm usado (amplamente) para construir programas
em servidores web com o intuito de tratar dados fornecidos por formulrios.

191
Aprenda Computao com Python Documentation, Verso 1.1

Banco de dados so como super arquivos, que armazenam dados em esquemas predefinidos, e mantm relaes
entre itens de dados que lhe permitem acessar os dados de vrias formas. Python tem vrios mdulos que
possibilitam ao usurio conectar seus programas a diversos sistemas gerenciadores de banco de dados, tanto
sistemas livres (Open source) quanto sistemas comerciais.
A programao multitarefa (multithread) permite que voc execute vrias tarefas (threads) dentro de um nico
programa. Se voc j teve a experincia de usar um navegador web para se deslocar por uma pgina web
enquanto o navegador ainda est carregando ela, ento voc j tem uma ideia do que da pra fazer usando a
programao multitarefa.
Quando o desempenho primordial, voc pode escrever extenses para o Python em linguagens compiladas,
como C e C++. Este abordagem vastamente utilizada na biblioteca padro do Python, formando a sua base.
O mecanismo de ligao de dados e funes um pouco complexo. Existe uma ferramenta, chamada SWIG
(Simplified Wrapper and Interface Generator), que faz este processo de ligao ser mais simples.

25.2 C.2 Sites e livros sobre Python

Aqui esto algumas recomendaes do autor de informaes sobre Python na Internet:


A pgina oficial do Python (www.python.org) o ponto de partida para pesquisa sobre qualquer material ligado
a Python. L voc encontrar ajuda, documentao, links para outros sites e listas de discusso nas quais voc
pode participar.
O Open Book Project (www.ibiblio.com/obp) contm no apenas este livro, mas tambm livros similares que
abordam Java e C++, escritos por Allen Downey. Alm disso, h aulas sobre Circuitos Eltricos feitas por
Tony R. Kuphaldt; Get down with ..., um conjunto de tutoriais sobre uma gama de tpicos em cincia da
computao, escrito e editado por alunos de ensino mdio; Python for Fun, um conjunto de estudos de caso
em Python, feito por Chris Meyers; e The Linux Cookbook, escrito por Michael Stultz, com 300 pginas de
dicas e tcnicas.
Por ltimo, se voc for ao Google e buscar por python -snake -monty, voc encontrar cerca de 750 mil
resultados.
E aqui esto alguns livros que contm material sobre Python:
Core Python Programming, escrito por Wesley Chun, um grande livro com cerca de 750 pginas. A primeira
prte do livro apresenta os recursos bsicos do Python. A segunda parte traz uma introduo aos tpicos mais
avanados, incluindo muitos dos mencionados acima.
Python Essential Reference, escrito por David M. Beazley, um livro pequeno, mas que contm informaes
tanto da linguagem em si quanto dos mdulos da biblioteca padro. tambm muito bem indexado.
Python Pocket Reference, escrito por Mark Lutz, este livro realmente cabe no seu bolso. Embora no seja to
abrangente quanto o Python Essential Reference, Python Pocket Reference uma referncia para se ter em
mos o tempo todo, capaz de atender muito bem explicao das funes e mtodos mais comuns. Mark Luiz
tambm autor do livro Programming Python, um dos primeiros (e maiores) livros sobre Python, e no visa
o programador iniciante. Seu ltimo livro, Learning Python, menor e mais acessvel.
Python Programming on Win32, escrito por Mark Hammond e Andy Robinson, um tem que ter para qual-
quer pessoa utilizando Python seriamente para desenvolver aplicaes Windows. Entre outras coisas, o livro
apresenta a integrao entre Python e COM, cria uma pequena aplicao com wxPython, e ainda usar Python
para criar scripts para aplicaes como Word e Excel.

192 Captulo 25. Apndice C: Leituras recomendadas


Aprenda Computao com Python Documentation, Verso 1.1

25.3 C.3 Livros de cincia da computao recomendados

As seguintes sugestes de leitura incluem muitos dos livros favoritos do autor. Eles lidam com as boas prticas de
programao e cincia da computao em geral.
The Practice of Programming, escrito por Kernighan e Pike, abrange no apenas o projeto e a implementao de
algoritmos e estrutura de dados, mas tambm depura, testa e melhora o desempenho de programas. Os exemplos
so principalmente em C++ e Java, nenhum em Python.
The Elements of Java Style, editado por Al Vermeulen, outro livro pequeno que discute alguns dos mais finos
pontos de boas prticas de programao, como o bom uso de convees, comentrios, e ainda espaos em branco
e endentao (o que no um problema em Python). O livro tambm abrange programao por contrato, usando
asseres para capturar erros testando precondies e poscondies, e programao adequada utilizando threads
e sua sincronizao.
Programming Pearls, escrito por Jon Bentley, um livro clssico. O livro consiste de casos de estudo que
originalmente apareceram na coluna do autor no site Communications of ACM (Association for Computing
Machinery). Os estudos lidam com trade-offs em programao e por que isto , muitas vezes, uma pssima
idia, especialmente para usar na sua primeira ideia para um programa. O livro um pouco mais velho que os
outros acima (1986), ento os exemplos esto em linguagens antigas. Existem vrios problemas para resolver,
uns com soluo e outros com dicas. O livro foi muito famoso e foi seguido por um segundo volume.
The New Turing Omnibus, escrito por A.K Dewdney, fornece uma leve introduo a 66 tpicos de cincia
da computao, indo de computao paralela aos vrus de computador, de tomografias computadorizadas a
algoritmos genticos. Todos os tpicos so curtos e agradveis. Um livro anterior escrito por Dewdney, The
Armchair Universe, uma coleo de sua coluna Computer Recreations (Brincadeiras computacionais) na
revista Scientific American. Ambos os livros representam uma rica fonte de ideias para projetos.
Turtles, Termites and Traffic Jams, escrito por Mitchel Resnick, trata do poder de descentralizao e como um
comportamento complexo pode ocorrer a partir de simples atividades coordenadas, com um grande nmero de
agentes. A execuo do programa demonstra o comportamento complexo, que , muitas vezes, contraintuitivo.
Gdel, Escher and Bach, escrito por Douglas Hofstadter. Simplificando, se voc encontrar a magia na recurso,
voc vai encontrar tambm neste best-seller. Um dos temas abordados por Hofstadter envolve loops estranhos
onde os padres evoluem e ascendem at se encontrarem novamente. Esta a controvrsia de Hofstadter, de que
tais loops estranhos representam o elemento essencial que separa o animado do inanimado. Ele demonstra
tais padres na msica de Bach, nos quadros de Escher e na incompletude dos teoremas de Gdel.

25.3. C.3 Livros de cincia da computao recomendados 193


Aprenda Computao com Python Documentation, Verso 1.1

194 Captulo 25. Apndice C: Leituras recomendadas


CAPTULO 26

Apndice D: GNU Free Documentation


License

Coligi aqui os links para tradues da Licensa Pblica GNU fornecidos pelo professor Imre Simon:
http://creativecommons.org/licenses/GPL/2.0/legalcode.pt
http://www.magnux.org/doc/GPL-pt_BR.txt
http://www.ead.unicamp.br/minicurso/bw/texto/fdl.pt.html (esta no consegui abrir...)
Encontrei tambm uma reproduo neste texto em pdf, alis sobre o incentivo do governo ao uso do Software Livre:
http://www.inf.ufpr.br/info/techrep/RT_DINF004_2002.pdf.gz
Parecem haver pequenas discrepncias entre as vrias tradues, mas acho que deveramos escolher uma para publicar
aqui como referncia.

195
Aprenda Computao com Python Documentation, Verso 1.1

196 Captulo 26. Apndice D: GNU Free Documentation License


CAPTULO 27

Indices and tables

genindex
modindex
search

197

Você também pode gostar