Você está na página 1de 209

Aprenda Computao com Python 3.

0
Verso 1
Allen Downey, Jeff Elkner and Chris Meyers
14/09/2009
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
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 Denies e uso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.8 3.8 Fluxo de execuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
5.9 3.9 Parmetros e argumentos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
5.10 3.10 Variveis e parmetros so locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.11 3.11 Diagramas da pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
5.12 3.12 Funes com resultados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
5.13 3.13 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.11 4.11 Recursividade innita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
6.12 4.12 Entrada pelo teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42
6.13 4.13 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
7.6 5.6 Voto de conana (Leap of faith) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51
7.7 5.7 Mais um exemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.6 6.6 Mais encapsulamento . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
8.7 6.7 Variveis locais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
8.8 6.8 Mais generalizao . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69
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 Classicao de caracteres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
9.11 7.11 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
10.5 8.5 Listas e laos for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76
10.6 8.6 Operaes em listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
10.11 8.11 Apelidos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
10.12 8.12 Clonando listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80
10.13 8.13 Lista como parmetro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
10.14 8.14 Lista aninhadas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.15 8.15 Matrizes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
10.16 8.16 Strings e listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
10.17 8.17 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
10.18 Outros termos utilizados neste captulo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
12.5 10.5 Hint XXX . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
12.6 10.6 Inteiros Longos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
12.7 10.7 Contando Letras . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
12.8 10.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106
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 denidos pelo usurio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109
14.2 12.2 Atributos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110
14.3 12.3 Instncias como parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
14.4 12.4 O signicado 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 Modicadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132
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 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
18.8 16.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 143
19 Captulo 17: Listas encadeadas 145
19.1 17.1 Referncias Embutidas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145
19.2 17.2 A classe No (Node) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 146
19.3 17.3 Listas como Colees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147
19.4 17.4 Listas e Recorrncia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
19.5 17.5 Listas Innitas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148
iv
19.6 17.6 O Teorema da Ambigidade Fundamental . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
19.7 17.7 Modicando Listas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 150
19.8 17.8 Envoltrios e Ajudadores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
19.9 17.9 A Classe ListaLigada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 151
19.10 17.10 Invariantes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
19.11 17.11 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 152
20 Captulo 18: Pilhas 155
20.1 18.1 Tipos abstratos de dados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 155
20.2 18.2 O TAD Pilha . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
20.3 18.3 Implementando pilhas com listas de Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . 156
20.4 18.4 Empilhando e desempilhando . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
20.5 18.5 Usando uma pilha para avaliar expresses ps-xas . . . . . . . . . . . . . . . . . . . . . . . . 157
20.6 18.6 Anlise sinttica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
20.7 18.7 Avaliando em ps-xo. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158
21 Captulo 19: Filas 161
21.1 19.1 Um TDA Fila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
21.2 19.2 Fila encadeada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161
21.3 19.3 Caractersticas de performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162
21.4 19.4 Fila encadeada aprimorada . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163
21.5 19.5 Fila por prioridade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164
21.6 19.6 A classe Golfer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
21.7 19.7 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166
22 Captulo 20: rvores 167
22.1 20.1 Construindo rvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 168
22.2 20.2 Percorrendo rvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
22.3 20.3 rvores de expresses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 169
22.4 20.4 Percurso de rvores . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 170
22.5 20.5 Construindo uma rvore de expresso . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172
22.6 20.6 Manipulando erros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175
22.7 20.7 A rvore dos animais . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176
22.8 20.8 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
23 Apndice A: Depurao 181
23.1 A.1 Erros de sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
23.2 A.2 Erros de tempo de execuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183
23.3 A.3 Erros de semntica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185
24 Apndice B: Criando um novo tipo de dado 189
24.1 B.1 Multiplicao de fraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190
24.2 B.2 Soma de fraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191
24.3 B.3 Simplicando fraes: O algoritmo de Euclides . . . . . . . . . . . . . . . . . . . . . . . . . . 192
24.4 B.4 Comparando fraes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
24.5 B.5 Indo mais alm... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
24.6 B.6 Glossrio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194
25 Apndice C: Leituras recomendadas 195
25.1 C.1 Recomendaes para leitura . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195
25.2 C.2 Sites e livros sobre Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196
25.3 C.3 Livros de cincia da computao recomendados . . . . . . . . . . . . . . . . . . . . . . . . . . 197
26 Apndice D: GNU Free Documentation License 199
v
27 Indices and tables 201
vi
Aprenda Computao com Python 3.0, Verso 1
Contents:
Contedo 1
Aprenda Computao com Python 3.0, Verso 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 prossional 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 prossionais, 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 3.0, Verso 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 nalizado 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 reexo 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 signicava que ele poderia ser usado livremente e modicado 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 ortogrco ou um trecho difcil, eu os encorajei a procurar por erros no livro, dando a eles pontos
de bonicao cada vez que zessem 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 prossional 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 nal
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 conrmado a
convenincia de Python no ensino de alunos iniciantes. Python simplica 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 3.0, Verso 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 signica 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 ca 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 signicado de varivel
que eles aprenderam em seus cursos de matemtica. Eu tive muito menos diculdade 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 diculdade na compreenso de funes. O problema principal gira em torno da
diferena entre a denio 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 denies de funo
comeam com def, ento eu simplesmente digo aos meus alunos Quando voc dene uma funo, comece com
def, seguido do nome da funo que voc est denindo; quando voc chama uma funo, simplesmente chame-a
digitando o nome dela. Parmetros cam nas denies; 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 signicativos 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 3.0, Verso 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 prossionais 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 prossionais 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 grcos. Com tal enfoque prtico temos uma bela maneira de alcanar o engajamento dos alunos e
permitir que eles nalizem projetos signicativos. 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 3.0, Verso 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, quei 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. Em-
bora estes comentrios reram-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 iningir 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 (especicamente, 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
car 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 3.0, Verso 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 signica que podem
rodar em diferentes tipos de computador, com pouca ou nenhuma modicao. 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:
$ python3.0
Python 3.0.1+ (r301:69556, Apr 15 2009, 15:59:22)
[GCC 4.3.3] 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 tambmpode escrever umprograma emumarquivo e usar o interpretador para executar o contedo desse arquivo.
10 Captulo 3. Captulo 1: O caminho do programa
Aprenda Computao com Python 3.0, Verso 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 modic-lo no futuro.
3.2 1.2 O que um programa?
Um programa uma sequncia de instrues que especicam 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 denir programao como o processo de
dividir uma tarefa grande e complexa em subtarefas cada vez menores, at que as subtarefas sejam simples o suciente
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 3.0, Verso 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 signicativo 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. Especicamente,
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 signicado do programa
(sua semntica ou lgica) est errado. Identicar 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, desaadoras 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
modica o seu programa e tenta de novo. Se a sua hiptese estava correta, ento voc consegue prever o resultado da
modicao e ca 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 modicaes, 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 3.0, Verso 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 Greeneld, 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 especcas. 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 tendema 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 cha, entende que a cha o sujeito e caiu o verbo. Uma vez
que voc analisou a frase, consegue entender o seu signicado, ou a semntica da frase. Assumindo que voc saiba o
que uma cha e o que signica 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 signica 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 3.0, Verso 1
literalidade: As linguagens naturais esto cheias de expresses idiomticas e metforas. Se eu digo Caiu a cha,
possvel que no exista cha 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 diculdade 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 signicado. A prosa mais
fcil de analisar do que a poesia, mas ainda , muitas vezes, ambgua.
programas: O signicado 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, identicando os smbolos e interpretando a estrutura.
Finalmente, os detalhes so importantes. Pequenas coisas, como erros ortogrcos 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 que faz a chamada da funo 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 m do valor, elas no aparecem no resultado nal.
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.
funo print (print statement) Funo 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 3.0, Verso 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 especcos,
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 especica uma computao.
script Um programa guardado em um arquivo (normalmente um que ser interpretado).
semntica (semantics) O signicado 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 3.0, Verso 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 identicar strings porque elas aparecem entre aspas.
A funo 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!")
<class str>
17
Aprenda Computao com Python 3.0, Verso 1
>>> type(17)
<class int>
Nenhuma surpresa: strings pertencem ao tipo str 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 utuante
1
:
>>> type(3.2)
<class float>
O que dizer de valores como "17" e "3.2"? Eles parecem nmeros, mas esto entre aspas, como strings:
>>> type("17")
<class str>
>>> type("3.2")
<class str>
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 utuante 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 gura 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 3.0, Verso 1
A funo 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)
<class str>
>>> type(n)
<class int>
>>> type(pi)
<class 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 signicativos 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
zer, 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 3.0, Verso 1
Ocorre que class uma das palavras reservadas em Python. Palavras reservadas denem as regras e a estrutura da
linguagem e no podem ser usadas como nomes de variveis.
Python tem 33 palavras reservadas:
and def for is raise False
as del from lambda return None
assert elif global nonlocal try True
break else if not while
class except import or with
continue finally in pass yield
Pode ser til ter essa lista mo. 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. Essa lista pode ser obtida atravs do prprio interpretador Python, com apenas
dois comandos:
import keyword
print (keyword.kwlist)
4.4 2.4 Comandos
Um comando uma instruo que o interpretador Python pode executar. Vimos at agora dois tipos de comandos: de
exibio (a chamada da funo 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 como a chamada da funo 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:
20 Captulo 4. Captulo 2: Variveis, expresses e comandos
Aprenda Computao com Python 3.0, Verso 1
>>> 17
17
>>> x
2
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 signica que as aspas so includas
2
. 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 signicados so mais ou menos claros:
20+32 hora-1 hora
*
60+minuto minuto/60 minuto//60 5
**
2 (5+9)
*
(15-7)
Em Python, os smbolos +, -, / e o uso de parnteses para agrupamento tm o mesmo signicado que em matemtica.
O asterisco (
*
) o smbolo para multiplicao,
**
o smbolo para potenciao e // o smbolo para diviso inteira.
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: quando todos os operandos so inteiros, o
resultado da operao um valor inteiro. Voc pode car surpreso com a diviso. Observe as seguintes operaes:
>>> minuto = 59
>>> minuto/60
0.98333333333333328
>>> minuto = 59
>>> minuto//60
0
O valor de minuto 59 e, em aritmtica convencional (/), 59 dividido por 60 0,98333. J a diviso inteira (//) de 59
por 60 0.
2
N.T.: Python aceita aspas simples ou duplas para delimitar strings.
4.6. 2.6 Operadores e operandos 21
Aprenda Computao com Python 3.0, Verso 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 signica 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 signicativa 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?
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.
22 Captulo 4. Captulo 2: Variveis, expresses e comandos
Aprenda Computao com Python 3.0, Verso 1
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
uma chamada da funo 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) Simplicar 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 grca 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-utuante (oating-point) Formato para representar nmeros que possuem partes fracionrias.
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-utuante (tipo float) e strings (tipo string).
4.10. 2.11 Glossrio 23
Aprenda Computao com Python 3.0, Verso 1
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 Denies 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)
<class 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)
<class str>
25
Aprenda Computao com Python 3.0, Verso 1
Como outro exemplo, a funo id recebe um valor ou uma varivel e retorna um inteiro, que atua como um identi-
cador nico para aquele valor:
>>> id(3)
134882108
>>> bia = 3
>>> bia(beth)
134882108
Todo valor temumid, que umnmero 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 utuante 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 utuante:
>>> 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 utuante 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.
26 Captulo 5. Captulo 3: Funes
Aprenda Computao com Python 3.0, Verso 1
Uma soluo converter minuto para ponto utuante e fazer a diviso em ponto utuante:
>>> 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 utuante.
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. Osen 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 especicar 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
5.4. 3.4 Funes matemticas 27
Aprenda Computao com Python 3.0, Verso 1
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.5 3.5 Composio
Do mesmo modo como nas funes matemticas, as funes do Python podem ser compostas, o que signica 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 especicada numa denio de funo. At agora, as funes que usamos neste livro
so pr-denidas e suas denies no foram apresentadas. Isso demonstra que podemos usar funes sem ter que nos
preocupar com os detalhes de suas denies.
A sintaxe para uma denio 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 especica 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 ()
28 Captulo 5. Captulo 3: Funes
Aprenda Computao com Python 3.0, Verso 1
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 chama a
funo 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 :
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 quatro 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-
car 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.6. 3.6 Adicionando novas funes 29
Aprenda Computao com Python 3.0, Verso 1
5.7 3.7 Denies e uso
Reunindo os fragmentos de cdigo da Seo 3.6, o programa completo ca assim:
def novaLinha() :
print ()
def tresLinhas() :
novaLinha()
novaLinha()
novaLinha()
print (Primeira Linha.)
tresLinhas()
print (Segunda Linha.)
Esse programa contm duas denies de funes: novaLinha e tresLinhas. Denies de funes so exe-
cutadas como quaisquer outros comandos, mas o efeito criar a nova funo. Os comandos dentro da denio da
funo no so executados at que a funo seja chamada, logo, a denio da funo no gera nenhuma sada.
Como voc j deve ter imaginado, preciso criar uma funo antes de poder execut-la. Emoutras palavras, a denio
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 denies. 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 denio de
novaLinha para depois da denio de tresLinhas. O que acontece quando voc roda este pro-
grama?
5.8 3.8 Fluxo de execuo
Para assegurar que uma funo esteja denida antes do seu primeiro uso, preciso saber em que ordem os comandos
so executados, ou seja, descobrir qual o uxo 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 denies de funo no alteram o uxo 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 denir uma funo dentro de outra.
Neste caso, a denio mais interna no executada at que a funo mais externa seja chamada.
Chamadas de funo so como um desvio no uxo de execuo. Em vez de ir para o prximo comando, o uxo 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 m 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 uxo de execuo.
30 Captulo 5. Captulo 3: Funes
Aprenda Computao com Python 3.0, Verso 1
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 denida pelo usurio, que recebe um parmetro:
def imprimeDobrado(bruno):
print (bruno, bruno)
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:
>>> imprimeDoobrado(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 denidas 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, assimimprimeDobrado 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.9. 3.9 Parmetros e argumentos 31
Aprenda Computao com Python 3.0, Verso 1
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.
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:
32 Captulo 5. Captulo 3: Funes
Aprenda Computao com Python 3.0, Verso 1
A ordem da pilha mostra o uxo de execuo. imprimeDobrado foi chamado por concatDupla, e
concatDupla foi chamado por __main__ (principal), que umnome 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
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
Aessa 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)?
5.12. 3.12 Funes com resultados 33
Aprenda Computao com Python 3.0, Verso 1
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 armativa 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.
denio de funo (function denition) Comando que cria uma nova funo, especicando seu nome, parmetros
e comandos que ela executa.
diagrama da pilha (stack diagram) Representao grca da pilha de funes, suas variveis e os valores aos quais
elas se referem.
uxo de execuo (ow 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.
notao de ponto (dot notation) A sintaxe para chamar uma funo que est em outro mdulo, especicando 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 denida dentro da funo. Uma varivel local s pode ser usada dentro da
funo onde foi denida.
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 innita
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 3.0, Verso 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 True, e uma expresso que falsa tem o valor False.
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 (signicado) destes operadores similar
aos seus signicados 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
36 Captulo 6. Captulo 4: Condicionais e recursividade
Aprenda Computao com Python 3.0, Verso 1
Em geral, esse tipo de coisa no considerado de bom estilo. Se voc precisa comparar um valor com zero, deve
faz-lo explicitamente.
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 m 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 ramicaes no uxo de execuo.
Por nal, 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")
6.4. 4.4 Execuo condicional 37
Aprenda Computao com Python 3.0, Verso 1
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.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)
38 Captulo 6. Captulo 4: Condicionais e recursividade
Aprenda Computao com Python 3.0, Verso 1
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 simplicar 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.")
A instruo print executada somente se a zermos 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 m. 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 uxo 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:
6.8. 4.8 A instruo return 39
Aprenda Computao com Python 3.0, Verso 1
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)
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=1 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)
40 Captulo 6. Captulo 4: Condicionais e recursividade
Aprenda Computao com Python 3.0, Verso 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 gura mostra um diagrama de pilha para contagemRegressiva, chamada com n = 3:
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 innita
Se uma recursividade nunca chega ao caso base, ela prossegue fazendo chamadas recursivas para sempre, e o programa
nunca termina. Isto conhecido como recursividade innita, e geralmente no considerada uma boa ideia. Aqui est
um programa mnimo com uma recursividade innita:
6.10. 4.10 Diagramas de pilha para funes recursivas 41
Aprenda Computao com Python 3.0, Verso 1
def recursiva():
recursiva()
Na maioria dos ambientes de programao, um programa com recursividade innita 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 innita e rode-a no interpretador Python.
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 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 input retorna o que o usurio digitou como uma cadeia de caracteres
(string):
>>> entrada = input()
O que voc est esperando?
>>> print (entrada)
O que voc est esperando?
Antes de chamar input, uma boa ideia exibir uma mensagem dizendo ao usurio o que ele deve entrar. Esta
mensagem como se fosse uma pergunta ou um alerta(prompt). Esta pergunta pode ser enviada como um argumento
para input:
>>> nome = 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 int aplicada funo input:
pergunta = "Qual... a velocidade de vo de uma andorinha?\n"
velocidade = int(input(pergunta))
Se o usurio digita uma cadeia de dgitos, ela convertida para um inteiro e atribuda a velocidade. Infelizmente,
se o usurio digitar um caractere que no seja um dgito, o programa trava:
>>> velocidade = int(input(pergunta))
Qual... a velocidade de vo de uma andorinha?
De qual voc fala, uma andorinha Africana ou uma Europeia?
SyntaxError: invalid syntax
42 Captulo 6. Captulo 4: Condicionais e recursividade
Aprenda Computao com Python 3.0, Verso 1
Para evitar esse tipo de erro, geralmente bom usar 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 uxo 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.
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 innita (innite recursion) Funo que chama a si mesma recursivamente sem nunca chegar ao caso
base. Aps algum tempo, uma recursividade innita causa um erro de execuo.
6.13. 4.13 Glossrio 43
Aprenda Computao com Python 3.0, Verso 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 conana (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 3.0, Verso 1
J vimos a instruo return antes, mas em uma funo frutfera a instruo return inclui um valor de retorno.
Esta instruo signica: 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 uxo 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 diculdade, especialmente comerros emtempo 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)
46 Captulo 7. Captulo 5: Funes frutferas
Aprenda Computao com Python 3.0, Verso 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)?
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 utuante.
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 signica 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 conrmamos 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 as chamadas da funo print que havamos escrito no passo anterior. Cdigo como este ajuda
a escrever o programa, mas no parte do produto nal (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:
7.2. 5.2 Desenvolvimento de programas 47
Aprenda Computao com Python 3.0, Verso 1
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.
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
48 Captulo 7. Captulo 5: Funes frutferas
Aprenda Computao com Python 3.0, Verso 1
Chamamos esta funo de area2 para distinguir da funo area, denida 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 angular 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).
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.4. 5.4 Funes booleanas 49
Aprenda Computao com Python 3.0, Verso 1
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 signica 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 armao 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, cou conhecido como Tese de Turing. Se voc
zer 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 denidas. Uma denio recursiva similar uma denio circular, no sentido
de que a denio faz referncia coisa que est sendo denida. Uma verdadeira denio circular no muito til:
vorpal: adjetivo usado para descrever algo que vorpal.
Se voc visse esta denio em um dicionrio, caria confuso. Por outro lado, se voc procurasse pela denio da
funo matemtica fatorial, voc encontraria algo assim:
0! = 1
n! = n.(n-1)!
Esta denio 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 denio 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 uxo de execuo para este programa similar ao uxo 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 ...
50 Captulo 7. Captulo 5: Funes frutferas
Aprenda Computao com Python 3.0, Verso 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 1, 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:
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 conana (Leap of faith)
Seguir o uxo de execuo uma maneira de ler programas, mas que pode rapidamente se transformar emumlabirinto.
Uma alternativa o que chamamos de voto de conana. Quando voc tem uma chamada de funo, em vez de
seguir o uxo de execuo, voc assume que a funo funciona corretamente e retorna o valor apropriado.
De fato, voc est agora mesmo praticando este voto de conana 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 uxo 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.
7.6. 5.6 Voto de conana (Leap of faith) 51
Aprenda Computao com Python 3.0, Verso 1
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 conana!
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
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 denida recursivamente fibonacci,
a qual tem a seguinte denio:
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 uxo de execuo aqui, mesmo para valores bem pequenos de n, sua cabea explodir. Mas,
de acordo com o voto de conana, 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 innita. 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 utuante, 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, caremos com a segunda.
52 Captulo 7. Captulo 5: Funes frutferas
Aprenda Computao com Python 3.0, Verso 1
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 certicar 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)
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 nal.
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 3.0, Verso 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, end="")
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. O argumento end="" do primeiro comando print suprime a nova linha no nal 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 3.0, Verso 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
Aterceira linha muda o valor de a mas no muda o valor de b, ento, elas no so mais iguais. (Emalgumas 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 ca 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 signica, 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 uxo 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 3.0, Verso 1
O corpo consiste de todos os comandos abaixo do cabealho, com a mesma endentao.
Este tipo de uxo 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 innito. Uma fonte
de diverso sem m para os cientistas da computao a observao de que as instrues da embalagem de shampoo,
Lave, enxge, repita um loop innito.
No caso de contagemRegressiva, podemos provar que o loop terminar porque sabemos que o valor de n nito,
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 armar:
def sequencia(n):
while n != 1:
print (n, end="")
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 especcos 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 caram 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-utuante.
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 3.0, Verso 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 uma chamada da funo 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 modicar 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 :
58 Captulo 8. Captulo 6: Iterao
Aprenda Computao com Python 3.0, Verso 1
1.0 0.0
2.0 1.0
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, modique 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, , end="")
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, o argumento end= na funo print suprime a nova linha. Depois que o loop se completa, a segunda
chamada da funo 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.4. 6.4 Tabelas de duas dimenses (ou bi-dimensionais) 59
Aprenda Computao com Python 3.0, Verso 1
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
na seo 4.5; e eDivisivel na seo 5.4
Generalizao signica tomar algo que especco, 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 , end="")
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 z foi substituir a
chamada da funo 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 nal da seo 6.5 e acondicion-lo, envolv-lo
em uma funo:
60 Captulo 8. Captulo 6: Iterao
Aprenda Computao com Python 3.0, Verso 1
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.
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 denio de funo so locais; voc no pode acessar uma varivel local de fora da
funo em que ela mora. Isto signica 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.7. 6.7 Variveis locais 61
Aprenda Computao com Python 3.0, Verso 1
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:
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 especicar 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, end="")
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
62 Captulo 8. Captulo 6: Iterao
Aprenda Computao com Python 3.0, Verso 1
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:
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 innito (innite 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.
8.9. 6.9 Funes 63
Aprenda Computao com Python 3.0, Verso 1
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 denir 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 especco (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.
plano de desenvolvimento (development plan) um processo denido para desenvolvimento de um programa. Neste
captulo, ns demonstramos um estilo de desenvolvimento baseado em escrever cdigo para executar tarefas
simples e especcas, 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 Classicao de caracteres
7.11 Glossrio
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:
a
65
Aprenda Computao com Python 3.0, Verso 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 especica 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 car 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 m. Este padro de
processamento chamado uma travessia (traversal, com a idia de percorrimento). Uma maneira de codicar uma
travessia com um comando while:
indice = 0
while indice < len(fruta):
letra = fruta[indice]
66 Captulo 9. Captulo 7: Strings
Aprenda Computao com Python 3.0, Verso 1
print (letra)
indice = indice + 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
simplicada - 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, modique 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
9.4. 7.4 Fatias de strings 67
Aprenda Computao com Python 3.0, Verso 1
>>> 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:
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 nal da string. Assim:
>>> fruta = "banana"
>>> fruta[:3]
ban
>>> fruta[3:]
ana
O que voc acha de s[:] signica?
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.
68 Captulo 9. Captulo 7: Strings
Aprenda Computao com Python 3.0, Verso 1
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)
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 signica 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 + saudao[1:]
print (novaSaudacao)
A soluo aqui concatenar uma nova primeira letra com uma fatia de saudao. 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 (nds) 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 (nd) o que est
procurando, ele pode gritar Eureka! e parar de procurar.
Como um exerccio, modique a funo nd (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:
9.6. 7.6 Strings so imutveis 69
Aprenda Computao com Python 3.0, Verso 1
fruta = "banana"
contador = 0
for letra in fruta:
if letra == a
contador = contador + 1
print (contador)
Este programa demonstra umoutro padro de computao chamado de contador. Avarivel 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 temrelao comexcremento, que umsubstantivo.) Quando se sai do loop, contador
guarda o resultado - o nmero total de as.
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
Omdulo string inclui uma funo chamada find (encontrar) que faz a mesma coisa que a funo que escrevemos.
Para cham-la, temos que especicar 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 denidas pelo usurio. Usando a notao de ponto podemos especicar 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 especica o ndice pelo qual ela deve comear sua procura:
>>> string.find("banana", "na", 3)
4
Ou ela pode receber dois argumentos adicionais que especicam 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.
70 Captulo 9. Captulo 7: Strings
Aprenda Computao com Python 3.0, Verso 1
9.10 7.10 Classicao 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 classicar caracteres. Por exemplo, se
find(lowercase, ch) retorna um valor outro que no -1, ento ch deve ser minsculo:
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 denida 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.
9.10. 7.10 Classicao de caracteres 71
Aprenda Computao com Python 3.0, Verso 1
fatia (slice) Uma parte de uma string especicada 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.
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 identicado 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 3.0, Verso 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 oat, 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:
>>> list(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:
>>> list(range(10))
[0,1, 2, 3, 4, 5, 6, 7, 8, 9]
Se existe um terceiro argumento, ele especica o espao entre os valores sucessivos, que chamado de tamanho do
passo. Este exemplo conta de 1 at 10 em passos de 2:
>>> list(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 especica 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 modica 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:
74 Captulo 10. Captulo 8: Listas
Aprenda Computao com Python 3.0, Verso 1
>>> 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):
>>> numeros[2]=5
IndexError: list assignment index out of range
Se um ndice possui um valor negativo, ele conta ao contrrio a partir do nal 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 modicando 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:
10.3. 8.3 Comprimento da lista 75
Aprenda Computao com Python 3.0, Verso 1
>>> [spam!, 1, [Brie, Roquefort, Pol l Veq], [1, 2 3]]
Como umexerccio, escreva umlao 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:
>>> 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 VARIVEL in LISTA:
CORPO
Esta declarao equivalente a:
>>> i = 0
while i < len(LIST):
VARIABLE = LIST[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:
76 Captulo 10. Captulo 8: Listas
Aprenda Computao com Python 3.0, Verso 1
>>> 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:
>>> 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 signica que podemos modicar seus elementos. Utilizando o
operador colchete no lado esquerdo de uma atribuio, podemos atualizar um de seus elementos:
10.6. 8.6 Operaes em listas 77
Aprenda Computao com Python 3.0, Verso 1
>>> 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 enando-os numa fatia vazia na posio desejada:
>>> 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.
78 Captulo 10. Captulo 8: Listas
Aprenda Computao com Python 3.0, Verso 1
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.
Todo objeto possui um identicador nico, que podemos obter com a funo id. Exibindo o identicador de a e b,
podemos dizer se elas se referem ao mesmo objeto.
>>> id(a)
135044008
>>> id(b)
135044008
De fato, obtivemos o mesmo identicador duas vezes, o que signica 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 ca assim:
a e b possuem o mesmo valor mas no se referem ao mesmo objeto.
10.10. 8.10 Ojetos e valores 79
Aprenda Computao com Python 3.0, Verso 1
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]
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 modicar 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.
80 Captulo 10. Captulo 8: Listas
Aprenda Computao com Python 3.0, Verso 1
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.
Se a funo modica 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.13. 8.13 Lista como parmetro 81
Aprenda Computao com Python 3.0, Verso 1
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:
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.
82 Captulo 10. Captulo 8: Listas
Aprenda Computao com Python 3.0, Verso 1
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 especicar 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...
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 identicado 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 identicado 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.16. 8.16 Strings e listas 83
Aprenda Computao com Python 3.0, Verso 1
10.18 Outros termos utilizados neste captulo
(XXX esta lista deve ser retirada na verso nal)
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 modicar
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?)
XXX handle tratar
XXX proceed agir
XXX By default por padro
XXX notice perceber (observar?)
XXX mirabile dictu Algum tem idia do que signica 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
modicados, 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 nal:
>>> t1 = (a,)
>>> type(t1)
<class tuple>
Sem a vrgula, Python entende (a) como uma string entre parnteses:
85
Aprenda Computao com Python 3.0, Verso 1
>>> t2 = (a)
>>> type(t2)
<class str>
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 modicar um dos elementos de uma tupla, teremos um erro:
>>> tupla[0] = A
TypeError: object doesnt support item assignment
Naturalmente, mesmo que no possamos modicar 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
86 Captulo 11. Captulo 9: Tuplas
Aprenda Computao com Python 3.0, Verso 1
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:
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 utuante (oating-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.
11.3. 9.3 Tuplas como valores de retorno 87
Aprenda Computao com Python 3.0, Verso 1
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.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 signica 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 emsubproblemas, e encontrar umsubproblema
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:
88 Captulo 11. Captulo 9: Tuplas
Aprenda Computao com Python 3.0, Verso 1
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.:
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 modicao 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 car 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:
11.7. 9.7 Vrios intervalos 89
Aprenda Computao com Python 3.0, Verso 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
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 conrmar 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 eciente 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.
90 Captulo 11. Captulo 9: Tuplas
Aprenda Computao com Python 3.0, Verso 1
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:
indice = int(i
*
numeroDeIntervalos)
intervalos[indice] = intervalos[indice] + 1
Usamos a funo int para converter um nmero em ponto utuante (oat) 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 modicado. 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 modicados. 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 identicar um teste padro
computacional familiar e copiar a soluo para um problema similar.
11.9. 9.9 Glossrio 91
Aprenda Computao com Python 3.0, Verso 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 voc aprendeu - strings, listas e tuplas - utilizam inteiros como indices. Se voc tentar utilizar
qualquer outro tipo como ndice, voc receber um erro.
Dicionrios so similiares a outros tipos compostos exceto por eles poderem usar qualquer tipo imutvel de dados
como ndice. 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 dicionrio 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 dicionrio chamado ing2esp; as outras atribuies adicionam novos elementos para
o dicionrio. Nos podemos imprimir o valor corrente de um dicionrio 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 ndice e
um valor separado por dois-pontos. Em um dicionrio, os ndices so 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 3.0, Verso 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]
94 Captulo 12. Captulo 10: Dicionrios
Aprenda Computao com Python 3.0, Verso 1
Dessa forma o ponto especica 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.
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 get recebe
uma chave e retorna o valor associado se a chave existe no dicionrio, e nada (None) caso contrrio:
>>> ing2esp.get(one)
uno
>>> ing2esp.get(deux)
>>>
Se voc tentar chamar um mtodo sem especicar em qual objeto, voc obter um erro. Nesse caso, a mensagem de
erro no muito til:
>>> get(one)
NameError: get
in um operador lgico que testa se uma chave est no dicionrio. Ns o utilizamos na Seo 7.10 com strings e
na Seo 8.4 com listas, mas ele tambm funciona com dicionrios:
>>> one in ing2esp
True
>>> deux in ing2esp
False
12.3 10.3 Aliasing (XXX) e Copiar
Uma vez que os dicionrios so mutveis, voc precisa saber sobre Aliasing. Sempre que duas variveis referenciarem
o mesmo objeto, quando uma alterada, afeta a outra.
Se voc quer modicar 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
modicar o alias, opposites tambm ser alterado.
12.3. 10.3 Aliasing (XXX) e Copiar 95
Aprenda Computao com Python 3.0, Verso 1
>>> alias[right] = left
>>> opossites[right]
left
Se modicarmos copy, opposites no ser modicado:
>>> 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:
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 especicada:
96 Captulo 12. Captulo 10: Dicionrios
Aprenda Computao com Python 3.0, Verso 1
>>> 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 denitivamente melhora a semntica e a sintaxe do acesso a matrizes esparsas.
12.5 10.5 Hint XXX
Se voc brincou com a funo bonacci 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.
Em uma das nossas mquinas, bonacci(20) executa instantaneamente, bonacci(30) demora cerca de um segundo,
e bonacci(40) demora uma eternidade.
Para entender o porque, considere o grco de chamadas para bonacci com n=4:
12.5. 10.5 Hint XXX 97
Aprenda Computao com Python 3.0, Verso 1
O grco mostra a estrutura da funo, com linhas conectando cada execuo com a execuo que a chamou. No
topo do grco, bonacci tem n=4, que chama bonacci com n=3 e n=2. Em seguida, bonacci com n=3 chama
bonacci com n=2 e n=1. E assim por diante.
Conte quantas vezes bonacci(0) e bonacci(1) so chamadas. Essa uma soluo ineciente 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
bonacci 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.
Sempre que bonacci chamada, ela verica 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
98 Captulo 12. Captulo 10: Dicionrios
Aprenda Computao com Python 3.0, Verso 1
estiver ali, ele calculado no newValue. O valor de newValue adicionado no dicionrio antes da funo retornar.
Usando essa verso de bonacci, nossa mquina consegue calcular bonacci(40) em um piscar de olhos. Mas quando
tentamos calcular bonacci(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 overow. 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 nal:
>>> type(1L)
<class 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 modicar muito para adaptar -
bonacci:
>>> previous = {0: 1L, 1:1L}
>>> fibonacci(50)
20365011074L
Somente trocando os valores iniciais de previous, conseguimos mudar o comportamento da bonacci. 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.
12.6. 10.6 Inteiros Longos 99
Aprenda Computao com Python 3.0, Verso 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 nal, 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 imutvel, 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.
overow Um resultado numrico que muito grande para ser representado no formato numrico.
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 cam 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 identicado 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 especica 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 3.0, Verso 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 signica
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 uma chamada da funo 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, escrever):
>>> 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 sucientes no arquivo, read retorna os caracteres restantes. Quando chegamos ao nal 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:
102 Captulo 13. Captulo 11: Arquivos e excees
Aprenda Computao com Python 3.0, Verso 1
def copiaArquivo(velhoArquivo, novoArquivo):
f1 = open(velhoArquivo, "r")
f2 = open(novoArquivo, "w")
while 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 uxo de execuo passa para o
primeiro comando depois do loop.
Neste exemplo, o loop while innito 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 m 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 signica que as strings aparecem entre aspas e o caractere de nova
linha aparece como a seqncia de escape 012.
No m 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 #:
13.2. 11.1 Arquivos texto 103
Aprenda Computao com Python 3.0, Verso 1
def filtraArquivo(velhoArquivo, novoArquivo):
f1 = open(velhoArquivo, "r")
f2 = open(novoArquivo, "w")
while 1:
texto = f1.readline()
if texto == "":
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 uxo 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
uxo 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?? signica 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 utuante, e %s
formata o prximo como uma string:
104 Captulo 13. Captulo 11: Arquivos e excees
Aprenda Computao com Python 3.0, Verso 1
>>> "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 utuante 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
>>> "%d" % reais
TypeError: illegal argument type for built-in operation
No primeiro exemplo, no existem expresses sucientes; no segundo, a expresso do tipo errado.
Para um controle maior na formatao de nmeros, podemos especicar 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-utuante, tambm podemos especicar 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 caro 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.3. 11.2 Gravando variveis 105
Aprenda Computao com Python 3.0, Verso 1
13.4 11.3 Diretrios
Quando voc cria um novo arquivo abrindo-o e escrevendo nele, o novo arquivo ca 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 especicar o caminho (path) para o
arquivo, o qual o nome do diretrio (ou folder) onde o arquivo est localizado:
>>> 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)
106 Captulo 13. Captulo 11: Arquivos e excees
Aprenda Computao com Python 3.0, Verso 1
<class "float">
>>> y = pickle.load(f)
>>> y
[1, 2, 3]
>>> type(y)
<class "list">
Cada vez que invocamos load, obtemos um nico valor do arquivo, completo com seu tipo original.
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: int division or modulo by zero
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 especicidades 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 = 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:
13.6. 11.5 Excees 107
Aprenda Computao com Python 3.0, Verso 1
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.
class ErroNumeroRuim(Exception):
pass
def entraNumero():
x = int(input ("Escolha um nmero: "))
if x == 17:
raise ErroNumeroRuim("17 um nmero ruim")
return x
O comando raise toma um argumento que um objeto da classe Exception. O objeto tomado pelo comando
raise recebe, na hora de sua criao, informaes especcas sobre o erro. ErroNumeroRuim uma nova classe
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 a classe 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 (le) 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 especica a exata localizao de um arquivo.
arquivo texto (text le) 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 uxo 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 denidos pelo usurio
12.2 Atributos
12.3 Instncias como parmetros
12.4 O signicado 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 denidos 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 utuante. 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 denir um novo tipo composto, tambm chamado uma classe. Esta abordagem envolve um pouco
mais de esforo, mas ela tem vantagens que logo caro evidentes.
Eis a denio 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 utuante 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 3.0, Verso 1
class Ponto:
pass
Denies de classes podem aparecer em qualquer parte de um programa, mas elas costuma car prximas do comeo
do programa (aps os comandos import). As regras de sintaxe para a denio de classes so as mesmas de outros
comandos compostos (veja Seo 4.4).
A denio 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 utuante.
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 signica, V ao objeto final e pegue o valor de x. Neste caso, atribumos este valor
a uma varivel cujo nome x. No h conito entre a varivel x e o atributo x. O propsito da notao
objeto.atributo identicar 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 3.0, Verso 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 denida no prgrama principal: __main__.
80f8e70 o identicador 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 identicador nico do
objeto. Traduza a forma hexadecimal para a forma decimal e conrme 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 signicado de mesmo
O signicado 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 vericar se duas referncias se referem ao mesmo objeto, use o operador ==
3
. Por exemplo:
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 vericar 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 3.0, Verso 1
>>> p1 = Ponto()
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = Ponto()
>>> 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 vericar 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 especicar um retngulo? Para manter as coisas simples, assuma que o retngulo orientado verticalmente ou
horizontalmente, nunca em um ngulo.
H algumas possibilidades: poderamos especicar o centro do retngulo (duas coordenadas) e seu tamanho (largura e
altura); ou poderamos especicar um dos lados e o tamanho; ou poderamos especicar dois lados opostos. A escolha
convencional especicar o canto superior esquerdo do retngulo e o tamanho.
Novamente, vamos denir uma nova classe:
class Rectangle:
pass
E instanci-la:
112 Captulo 14. Captulo 12: Classes e objetos
Aprenda Computao com Python 3.0, Verso 1
box = Rectangle()
box.width = 100.0
box.height = 200.0
Este cdigo cria um novo objeto Retngulo com dois atributos ponto-utuante. Para especicar o canto superior
esquerdo, podemos embutir um objeto dentro de um objeto!
box.corner = Ponto()
box.corner.x = 0.0;
box.corner.y = 0.0;
A expresso box.corner.x signica, 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 gura mostra o estado deste objeto:
14.6 12.6 Instancias como valores retornados
Funes podem retornar instncias. Por exemplo, ndCenter 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 modicar os valores de sua largura e altura. Veja:
14.6. 12.6 Instancias como valores retornados 113
Aprenda Computao com Python 3.0, Verso 1
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
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
como 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 zemos 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 suciente. Isto
eh chamado shallow copia.
114 Captulo 14. Captulo 12: Classes e objetos
Aprenda Computao com Python 3.0, Verso 1
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 car assim:
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 car 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 modicar 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
modicar o antigo.
14.9 12.9 Glossrio
classe (class) Um tipo composto (XXX compound type) denido pelo usurio. Uma classe tambm pode ser visual-
izada como um molde que dene 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.
14.9. 12.9 Glossrio 115
Aprenda Computao com Python 3.0, Verso 1
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.
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 Modicadores
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 denido pelo usurio, vamos denir uma classe chamada Horario que grava os registros
de horrio do dia. Eis a denio 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 3.0, Verso 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 modicadoras.
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 modica 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 3.0, Verso 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 car grande. Depois vamos sugerir uma aproximao alterna-
tiva que rende um cdigo menor. Clique aqui para feedback
15.3 13.3 Modicadores
Existem momentos quando til para uma funo modicar 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 modicadores.
incrementar, que adiciona um nmero dado de segundos para um objeto Horario, que poderia ser escrito quase
naturalmente como um modicador. 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
suciente 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:
15.3. 13.3 Modicadores 119
Aprenda Computao com Python 3.0, Verso 1
horario.segundos = horario.segundos - 60
horario.minutos = horario.minutos + 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 eciente.
Como umexerccio, reescreva esta funo de maneira que ela no contenha nenhumloop. Como umsegundo 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 modicadores tambm podem ser feitas com funes puras. De fato, algumas
linguagens de programao permitemapenas funes puras. Existe alguma evidncia que programas que usamfunes
puras so desenvolvidos mais rapidamente e so menos propensos a erros que programas que usam modicadores. No
entanto, modicadores as vezes so convenientes, e em alguns casos, programao funcional menos eciente.
Em geral, recomendamos que voc escreva funes puras sempre que for necessrio e recorrer para modicadores 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 ecaz, 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:
120 Captulo 15. Captulo 13: Classes e funes
Aprenda Computao com Python 3.0, Verso 1
def criarHorario(segundos):
horario = Time()
horario.horas = segundos/3600
segundos = segundos - horario.horas
*
3600
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 convel.
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 especca para
um nico problema, voc escreveu um algortmo. Ns mencionamos isso antes mas no denimos cuidadosamente.
Isso no fcil para denir, 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
especcas. 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
15.6. 13.6 Generalizao 121
Aprenda Computao com Python 3.0, Verso 1
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.
Por outro lado, o processo de projetar algoritmos interessante, intelectualmente desaante, e uma parte central
daquilo que chamamos programao.
Algumas das coisas que as pessoas fazem naturalmente, sem diculdade 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 modica nenhum dos objetos que ela recebe como parmetro. A
maioria das funes puras frutfera.
modicador (modier) Uma funo que muda um ou mais dos objetos que ela recebe como parmetros. A maioria
dos modicadores 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 comum
prottipo e gradualmente melhorando-o.
desenvolvimento planejado (planned development) Uma maneira de desenvolver programas que envolvemuma 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
unicadas...
16.1 14.1 Caractersticas da orientao a objetos
Python uma linguagem de programao orientada a objetos, o que signica que ela tem caractersticas que
suportam a programao orientada a objetos.
No fcil denir programao orientada a objetos, mas temos visto already algumas de suas caractersticas:
Programas so construdos sobre denies de objetos e denies de funes, e a maioria das computaes
expressa em termos de operaes sobre objetos.
Cada denio 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, denida no captulo 13 corresponde maneira como as pessoas registram as horas do
dia, e as funes que denimos 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 zemos, 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 denio da classe e a denio da funo
que segue. Com alguma investigao, ca aparente que toda funo toma pelo menos um objeto Time como um
parmetro.
123
Aprenda Computao com Python 3.0, Verso 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 denidos dentro da denio 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, denimos uma classe chamada Horrio (Time) e voc escreveu uma funo chamada exibeHora
(printTime), que deve ter cado 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 ummtodo, tudo o que temos a fazer mover a denio da funo para dentro da denio
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 notao 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.
124 Captulo 16. Captulo 14: Classes e mtodos
Aprenda Computao com Python 3.0, Verso 1
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.
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 ca 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
denidos 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 denio do mtodo para dentro da denio 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 denidas 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.
16.3. 14.3 Um outro exemplo 125
Aprenda Computao com Python 3.0, Verso 1
mtodo Uma funo que denida dentro de uma denio de classe e chamada em instncias desta classe.
override (sem traducao; termo consagrado) Substituir uma denio 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 denidos pelo usurio.
produto escalar Operao denida na lgebra linear que multiplica dois pontos (com coordenadas (x,y,z)) e retorna
um valor numrico.
multiplicao por escalar Operao denida na lgebra linear que multiplica cada uma das coordenadas de um ponto
por um valor numrico.
polimrca 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 car 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 3.0, Verso 1
Se quisermos denir 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 codicar as posies e naipes. Codicar, neste caso, no signica o mesmo
que as pessoas normalmente pensam, que criptografar ou traduzir para um cdigo secreto. O que um cientista da
computao quer dizer com codicar denir 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 gura 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
denio de classe para o tipo Carta ca 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 denio 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
128 Captulo 17. Captulo 15: Conjuntos de objetos
Aprenda Computao com Python 3.0, Verso 1
def __str__(self):
return (self.listaDePosicoes[self.posicao] + " de " +
self.ListaDeNaipes[self.naipe])
Um atributo de classe denido 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-
nica 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 codicar 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 modicarmos 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 = "Baleias Rodopiantes"
>>> print (carta1)
3 de Baleias Rodopiantes
O problema que todos os Ouros se tornam Baleias Rodopiantes:
>>> print (carta2)
3 de Baleias Rodopiantes
Normalmente, no uma boa idia modicar 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 denidos pelo usurio, ns podemos sobrescrever o comportamento
dos operadores pr-denidos 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 signica que ns podemos comparar quaisquer dois elementos e dizer
qual o maior. Por exemplo, os inteiros e os nmeros de ponto utuante so totalmente ordenados. Alguns conjuntos
17.4. 15.4 Comparando cartas 129
Aprenda Computao com Python 3.0, Verso 1
so no-ordenados, o que signica que no existe maneira signicativa 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.
O conjunto de cartas de jogo parcialmente ordenado, o que signica 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, modique __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 denir 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 denio 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 denimos 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:
130 Captulo 17. Captulo 15: Conjuntos de objetos
Aprenda Computao com Python 3.0, Verso 1
class Baralho:
...
def imprimirBaralho(self):
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 exvel. 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 chamar a funo 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.6. 15.6 Imprimindo o baralho 131
Aprenda Computao com Python 3.0, Verso 1
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.
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 verica por igualdade profunda, o mtodo
removerCarta tambm testa por igualdade profunda.
132 Captulo 17. Captulo 15: Conjuntos de objetos
Aprenda Computao com Python 3.0, Verso 1
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()
Na verdade, pop remove a ltima carta da lista. Portanto, ns estamos realmente distribuindo as cartas do m 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
codicar (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 denida dentro de uma denio 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 3.0, Verso 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
denir uma nova classe que uma verso modicada de uma classe existente.
A principal vantagem dessa caracterstica que voc pode adicionar novos mtodos a uma classe sem ter que modicar
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 lha 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 modic-las. Em alguns casos, a estrutura da herana
reete 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 denio. 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 3.0, Verso 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 classicar uma mo (trinca, ush, etc.) ou compar-la com outra mo. No jogo de bridge, podemos querer
computar a quantidade de pontos que h numa mo, a m 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 denio 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 identica 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 nal 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 sucientes no baralho, o mtodo d todas as cartas e pra:
136 Captulo 18. Capitulo 16: Herana
Aprenda Computao com Python 3.0, Verso 1
class Baralho:
#...
def distribuir(self, maos, nCartas=999):
nMaos = len(maos)
for i in range(nCartas):
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 signica 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 ush.
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 identica 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.
18.4. 16.4 Exibindo a mao 137
Aprenda Computao com Python 3.0, Verso 1
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.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 signica-
tiva, para alm de inicializar atributos.
Para implementar jogos especcos, 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 gura. 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 que 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 que 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 denir
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:
138 Captulo 18. Capitulo 16: Herana
Aprenda Computao com Python 3.0, Verso 1
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 modicada no lao, no queremos us-la para controlar o percurso. Python pode car
bem confuso se estiver percorrendo uma lista que est mudando!
Para cada carta na mo, vericamos qual a carta que faz par com ela e vamos procur-la. O par da carta tem o
mesmo valor (nmero ou gura) 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.6. 16.6 Classe MaoDeMico 139
Aprenda Computao com Python 3.0, Verso 1
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 = []
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 signica que sobrou s uma
carta e o jogo chegou ao m.
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.
140 Captulo 18. Capitulo 16: Herana
Aprenda Computao com Python 3.0, Verso 1
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
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 m 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
18.7. 16.7 Classe Mico 141
Aprenda Computao com Python 3.0, Verso 1
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
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.
142 Captulo 18. Capitulo 16: Herana
Aprenda Computao com Python 3.0, Verso 1
18.8 16.8 Glossrio
herana (inheritance) Habilidade de denir uma nova classe que a verso modicada de uma classe denida ante-
riormente.
classe me (parent class) A classe de quem a classe lha herda.
classe lho (child class) Um nova classe criada herdando de uma classe existente; tambm chamada de subclasse.
18.8. 16.8 Glossrio 143
Aprenda Computao com Python 3.0, Verso 1
144 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 Innitas
17.6 O Teorema da Ambigidade Fundamental
17.7 Modicando 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 denio 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.
145
Aprenda Computao com Python 3.0, Verso 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 denidas 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 car 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 nal da lista. Agora o diagrama de estado se parece com:
146 Captulo 19. Captulo 17: Listas encadeadas
Aprenda Computao com Python 3.0, Verso 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 m:
def imprimeLista(no):
while no:
print (no, end="")
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 reram
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, modique imprimeLista para que ela gere uma sada neste formato.
19.3. 17.3 Listas como Colees 147
Aprenda Computao com Python 3.0, Verso 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 nal, chegar no
caso base. Dada a denio 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, end="")
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 nal 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 Innitas
No h nada que impea um n de referenciar de volta um n anterior na lista, incluindo ele mesmo. Por exemplo,
esta gura mostra uma lista com dois ns, um dos quais refere-se a si mesmo:
148 Captulo 19. Captulo 17: Listas encadeadas
Aprenda Computao com Python 3.0, Verso 1
Se ns invocarmos imprimeLista nesta lista, ele car em lao para sempre. Se ns invocarmos
imprimeDeTrasParaFrente, ele recorrer innitamente. Este tipo de comportamento torna as listas innitas
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 innita para representar uma frao repetente.
Mesmo assim, problemtico que no possamos provar que imprimeLista e imprimeDeTrasParaFrente
terminem. O melhor que podemos fazer a armao 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 emcabeca, pensamos como uma referncia
a um nico n, e quando pensamos emlista 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, end="")
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.
19.6. 17.6 O Teorema da Ambigidade Fundamental 149
Aprenda Computao com Python 3.0, Verso 1
O teorema da ambigidade fundamental descreve a ambigidade que inerente referncia a um n:
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 Modicando Listas
Existem duas maneiras de se modicar uma lista ligada. Obviamente, podemos modicar 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.
150 Captulo 19. Captulo 17: Listas encadeadas
Aprenda Computao com Python 3.0, Verso 1
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
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 ("[", end="")
if lista != None :
cabeca = lista
rabo = lista.proximo
imprimeDeTrasParaFrente(rabo)
print (cabeca, end="")
print ("]", end="")
Novamente, uma boa idia vericar 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 ("[", end="")
if self.cabeca != None :
self.cabeca.imprimeDeTrasParaFrente()
print ("]", end="")
class No:
...
def imprimeDeTrasParaFrente(self):
if self.proximo != None:
19.8. 17.8 Envoltrios e Ajudadores 151
Aprenda Computao com Python 3.0, Verso 1
rabo = self.proximo
rabo.imprimeDeTrasParaFrente()
print (self.carga, end="")
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
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. Especicar invariantes para objetos um prtica de programao til porque torna mais fcil
provar a correo do cdigo, vericar 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
modicar 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 signicativo 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.
152 Captulo 19. Captulo 17: Listas encadeadas
Aprenda Computao com Python 3.0, Verso 1
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.
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 modicado).
19.11. 17.11 Glossrio 153
Aprenda Computao com Python 3.0, Verso 1
154 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-xas
18.6 Anlise sinttica
18.7 Avaliando em ps-xo.
*
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 especicamos 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, especica um conjunto de operaes (ou mtodos) e a semntica das operaes
(o que elas fazem), mas no especica a implementao das operaes. Isto o que o faz abstrato.
Por que isto til?
Simplica a tarefa dde especicar 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 especicar 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.
155
Aprenda Computao com Python 3.0, Verso 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 denido 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 : Verica se a pilha est vazia.
Uma s vezes chamada uma estrutura de dados last in, rst 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 denem 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
dene 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 vericar 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 na 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.
156 Captulo 20. Captulo 18: Pilhas
Aprenda Computao com Python 3.0, Verso 1
20.4 18.4 Empilhando e desempilhando
Uma pilha uma estrutura de dados genrica, o que signica 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-xas
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 inxa. Uma alternativa usada por algumas calculadoras
chamada notao ps-xa. Em notao ps-xa, o operador segue os operandos, como em 1 2 +.
A razo pela qual a notao ps-xa til algumas vezes que existe uma maneira natural de avaliar uma expresso
ps-xa 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 m 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-xa - no necessrio usar parnteses para controlar a
ordem das operaes. Para ter o mesmo resultado em notao inxa, deveramos escrever (1 + 2) * 3.
Como um exerccio, escreva a expresso ps-xa 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 157
Aprenda Computao com Python 3.0, Verso 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 especicar 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-xas.
>>> 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-xo.
Para avaliar uma expresso ps-xa, 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-xa de (56 + 47)
*
2
>>> print (evalPostfix("56 47 + 2
*
"))
206
XXXthats close enough
18.8 Clientes de fornecedores.
158 Captulo 20. Captulo 18: Pilhas
Aprenda Computao com Python 3.0, Verso 1
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 especicao do TAD - e no como ele ser usado.
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
denidopor um conjunto de operaes, que podem ser implementadas de vrias maneiras.
interface (interface): o conjunto de operaes que denem 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): Denio de classe que implementa um TDA com denies de mtodos que so chamadas
a outros mtodos, s vezes com pequenas modicaes. A lmina faz um trabalho insignicante, 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).
inxa (inx): Notao matemtica em que os operadores se situam entre os operandos.
ps-xa (postx): 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 ns 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-xo. 159
Aprenda Computao com Python 3.0, Verso 1
160 Captulo 20. Captulo 18: Pilhas
CAPTULO 21
Captulo 19: Filas
Este captulo apresenta dois TDAs: Fila e Fila por Prioridade. Na nossa vida diria, la um alinhamento de con-
sumidores aguardando algum tipo de servio. Na maioria dos casos, o primeiro da la 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 la. No supermercado, comum na la do caixa algum deixar passar na
frente uma pessoa que chega la s com um ou dois produtos na mo.
A regra que determina quem o prximo da la chama-se poltica de enleiramento. A poltica de enleiramento
mais simples chama-se FIFO, sigla de rst-in-rst-out: primeiro a entrar, primeiro a sair. A poltica de enleiramento
mais geral o enleiramento por prioridade, em que se atribui uma prioridade a cada pessoa da la 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 enleiramento 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 la usa a poltica FIFO; e a la por prioridade (como o prprio nome sugere) usa a poltica de enleiramento
por prioridade.
21.1 19.1 Um TDA Fila
O TDA Fila denido pelas seguintes operaes:
__init__ Inicializar uma nova la vazia.
insert Adicionar um novo item la.
remove Remover e retornar um item da la. O item retornado o que foi adicionado primeiro.
isEmpty Checar se a la est vazia.
21.2 19.2 Fila encadeada
A primeira implementao que vamos ver de um TDA Fila chama-se la encadeada porque feita de objetos Ns
encadeados. A denio da classe a seguinte:
161
Aprenda Computao com Python 3.0, Verso 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 m da lista. Se a la 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 identicar 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 la, e o
ltimo n deve ter seu atributo next igual a None. Estude o mtodo at car 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 signicativa. 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.
162 Captulo 21. Captulo 19: Filas
Aprenda Computao com Python 3.0, Verso 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 modicar a classe Fila, de modo que ela mantenha a referncia tanto ao primeiro quanto ao ltimo n,
como mostra a gura:
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 congurar 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
21.4. 19.4 Fila encadeada aprimorada 163
Aprenda Computao com Python 3.0, Verso 1
if self.length == 0:
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 las 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 la vazia.
insert Adicionar um novo item la.
remove Remover e retornar um item da la. O item retornado aquele que tiver maior prioridade.
isEmpty Checar se a la est vazia.
A diferena semntica que o item removido da la 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 especicado pela
implementao Fila por Prioridade. Isso depende de quais itens esto na la.
Por exemplo, se os itens da la 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 la, 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
la.
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
164 Captulo 21. Captulo 19: Filas
Aprenda Computao com Python 3.0, Verso 1
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.
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 la contmnmeros ou strings simples, eles so removidas emordemnumrica 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 la 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 denio no-usual de prioridade, vamos implementar uma classe chamada
Golfer (golsta), que mantm registro dos nomes e da pontuao de golstas. Como sempre, comeamos denindo
__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, denimos uma verso de __cmp__, ma qual a pontuao mais baixa ca 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 la por prioridade com a classe Golfer:
21.6. 19.6 A classe Golfer 165
Aprenda Computao com Python 3.0, Verso 1
>>> tiger = Golfer("Tiger Woods", 61)
>>> phil = Golfer("Phil Mickelson", 72)
>>> hal = Golfer("Hal Sutton", 69)
>>>
>>> pq = PriorityQueue()
>>> pq.insert(tiger)
>>> pq.insert(phil)
>>> 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
la (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 la.
poltica de enleiramento (queueing policy) As regras que determinam qual membro de uma la o prximo a ser
removido.
FIFO First In, First Out, (primeiro a entrar, primeiro a sair) poltica de enleiramento em que o primeiro membro
a chegar o primeiro a ser removido.
la por prioridade (priority queue) Poltica de enleiramento 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 dene as operaes comuns de acontecerem em uma la por priori-
dade.
la encadeada (linked queue) Implementao de uma la 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.
166 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 m 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:
167
Aprenda Computao com Python 3.0, Verso 1
Figura 1
Para evitar a sobrecarga da gura, 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 gura 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 lhos.
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 lhos/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 denidas 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.
168 Captulo 22. Captulo 20: rvores
Aprenda Computao com Python 3.0, Verso 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 lhos primeiro:
left = Tree(2)
right = Tree(3)
Em seguida crie a clula pai e ligue ela a seus lhos:
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 lhos. Ao nalizar 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 inxa 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 169
Aprenda Computao com Python 3.0, Verso 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, signicando que eles tem exatamente dois operandos.)
Podemos construir rvores assim:
>>> tree = Tree(+, Tree(1), Tree(
*
, Tree(2), Tree(3)))
Examinando a gura, 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
psxa, prexa e inxa. 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
170 Captulo 22. Captulo 20: rvores
Aprenda Computao com Python 3.0, Verso 1
print (tree.cargo, end="")
printTree(tree.left)
printTree(tree.right)
Em outras palavras, para imprimir uma rvore, imprima primeiro o contedo da raiz, em seguida imprima toda a
subrvore esquerda e nalmente imprima toda a subrvore direita. Esta forma de percorrer uma rvore chamada de
prordem, porque o contedo da raiz aparece antes dos contedos dos lhos. 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 psxa quanto da inxa; uma notao chamada de prexa, 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, end="")
O resultado, 1 2 3
*
+, est na notao psxa! 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, end="")
printTreeInorder(tree.right)
O resultado 1 + 2
*
3, que a expresso na notao inxa.
Para sermos justos, devemos lembrar que acabamos de omitir uma complicao importante. algumas vezes quando
escrevemos expresses na notao inxa devemos usar parntesis para prescrever a ordem das operaes. Ou seja, um
percurso em inordem no suciente para gerar a expresso inxa.
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, modique 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 grca 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)
22.4. 20.4 Percurso de rvores 171
Aprenda Computao com Python 3.0, Verso 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 lho 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
+
1
Se Voc deitar a sada acima Voc enxerga uma verso simplicada da gura original.
22.5 20.5 Construindo uma rvore de expresso
Nesta seo analisamos expresses inxas e construmos as rvores de express correspondentes. Por exemplo, para a
expresso (3+7)
*
9 resultar a seguinte rvore:
Figura 3
Note que simplicamos 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 nal 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:
172 Captulo 22. Captulo 20: rvores
Aprenda Computao com Python 3.0, Verso 1
def getToken(tokenList, expected) :
if tokenList[0] == expected :
tokenList[0:1] = [] # remove the token
return 1
else :
return 0
J que tokenList refere a um objeto mutvel, as alteraes feitas aqui so visveis para qualquer outra varivel que
se rera 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)
22.5. 20.5 Construindo uma rvore de expresso 173
Aprenda Computao com Python 3.0, Verso 1
>>> printTreePostorder(tree)
9
O segundo exemplo sugere que ns consideramos um operando unitrio como uma espcie de produto. Esta denio
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 :
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 lho
esquerdo e um produto como lho direito. Este tipo de denio recursiva devia comear a car 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 denio de soma que ligeiramente no
intuitiva. Para ns, uma soma pode ser uma rvore com + na raiz, que tem um produto como lho esquerdo e uma
soma como lho direito. Ou, uma soma pode ser simplesmente um produto.
174 Captulo 22. Captulo 20: rvores
Aprenda Computao com Python 3.0, Verso 1
Se Voc est disposto a brincar com esta denio, 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)
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, modicar
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 nal 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 m 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.
:: class BadExpressionError(Exception): pass
22.6. 20.6 Manipulando erros 175
Aprenda Computao com Python 3.0, Verso 1
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 uma classe 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.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:
176 Captulo 22. Captulo 20: rvores
Aprenda Computao com Python 3.0, Verso 1
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 lho 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.
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 = input(prompt)
22.7. 20.7 A rvore dos animais 177
Aprenda Computao com Python 3.0, Verso 1
prompt = "What question would distinguish a %s from a %s? "
question = 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(input(ques))
return (ans[0:1] == y)
A condio do lao externo 1, que signica 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 lhos so o novo animal e
a carga original.
Uma falha do programa que ao sair ele esquece tudo que lhe foi cuidadosamente ensinado!
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.
lho (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 lhos.
notao prexa (prex 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 lhos de cada clula antes da prpria clula.
178 Captulo 22. Captulo 20: rvores
Aprenda Computao com Python 3.0, Verso 1
in-ordem (inorder) Uma forma de percorrer uma rvore visitando a subrvore esquerda, seguida da raiz e nalmente
da subrvore direita.
22.8. 20.8 Glossrio 179
Aprenda Computao com Python 3.0, Verso 1
180 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 Innito
Recurso Innita
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 cou 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 nal 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 innita eventualmente causa um erro em tempo de execuo iden-
ticado 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.
181
Aprenda Computao com Python 3.0, Verso 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. Verique 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. Certique-se que voc no est utilizando uma palavra reservada de Python para um nome de varivel.
2. Verique a existncia do sinal de dois pontos no nal do cabealho de cada declarao composta, incluindo as
declaraes for, while, if, e def.
3. Verique 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 nal 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. Verique 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 congurado.
182 Captulo 23. Apndice A: Depurao
Aprenda Computao com Python 3.0, Verso 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 signica que ele foi
pego num lao innito ou numa recurso innita.
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 innito.
V para a seo Lao Innito abaixo.
Na maioria das vezes, uma recurso innita 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
Innita 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 Innita.
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 uxo de execuo do seu programa. V para a
seo Fluxo de Execuo abaixo.
Lao Innito
Se voc acha que tem um lao innito e descona de qual seja lao causador do problema, adicione uma declarao
print no nal 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 183
Aprenda Computao com Python 3.0, Verso 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 Innita
Na maioria das vezes, uma recurso innita 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 innita, comece vericando para se assegurar
que exista um caso bsico. Em outras palavras, deve existir alguma condio que faa com que a funo ou mtodo
nalize sem fazer uma chamada recursiva. Se no existe tal condio, voc precisa repensar o algoritmo e identicar
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 uindo, 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 identicam 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 denida.
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, verique sua
denio e conra se o primeiro parmetro chama-se self. Ento verique 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.
184 Captulo 23. Apndice A: Depurao
Aprenda Computao com Python 3.0, Verso 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 cou
bagunada
Um dos problemas com o uso de declaraes print para a depurao que a sada pode car confusa, dicultando a
depurao, ao invs de facilitar. H duas coisas que podem ser feitas: simplicar a sada ou simplicar o programa.
Para simplicar 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 simplicar 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 dicultam 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 congurar 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 185
Aprenda Computao com Python 3.0, Verso 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? Cetique-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
vericando 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 vericar 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.
186 Captulo 23. Apndice A: Depurao
Aprenda Computao com Python 3.0, Verso 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, certique-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 suciente 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?
23.3. A.3 Erros de semntica 187
Aprenda Computao com Python 3.0, Verso 1
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.
Lembre-se, o objetivo no apenas fazer o programa funcionar. O objetivo aprender como fazer o programa fun-
cionar.
188 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 Simplicando 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 ca em cima,
que dividido, e o 6 representa o denominador, o nmero que ca embaixo, pelo qual a diviso feita. A frao 5/6
pode ser lida cinco dividido por seis.
O primeiro passo denir 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:
...
189
Aprenda Computao com Python 3.0, Verso 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, a funo print chama implicitamente o mtodo __str__.
24.1 B.1 Multiplicao de fraes
interessante que nossas fraes possam ser somadas, subtradas, multiplicadas, divididas, etc. Enm, 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 vericar 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
190 Captulo 24. Apndice B: Criando um novo tipo de dado
Aprenda Computao com Python 3.0, Verso 1
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-
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.2. B.2 Soma de fraes 191
Aprenda Computao com Python 3.0, Verso 1
24.3 B.3 Simplicando 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 simplicarmos a frao. Para simplicar 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.
De forma geral, sempre que um objeto do tipo Fracao for criado, a frao deve ser simplicada, 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 denio 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. Ointeressante 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)
192 Captulo 24. Apndice B: Criando um novo tipo de dado
Aprenda Computao com Python 3.0, Verso 1
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,
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, verica 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 nal.
24.4. B.4 Comparando fraes 193
Aprenda Computao com Python 3.0, Verso 1
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.5.1 B.5.1 Exerccio
Como exerccio, nalize 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.
simplicar Transformar uma frao em sua equivalente com o MDC valendo 1
194 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
especicamente 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 grcas (GUI - graphical user interface) permite ao seu programa usar um
ambiente de janelas para interagir com o usurio e exibir contedos grcos (janelas, imagens, etc.) A biblioteca
grca 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 uxo 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.
195
Aprenda Computao com Python 3.0, Verso 1
Banco de dados so como super arquivos, que armazenam dados em esquemas predenidos, 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
(Simplied 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 ocial 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.
196 Captulo 25. Apndice C: Leituras recomendadas
Aprenda Computao com Python 3.0, Verso 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 nos
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 tomograas 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 Scientic American. Ambos os livros representam uma rica fonte de ideias para projetos.
Turtles, Termites and Trafc 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. Simplicando, 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 197
Aprenda Computao com Python 3.0, Verso 1
198 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.
199
Aprenda Computao com Python 3.0, Verso 1
200 Captulo 26. Apndice D: GNU Free Documentation License
CAPTULO 27
Indices and tables
ndice
ndice do Mdulo
Pgina de Pesquisa
201