Escolar Documentos
Profissional Documentos
Cultura Documentos
AprendaComputaocomPython PDF
AprendaComputaocomPython PDF
Documentation
Verso 1.1
12/08/2010
Contedo
Prefcio
1.1 Como e porque eu vim a usar Python .
1.2 Encontrando um livro-texto . . . . . .
1.3 Introduzindo programao com Python
1.4 Construindo uma comunidade . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
3
3
4
4
6
Apresentao
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9
9
11
11
13
14
14
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
17
17
18
19
20
20
21
22
22
23
23
Captulo 3: Funes
5.1 3.1 Chamadas de funes
5.2 3.2 Converso entre tipos
5.3 3.3 Coero entre tipos . .
5.4 3.4 Funes matemticas .
5.5 3.5 Composio . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
25
25
26
26
27
28
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
5.6
5.7
5.8
5.9
5.10
5.11
5.12
5.13
6
ii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
28
29
30
30
31
32
33
33
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
35
35
36
36
37
37
38
38
39
39
40
41
42
42
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
45
45
46
48
49
49
51
51
52
53
Captulo 6: Iterao
8.1 6.1 Reatribuies . . . . . . . . . . . . . . . . . . .
8.2 6.2 O comando while . . . . . . . . . . . . . . . .
8.3 6.3 Tabelas . . . . . . . . . . . . . . . . . . . . . .
8.4 6.4 Tabelas de duas dimenses (ou bi-dimensionais)
8.5 6.5 Encapsulamento e generalizao . . . . . . . . .
8.6 6.6 Mais encapsulamento . . . . . . . . . . . . . .
8.7 6.7 Variveis locais . . . . . . . . . . . . . . . . . .
8.8 6.8 Mais generalizao . . . . . . . . . . . . . . . .
8.9 6.9 Funes . . . . . . . . . . . . . . . . . . . . . .
8.10 6.10 Glossrio . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
55
55
56
57
59
59
60
61
61
63
63
Captulo 7: Strings
9.1 7.1 Um tipo de dado composto . . .
9.2 7.2 Comprimento . . . . . . . . . .
9.3 7.3 Travessia e o loop for . . . . .
9.4 7.4 Fatias de strings . . . . . . . .
9.5 7.5 Comparao de strings . . . . .
9.6 7.6 Strings so imutveis . . . . . .
9.7 7.7 Uma funo find (encontrar)
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
65
65
66
66
67
68
68
69
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
9.8
9.9
9.10
9.11
9.12
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
69
70
70
71
72
10 Captulo 8: Listas
10.1 8.1 Valores da lista . . . . . . . . . . .
10.2 8.2 Acessado elementos . . . . . . . .
10.3 8.3 Comprimento da lista . . . . . . .
10.4 8.4 Membros de uma lista . . . . . . .
10.5 8.5 Listas e laos for . . . . . . . . .
10.6 8.6 Operaes em listas . . . . . . . .
10.7 8.7 Fatiamento de listas . . . . . . . .
10.8 8.8 Listas so mutveis . . . . . . . . .
10.9 8.9 Remoo em lista . . . . . . . . .
10.10 8.10 Ojetos e valores . . . . . . . . . .
10.11 8.11 Apelidos . . . . . . . . . . . . . .
10.12 8.12 Clonando listas . . . . . . . . . .
10.13 8.13 Lista como parmetro . . . . . . .
10.14 8.14 Lista aninhadas . . . . . . . . . .
10.15 8.15 Matrizes . . . . . . . . . . . . . .
10.16 8.16 Strings e listas . . . . . . . . . . .
10.17 8.17 Glossrio . . . . . . . . . . . . .
10.18 Outros termos utilizados neste captulo
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
73
73
74
75
75
76
76
77
77
78
78
79
80
80
81
81
82
83
83
11 Captulo 9: Tuplas
11.1 9.1 Mutabilidade e tuplas . . . . .
11.2 9.2 Atribuies de tupla . . . . . .
11.3 9.3 Tuplas como valores de retorno
11.4 9.4 Nmeros aleatrios . . . . . . .
11.5 9.5 Lista de nmeros aleatrios . .
11.6 9.6 Contando . . . . . . . . . . . .
11.7 9.7 Vrios intervalos . . . . . . . .
11.8 9.8 Uma soluo em um s passo .
11.9 9.9 Glossrio . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
85
85
86
86
87
88
88
89
90
91
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
93
94
94
95
95
96
98
98
99
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
101
101
103
104
105
106
107
108
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
iii
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
109
109
110
111
111
112
113
113
114
115
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
117
117
118
119
120
120
121
121
122
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
123
123
124
125
125
125
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
127
127
127
128
129
130
130
131
132
133
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
135
135
136
136
137
138
138
139
142
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
143
143
144
145
146
146
iv
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
19.6
19.7
19.8
19.9
19.10
19.11
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
147
148
148
149
150
150
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
153
153
154
154
155
155
155
156
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
159
159
159
160
161
162
163
164
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
165
166
167
167
168
170
173
174
176
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
23 Apndice A: Depurao
177
23.1 A.1 Erros de sintaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178
23.2 A.2 Erros de tempo de execuo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 179
23.3 A.3 Erros de semntica . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181
24 Apndice B: Criando um novo tipo de dado
24.1 B.1 Multiplicao de fraes . . . . . . . . . . . . .
24.2 B.2 Soma de fraes . . . . . . . . . . . . . . . . .
24.3 B.3 Simplificando fraes: O algoritmo de Euclides
24.4 B.4 Comparando fraes . . . . . . . . . . . . . . .
24.5 B.5 Indo mais alm... . . . . . . . . . . . . . . . . .
24.6 B.6 Glossrio . . . . . . . . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
185
186
187
187
189
189
190
195
vi
197
Contents:
Contedo
Contedo
CAPTULO 1
Prefcio
Pedi para um dos talentosos estudantes de Yorktown, Matt Ahrens, que experimentasse Python. Em dois meses ele no
s aprendeu a linguagem como tambm escreveu uma aplicao chamada pyTicket que possibilitou nossa equipe
reportar problemas de tecnologia pela Web. Eu sabia que Matt no poderia ter finalizado uma aplicao daquele
porte em perodo to curto em C++, e esta realizao, combinada com a avaliao positiva de Python dada por Matt,
sugeriam que Python era a soluo que eu estava procurando.
Captulo 1. Prefcio
#include <iostream.h>
void main()
{
cout << "Al, mundo." << endl;
}
Mesmo sendo um exemplo trivial, as vantagens do Python saltam aos olhos. O curso de Cincia da Computao I que
ministro em Yorktown no tem pr-requisitos, assim, muitos dos alunos que veem esse exemplo esto olhando para o
seu primeiro programa. Alguns deles esto indubitavelmente nervosos, por j terem ouvido falar que programao de
computadores difcil de aprender. A verso C++ tem sempre me forado a escolher entre duas opes insatisfatrias:
ou explicar os comandos #include, void main(), {, e } e arriscar confundir ou intimidar alguns dos alunos logo
assim que iniciam, ou dizer a eles No se preocupem com todas estas coisas agora; falaremos sobre elas mais tarde,
e correr o mesmo risco. O objetivo educacional neste ponto do curso introduzir os alunos idia de comando em
programao e v-los escrever seu primeiro programa, deste modo introduzindo-os ao ambiente de programao. O
programa em Python tem exatamente o que necessrio para conseguir isto, e nada mais.
Comparar o texto explicativo do programa em cada verso do livro ilustra ainda mais o que significa para o aluno
iniciante. Existem treze pargrafos de explicao do Al, mundo! na verso C++; na verso Python existem apenas
dois. Mais importante, os onze pargrafos perdidos no se ocupam das idias chave da programao de computadores, mas com a mincia da sintaxe C++. Vejo a mesma coisa acontecendo atravs de todo o livro. Pargrafos
inteiros simplesmente desaparecem da verso Python do texto porque a sintaxe muito mais clara de Python os torna
desnecessrios.
Utilizar uma linguagem de to alto nvel como Python, permite ao professor deixar para falar mais tarde sobre os
nveis mais baixos, prximos mquina, quando os alunos j tero a experincia necessria para ver com mais sentido
os detalhes. Desta maneira podemos pedagogicamente por em primeiro lugar as primeiras coisas. Um dos melhores
exemplos disto a maneira com que Python lida com variveis. Em C++ uma varivel um nome para um lugar que
guarda uma coisa. Variveis tm de ser declaradas com seu tipo pelo menos em parte por que o tamanho do lugar a que
se referem precisa ser predeterminado. Assim, a idia de varivel fica amarrada ao hardware da mquina. O conceito
poderoso e fundamental de varivel j bastante difcil para o aluno iniciante (tanto em cincia da computao quanto
em lgebra). Bytes e endereos no ajudam neste caso. Em Python uma varivel um nome que se refere a uma coisa.
Este um conceito muito mais intuitivo para alunos iniciantes e est muito mais prximo do significado de varivel
que eles aprenderam em seus cursos de matemtica. Eu tive muito menos dificuldade em ensinar variveis este ano do
que tive no passado, e gastei menos tempo ajudando aos alunos com problemas no uso delas.
Um outro exemplo de como Python ajuda no ensino e aprendizagem de programao em sua sintaxe para funo.
Meus alunos tm sempre tido grande dificuldade na compreenso de funes. O problema principal gira em torno da
diferena entre a definio de uma funo e a chamada de uma funo, e a distino relacionada entre um parmetro
e um argumento. Python vem em auxlio com uma sintaxe no apenas curta quanto bela. As definies de funo
comeam com def, ento eu simplesmente digo aos meus alunos Quando voc define uma funo, comece com
def, seguido do nome da funo que voc est definindo; quando voc chama uma funo, simplesmente chame-a
digitando o nome dela. Parmetros ficam nas definies; argumentos vo com as chamadas. No existem tipos de
retorno, tipos de parmetro ou passagem de parmetros por valor ou por referncia no meio do caminho, permitindome ensinar funes em menos da metade do tempo que isto me tomava anteriormente, com uma melhor compreenso.
A utilizao do Python tem melhorado a efetividade de nosso programa em cincia da computao para todos os
estudantes. Eu vejo um nvel geral de sucesso muito mais alto e um nvel mais baixo de frustrao do que experimentei
durante os dois anos em que ensinei C++. Eu avano mais rpido com melhores resultados. Mais alunos deixam o
curso com a habilidade de criar programas significativos e com uma atitude positiva em relao a experincia de
programao que isso traz.
Captulo 1. Prefcio
CAPTULO 2
Apresentao
Python ainda toma emprestado certas caractersticas de linguagens de programao funcionais e pode ser usado para
introduzir conceitos cujos detalhes poderiam ser aprofundados em cursos de Scheme e Lisp.
Lendo o prefcio de Jeffrey, fiquei impressionado com seu comentrio de que Python o fez ver um ?maior nvel de
sucesso e um menor nvel de frustrao? o que lhe permitiu ?progredir mais depressa com resultados melhores?.
Embora estes comentrios refiram-se aos seus cursos introdutrios, eu s vezes uso Python exatamente pelas mesmas
razes em cursos avanados de ps-graduao (graduate = pos-graduacao XXX) em cincia da computao na Universidade de Chicago. Nestes cursos, enfrento constantemente a assustadora tarefa de cobrir muitos tpicos difceis
em um rapidssimo trimestre (quarter XXX) de nove semanas. Embora me seja possvel inflingir um bocado de dor e
sofrimento pelo uso de uma linguagem como C++, tenho percebido muitas vezes que este enfoque contraproducente
? especialmente quando o curso sobre um tpico no relacionado apenas com ?programar?. Acho que usar Python
me permite um melhor foco no tpico em questo, enquanto permite que os alunos completem projetos substanciais
em classe.
Embora Python seja ainda uma linguagem jovem e em evoluo, acredito que tem um futuro brilhante em educao.
Este livro um passo importante nessa direo.
David Beazley
Universidade de Chicago
Autor de Python Essencial Reference
Captulo 2. Apresentao
CAPTULO 3
Tpicos
Captulo 1: O caminho do programa
1.1 A linguagem de programao Python
1.2 O que um programa?
1.3 O que depurao (debugging)?
* 1.3.1 Erros de sintaxe
* 1.3.2 Erros em tempo de execuo (runtime errors)
* 1.3.3 Erros de semntica (ou de lgica)
* 1.3.4 Depurao experimental (debugging)
1.4 Linguagens naturais e linguagens formais
1.5 O primeiro programa
1.6 Glossrio
O objetivo deste livro ensinar o leitor a pensar como um cientista da computao. Essa maneira de pensar combina
algumas das melhores caractersticas da matemtica, da engenharia e das cincias naturais. Como os matemticos, os
cientistas da computao usam linguagens formais para representar ideias (especificamente, computaes). Como os
engenheiros, eles projetam coisas, montando sistemas a partir de componentes e avaliando as vantagens e desvantagens de diferentes alternativas. Como os cientistas naturais, eles observam o comportamento de sistemas complexos,
formulam hipteses e testam previses.
A habilidade mais importante de um cientista da computao a soluo de problemas. Soluo de problemas
a habilidade de formular questes, pensar criativamente sobre solues possveis e expressar uma soluo de forma
clara e precisa. Ocorre que aprender a programar uma excelente oportunidade de praticar a habilidade da soluo de
problemas. por isso que este captulo se chama O caminho do programa.
Em certo nvel, voc estar aprendendo a programar, habilidade que til em si mesma. Em outro nvel, voc usar
a programao como um meio para atingir um objetivo. medida que voc for avanando na leitura, esse objetivo
ficar mais claro.
Como voc pode deduzir a partir da expresso linguagem de alto nvel, tambm existem as linguagens de baixo
nvel, s vezes chamadas de linguagens de mquina ou linguagem assembly (linguagens de montagem). De
forma simples, o computador s consegue executar programas escritos em linguagens de baixo nvel. Deste modo,
programas escritos em linguagens de alto nvel precisam ser processados antes que possam rodar. Esse processamento
extra toma algum tempo, o que uma pequena desvantagem em relao s linguagens de alto nvel.
Mas as vantagens so enormes. Primeiro, muito mais fcil programar em uma linguagem de alto nvel. mais
rpido escrever programas em uma linguagem de alto nvel; eles so mais curtos e mais fceis de ler, e h maior
probabilidade de esterem corretos. Segundo, as linguagens de alto nvel so portveis, o que significa que podem
rodar em diferentes tipos de computador, com pouca ou nenhuma modificao. Programas em baixo nvel s podem
rodar em um nico tipo de computador e precisam ser re-escritos para rodar em outro tipo.
Devido a essas vantagens, quase todos os programas so escritos em linguagens de alto nvel. As de baixo nvel so
utilizadas somente para umas poucas aplicaes especializadas.
Dois tipos de programas processam linguagens de alto nvel, traduzindo-as em linguagens de baixo nvel: interpretadores e compiladores. O interpretador l um programa escrito em linguagem de alto nvel e o executa, ou seja, faz o
que o programa diz. Ele processa o programa um pouco de cada vez, alternadamente: hora lendo algumas linhas, hora
executando essas linhas e realizando clculos.
O compilador l o programa e o traduz completamente antes que o programa comece a rodar. Neste caso, o programa
escrito em linguagem de alto nvel chamado de cdigo fonte, e o programa traduzido chamado de cdigo objeto
ou executvel. Uma vez que um programa compilado, voc pode execut-lo repetidamente, sem que precise de nova
traduo.
Python considerada uma linguagem interpretada, pois os programas em Python so executados por um interpretador.
Existem duas maneiras de usar o interpretador: no modo de linha de comando e no modo de script. No modo de linha
de comando, voc digita programas em Python e o interpretador mostra o resultado:
$ python
Python 2.5.2 (r252:60911, Jan 4 2009, 17:40:26)
[GCC 4.3.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> print 1 + 1
2
A primeira linha deste exemplo o comando que inicia o interpretador Python. As trs linhas seguintes so mensagens
do interpretador. A quarta linha comea com >>>, que o sinal usado pelo interpretador para indicar que ele est
pronto. No exemplo anterior, digitamos print 1 + 1 e o interpretador respondeu 2.
Voc tambm pode escrever um programa em um arquivo e usar o interpretador para executar o contedo desse arquivo.
10
Um arquivo como este chamado de script. Por exemplo, usamos um editor de texto para criar um arquivo chamado
leticia.py com o seguinte contedo:
print 1 + 1
Por conveno, arquivos que contenham programas em Python tm nomes que terminam com .py.
Para executar o programa, temos de dizer ao interpretador o nome do script:
$ python leticia.py
2
Em outros ambientes de desenvolvimento, os detalhes da execuo de programas podem ser diferentes. Alm disso, a
maioria dos programas so mais interessantes do que esse.
A maioria dos exemplos neste livro so executados a partir da linha de comando. Trabalhar com a linha de comando
conveniente no desenvolvimento e testagem de programas, porque voc pode digitar os programas e execut-los
imediatamente. Uma vez que voc tem um programa que funciona, deve guard-lo em um script, de forma a poder
execut-lo ou modific-lo no futuro.
11
12
Por exemplo, o Linux um sistema operacional que contm milhares de linhas de cdigo, mas comeou como um
programa simples, que Linus Torvalds usou para explorar o chip Intel 80386. De acordo com Larry Greenfield, Um
dos primeiros projetos de Linus Torvalds foi um programa que deveria alternar entre imprimir AAAA e BBBB. Isso
depois evoluiu at o Linux. (The Linux Users Guide Verso Beta 1)
Captulos posteriores faro mais sugestes sobre depurao e outras prticas de programao.
13
literalidade: As linguagens naturais esto cheias de expresses idiomticas e metforas. Se eu digo Caiu a ficha,
possvel que no exista ficha nenhuma, nem nada que tenha cado. Nas linguagens formais, no h sentido
ambguo.
Pessoas que crescem falando uma linguagem natural, ou seja, todo mundo, muitas vezes tm dificuldade de se acostumar com uma linguagem formal. De certa maneira, a diferena entre linguagens formais e naturais como a diferena
entre poesia e prosa, porm mais acentuada:
poesia: As palavras so usadas pela sua sonoridade, alm de seus sentidos, e o poema como um todo cria um efeito
ou uma reao emocional. A ambiguidade no apenas frequente, mas na maioria das vezes, proposital.
prosa: O sentido literal das palavras mais importante, e a estrutura contribui mais para o significado. A prosa mais
fcil de analisar do que a poesia, mas ainda , muitas vezes, ambgua.
programas: O significado de um programa de computador exato e literal, e pode ser inteiramente entendido pela
anlise de seus smbolos e de sua estrutura.
Aqui vo algumas sugestes para a leitura de programas (e de outras linguagens formais). Primeiro, lembre-se de que
linguagens formais so muito mais densas do que linguagens naturais, por isso, mais demorado l-las. A estrutura
tambm muito importante, logo, geralmente no uma boa ideia ler de cima para baixo, da esquerda para a direita.
Em vez disso, aprenda a analisar o programa na sua cabea, identificando os smbolos e interpretando a estrutura.
Finalmente, os detalhes so importantes. Pequenas coisas, como erros ortogrficos e m pontuao, com as quais voc
pode se safar nas linguagens naturais, podem fazer uma grande diferena em uma linguagem formal.
Isso um exemplo de um comando print, que, na realidade, no imprime nada em papel. Ele apresenta o valor na
tela. Neste caso, o resultado so as palavras:
Al, Mundo!
As aspas no programa marcam o comeo e o fim do valor, elas no aparecem no resultado final.
Algumas pessoas julgam a qualidade de uma linguagem de programao pela simplicidade do programa Al,
Mundo!. Por esse padro, Python se sai to bem quanto possvel.
14
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 pretendia o programador.
erro de sintaxe (syntax error) Erro em um programa, que torna impossvel a anlise sinttica (logo, tambm impossvel a interpretao).
erro em tempo de execuo (runtime error) Erro que no ocorre at que o programa seja executado, mas que impede
que o programa continue.
exceo (exception) Um outro nome para um erro em tempo de execuo ou erro de runtime.
executvel (executable) Um outro nome para cdigo objeto que est pronto para ser executado.
interpretar (interpret) Executar um programa escrito em uma linguagem de alto nvel, traduzindo-o uma linha de
cada vez.
linguagem de alto nvel (high-level language) Uma linguagem de programao como Python: projetada para ser
fcil para os seres humanos utilizarem.
linguagem de baixo nvel (low-level language) Uma linguagem de programao que concebida para ser fcil para
um computador, tal como a linguagem de mquina ou a linguagem montagem (assembly language)
linguagem formal (formal language) Qualquer linguagem desenvolvida pelas pessoas para propsitos especficos,
tais como, a representao de ideias matemticas ou programas de computadores; todas as linguagens de programao so linguagens formais.
linguagem natural (natural language) Qualquer lngua falada pelos seres humanos que tenha evoludo naturalmente.
portabilidade (portability) Propriedade que um programa tem de rodar em mais de um tipo de computador.
programa (program) Conjunto de instrues que especifica uma computao.
script Um programa guardado em um arquivo (normalmente um que ser interpretado).
semntica (semantics) O significado de um programa.
smbolo (token) Um elemento bsico da estrutura sinttica de um programa, anlogo a uma palavra em uma linguagem 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.
15
16
CAPTULO 4
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
Se voc estiver em dvida sobre qual o tipo de um determinado valor, o interpretador pode revelar:
>>> type("Al, Mundo!")
<type string>
17
>>> type(17)
<type int>
Nenhuma surpresa: strings pertencem ao tipo string e inteiros pertencem ao tipo int. Menos obviamente, nmeros
com um ponto decimal pertencem a um tipo chamado float, porque estes nmeros so representados em um formato
chamado ponto flutuante 1 :
>>> type(3.2)
<type float>
O que dizer de valores como "17" e "3.2"? Eles parecem nmeros, mas esto entre aspas, como strings:
>>> type("17")
<type string>
>>> type("3.2")
<type string>
Eles so strings.
Ao digitar um nmero grande, tentador usar pontos entre grupos de trs dgitos, assim: 1.000.000. Isso no funciona
por que Python usa o ponto como separador decimal. Usar a vrgula, como se faz em ingls, resulta numa expresso
vlida, mas no no nmero que queramos representar:
>>> print 1,000,000
1 0 0
No nada do que se esperava! Python interpreta 1,000,000 como uma tupla, algo que veremos no Captulo 9. Por
hora, lembre-se apenas de no colocar vrgulas nos nmeros.
Este exemplo faz trs atribuies. A primeira atribui a string "E a, Doutor?" a uma nova varivel chamada
mensagem. A segunda d o valor inteiro 17 a n, e a terceira atribui o nmero de ponto flutuante 3.14159 varivel
chamada pi.
Uma maneira comum de representar variveis no papel escrever o nome delas com uma seta apontando para o
valor da varivel. Esse tipo de figura chamado de diagrama de estado porque mostra em que estado cada varivel
est (pense nisso como o estado de esprito da varivel). O diagrama a seguir mostra o resultado das instrues de
atribuio:
1
18
N.T.: Observe o uso de ponto no lugar da vrgula para separar a parte inteira da parte fracionria.
Em cada um dos casos, o resultado o valor da varivel. Variveis tambm tm tipo. Novamente, podemos perguntar
ao interpretador quais so eles:
>>> type(mensagem)
<type string>
>>> type(n)
<type int>
>>> type(pi)
<type float>
76trombones invlida por no comear com uma letra. muito$ invlida por conter um caractere ilegal, o
cifro. Mas o que est errado com class?
19
Ocorre que class uma das palavras reservadas em Python. Palavras reservadas definem as regras e a estrutura da
linguagem e no podem ser usadas como nomes de variveis.
Python tem 29 palavras reservadas:
and
assert
break
class
continue
def
del
elif
else
except
exec
finally
for
from
global
if
import
in
is
lambda
not
or
pass
print
raise
return
try
while
yield
Pode ser til ter essa lista mo 2 . Se o interpretador acusar erro sobre um de seus nomes de varivel e voc no
souber o porqu, veja se o nome est na lista.
produz a sada:
1
2
Embora expresses contenham valores, variveis e operadores, nem toda expresso contm todos estes elementos. Um
valor por si s considerado uma expresso, do mesmo modo que uma varivel:
>>> 17
17
>>> x
2
2 N.T.: esta lista pode ser obtida atravs do prprio interpretador Python, com apenas dois comandos: import keyword; print
keyword.kwlist
20
Quando Python exibe o valor de uma expresso, usa o mesmo formato que voc usaria para entrar com o valor. No
caso de strings, isso significa que as aspas so includas 3 . Mas o comando print imprime o valor da expresso, que,
neste caso, o contedo da string.
Num script, uma expresso sozinha um comando vlido, porm sem efeito. O script:
17
3.2
"Al, Mundo!"
1 + 1
no produz qualquer sada. Como voc mudaria o script para exibir os valores destas quatro expresses?
hora-1
hora*60+minuto
minuto/60
5**2
(5+9)*(15-7)
Em Python, os smbolos +, -, / e o uso de parnteses para agrupamento tm o mesmo significado que em matemtica.
O asterisco (*) o smbolo para multiplicao e ** o smbolo para potenciao.
Quando um nome de varivel aparece no lugar de um operando, ele substitudo pelo valor da varivel, antes da
operao ser executada.
Adio, subtrao, multiplicao e potenciao fazem o que se espera, mas voc pode ficar surpreso com a diviso. A
operao seguinte tem um resultado inesperado:
>>> minuto = 59
>>> minuto/60
0
O valor de minuto 59 e, em aritmtica convencional, 59 dividido por 60 0,98333, no 0. A razo para a discrepncia
que Python est realizando uma diviso inteira.
Quando ambos os operandos so inteiros, o resultado tem de ser tambm um inteiro e, por conveno, a diviso inteira
sempre arredonda para baixo, mesmo em casos como este, em que o inteiro seguinte est muito prximo:
>>> minuto*100/60
98
De novo, o resultado arredondado para baixo, mas agora pelo menos a resposta aproximadamente correta. A
alternativa usar a diviso em ponto flutuante, o que veremos no captulo 3.
3
21
Interessante o operador +, que funciona com strings, embora ele no faa exatamente o que voc poderia esperar.
Para strings, o operador + representa concatenao, que significa juntar os dois operandos ligando-os pelos extremos.
Por exemplo:
fruta = "banana"
assada = " com canela"
print fruta + assada
A sada deste programa banana com canela. O espao antes da palavra com parte da string e necessrio
para produzir o espao entre as strings concatenadas.
O operador * tambm funciona com strings; ele realiza repetio.
Por exemplo, "Legal"*3
"LegalLegaLegal". Um dos operadores tem que ser uma string; o outro tem que ser um inteiro.
Por um lado, esta interpretao de + e * faz sentido pela analogia entre adio e multiplicao. Assim como 4*3
equivale a 4+4+4, no de estranhar que "Legal"*3 seja o mesmo que "Legal"+"Legal"+"Legal". Por
outro lado, uma diferena significativa separa concatenao e repetio de adio e multiplicao. Voc saberia mencionar uma propriedade da adio e da multiplicao que no ocorre na concatenao e na repetio?
22
Na realidade, a soma tem que acontecer antes da impresso, assim, as aes no esto na realidade acontecendo ao
mesmo tempo. O ponto que qualquer expresso envolvendo nmeros, strings, e variveis pode ser usada dentro de
um comando print. Voc j tinha visto um exemplo disto:
print "Nmero de minutos desde a meia-noite: ", hora*60+minuto
Esta possibilidade pode no parecer muito impressionante agora, mas voc ver outros exemplos em que a composio
torna possvel expressar clculos e tarefas complexas de modo limpo e conciso.
Ateno: Existem limites quanto ao lugar onde voc pode usar certos tipos de expresso. Por exemplo, o lado esquerdo
de um comando de atribuio tem que ser um nome de varivel, e no uma expresso. Assim, o seguinte no vlido:
minuto+1 = hora.
23
regras de precedncia (rules of precedence) O conjunto de regras que governa a ordem em que expresses envolvendo mltiplos operadores e operandos so avaliadas.
tipo (type) Um conjunto de valores. O tipo de um valor determina como ele pode ser usado em expresses. At agora,
os tipos vistos so: inteiros (tipo int), nmeros em ponto-flutuante (tipo float) e strings (tipo string).
valor (value) Um nmero ou string (ou outra coisa que ainda vamos conhecer) que pode ser atribuda a uma varivel
ou computada em uma expresso.
varivel (variable) Nome que se refere a um valor.
24
CAPTULO 5
Captulo 3: Funes
Tpicos
Captulo 3: Funes
3.1 Chamadas de funes
3.2 Converso entre tipos
3.3 Coero entre tipos
3.4 Funes matemticas
3.5 Composio
3.6 Adicionando novas funes
3.7 Definies e uso
3.8 Fluxo de execuo
3.9 Parmetros e argumentos
3.10 Variveis e parmetros so locais
3.11 Diagramas da pilha
3.12 Funes com resultados
3.13 Glossrio
O nome da funo type e ela exibe o tipo de um valor ou varivel. O valor ou varivel, que chamado de
argumento da funo, tem que vir entre parnteses. comum se dizer que uma funo recebe um valor ou mais
valores e retorna um resultado. O resultado chamado de valor de retorno.
Em vez de imprimir um valor de retorno, podemos atribui-lo a uma varivel:
>>> bia = type(32)
>>> print bia
<type str>
25
Como outro exemplo, a funo id recebe um valor ou uma varivel e retorna um inteiro, que atua como um identificador nico para aquele valor:
>>> id(3)
134882108
>>> bia = 3
>>> bia(beth)
134882108
Todo valor tem um id, que um nmero nico relacionado ao local onde ele est guardado na memria do computador.
O id de uma varivel o id do valor a qual ela se refere.
int tambm pode converter valores em ponto flutuante para inteiro, mas lembre que isso trunca a parte fracionria:
>>> int(3.99999)
3
>>> int(-2.3)
-2
Pode parecer curioso que Python faa distino entre o valor inteiro 1 e o valor em ponto flutuante 1.0. Eles podem
representar o mesmo nmero, mas pertencem a tipos diferentes. A razo que eles so representados de modo
diferente dentro do computador.
26
>>> 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
Para chamar uma das funes, temos que especificar o nome do mdulo e o nome da funo, separados por um ponto.
Esse formato chamado de notao de ponto:
>>> decibel = math.log10(17.0)
>>> angulo = 1.5
>>> altura = math.sin(angulo)
A primeira instruo atribui a decibel o logaritmo de 17 na base 10. Existe tambm uma funo chamada log,
usada para calcular o logaritmo em outra base ou o logaritmo natural de um nmero (base e).
A terceira instruo encontra o seno do valor da varivel angulo. sin e as outras funes trigonomtricas (cos,
tan, etc.) recebem argumentos em radianos. Para converter de graus em radianos, divida por 360 e multiplique por
2*pi. Por exemplo, para encontrar o seno de 45 graus, primeiro calcule o ngulo em radianos e depois ache o seno:
>>> graus = 45
>>> angulo = graus * 2 * math.pi / 360.0
>>> math.sin(angulo)
0.707106781187
A constante pi tambm parte do mdulo math. Se voc sabe geometria, pode checar o resultado anterior
comparando-o com a raiz quadrada de dois dividido por dois:
>>> math.sqrt(2) / 2.0
0.707106781187
27
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.
Voc pode usar o nome que quiser para as funes que criar, exceto as palavras reservadas do Python. A lista de
parmetros especifica que informao, se houver alguma, voc tem que fornecer para poder usar a nova funo.
Uma funo pode ter quantos comandos forem necessrios, mas eles precisam ser endentados a partir da margem
esquerda. Nos exemplos deste livro, usaremos uma endentao de dois espaos.
As primeiras funes que vamos mostrar no tero parmetros, ento, a sintaxe ter esta aparncia:
def novaLinha():
print
Esta funo chamada de novaLinha. Os parnteses vazios indicam que ela no tem parmetros. Contm apenas
um nico comando, que gera como sada um caractere de nova linha (isso o que acontece quando voc usa um
comando print sem qualquer argumento).
A sintaxe para a chamada desta nova funo a mesma sintaxe para as funes nativas:
print Primeira Linha.
novaLinha()
print Segunda Linha.
28
Primeira Linha.
Segunda Linha.
Observe o espao extra entre as duas linhas. E se quisssemos mais espao entre as linhas? Poderamos chamar a
mesma funo repetidamente:
print Primeira Linha.
novaLinha()
novaLinha()
novaLinha()
print Segunda Linha.
Ou poderamos escrever uma nova funo chamada tresLinhas, que produzisse trs novas linhas:
def tresLinhas() :
novaLinha()
novaLinha()
novaLinha()
print Primeira Linha.
tresLinhas()
print Segunda Linha.
Esta funo contm trs comandos, todos com recuo de dois espaos a partir da margem esquerda. J que o prximo
comando no est endentado, Python reconhece que ele no faz parte da funo.
Algumas coisas que devem ser observadas sobre este programa:
1. Voc pode chamar o mesmo procedimento repetidamente. Isso muito comum, alm de til.
2. Voc pode ter uma funo chamando outra funo; neste caso tresLinhas chama novaLinha.
Pode no estar claro, at agora, de que vale o esforo de criar novas funes - existem vrias razes, mas este exemplo
demonstra duas delas:
Criar uma nova funo permite que voc coloque nome em um grupo de comandos. As funes podem simplificar 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?
29
tresLinhas()
print Segunda Linha.
Esse programa contm duas definies de funes: novaLinha e tresLinhas. Definies de funes so executadas como quaisquer outros comandos, mas o efeito criar a nova funo. Os comandos dentro da definio da
funo no so executados at que a funo seja chamada, logo, a definio da funo no gera nenhuma sada.
Como voc j deve ter imaginado, preciso criar uma funo antes de poder execut-la. Em outras palavras, a definio
da funo tem que ser executada antes que ela seja chamada pela primeira vez.
Como exerccio, mova as ltimas trs linhas deste programa para o topo, de modo que a chamada da
funo aparea antes das definies. Rode o programa e veja que mensagem de erro voc ter.
Tambm a ttulo de exerccio, comece com a verso que funciona do programa e mova a definio de
novaLinha para depois da definio de tresLinhas. O que acontece quando voc roda este programa?
30
Esta funo recebe um nico argumento e o atribui a um parmetro chamado bruno. O valor do parmetro (a essa
altura, no sabemos qual ser) impresso duas vezes, seguido de uma nova linha. Estamos usando bruno para
mostrar que o nome do parmetro deciso sua, mas claro que melhor escolher um nome que seja mais ilustrativo.
A funo imprimeDobrado funciona para qualquer tipo que possa ser impresso:
>>> imprimeDobrado(Spam)
Spam Spam
>>> imprimeDobrado(5)
5 5
>>> imprimeDobrado(3.14159)
3.14159 3.14159
Na primeira chamada da funo, o argumento uma string. Na segunda, um inteiro. Na terceira um float.
As mesmas regras de composio que se aplicam a funes nativas tambm se aplicam s funes definidas pelo
usurio, assim, podemos usar qualquer tipo de expresso como um argumento para imprimeDobrado:
>>> imprimeDobrado(Spam*4)
SpamSpamSpamSpam SpamSpamSpamSpam
>>> imprimeDobrado(math.cos(math.pi))
-1.0 -1.0
Como acontece normalmente, a expresso avaliada antes da execuo da funo, assim imprimeDobrado imprime
SpamSpamSpamSpam SpamSpamSpamSpam em vez de Spam*4 Spam*4.
Como exerccio, escreva um chamada a imprimeDobrado que imprima Spam*4 Spam*4.
Dica: strings podem ser colocadas tanto entre aspas simples quanto duplas e o tipo de aspas que no
for usado para envolver a string pode ser usado dentro da string, como parte dela.
Tambm podemos usar uma varivel como argumento:
>>> miguel = Eric, the half a bee.
>>> imprimeDobrado(miguel)
Eric, the half a bee. Eric, the half a bee.
N.T.: Eric, the half a bee uma msica do grupo humorstico britnico Monty Python. A linguagem Python foi
batizada em homenagem ao grupo e, por isso, os programadores gostam de citar piadas deles em seus exemplos.
Repare numa coisa importante: o nome da varivel que passamos como um argumento (miguel) no tem nada a ver
com o nome do parmetro (bruno). No importa de que modo o valor foi chamado de onde veio (do chamador);
aqui, em imprimeDobrado, chamamos a todo mundo de bruno.
Esta funo recebe dois argumentos, concatena-os, e ento imprime o resultado duas vezes. Podemos chamar a funo
com duas strings:
>>>
>>>
>>>
Pie
31
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.
A ordem da pilha mostra o fluxo de execuo. imprimeDobrado foi chamado por concatDupla, e
concatDupla foi chamado por __main__ (principal), que um nome especial para a funo mais no topo. Quando
voc cria uma varivel fora de qualquer funo, ela pertence __main__.
Cada parmetro se refere ao mesmo valor que o seu argumento correspondente. Assim, parte1 tem o mesmo valor
de canto1, parte2 tem o mesmo valor de canto2 e bruno tem o mesmo valor de concat.
Se um erro acontece durante uma chamada de funo, Python imprime o nome da funo, e o nome da funo que a
chamou, e o nome da funo que chamou a que chamou, percorrendo todo o caminho de volta a __main__.
Por exemplo, se tentssemos acessar concat de dentro de imprimeDobrado, teramos um NameError:
Traceback (innermost last):
File "teste.py", line 13, in __main__
concatDupla(canto1, canto2)
File "teste.py", line 5, in concatDupla
imprimeDobrado(concat)
File "teste.py", line 9, in imprimeDobrado
32
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.
33
notao de ponto (dot notation) A sintaxe para chamar uma funo que est em outro mdulo, especificando o nome
do mdulo, seguido por um ponto (.) e o nome da funo.
parmetro (parameter) Nome usado numa funo para referir-se a um valor passado como argumento.
traceback Lista de funes que esto em execuo, impressa quando um erro de execuo ocorre.
valor de retorno (return value) O resultado da funo. Se uma chamada de funo usada como expresso, o valor
de retorno o valor da expresso.
varivel local (local variable) Varivel definida dentro da funo. Uma varivel local s pode ser usada dentro da
funo onde foi definida.
34
CAPTULO 6
Captulo 4: Condicionais e
recursividade
Tpicos
Captulo 4: Condicionais e recursividade
4.1 O operador mdulo
4.2 Expresses booleanas
4.3 Operadores lgicos
4.4 Execuo condicional
4.5 Execuo alternativa
4.6 Condicionais encadeados
4.7 Condicionais aninhados
4.8 A instruo return
4.9 Recursividade
4.10 Diagramas de pilha para funes recursivas
4.11 Recursividade infinita
4.12 Entrada pelo teclado
4.13 Glossrio
quociente = 7 / 3
print quociente
resto = 7 % 3
print resto
35
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.
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
x
x
x
x
!= y
> y
< y
>= y
<= y
#
#
#
#
#
x
x
x
x
x
diferente de y
maior que y
menor que y
maior ou igual a y
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 =>.
x = 5
x and 1
y = 0
y and 1
Em geral, esse tipo de coisa no considerado de bom estilo. Se voc precisa comparar um valor com zero, deve
faz-lo explicitamente.
36
A expresso booleana depois da instruo if chamada de condio. Se ela verdadeira (true), ento a instruo
endentada executada. Se no, nada acontece.
Assim como outras instrues compostas, a instruo if constituda de um cabealho e de um bloco de instrues:
CABECALHO:
PRIMEIRO COMANDO
...
ULTIMO COMANDO
O cabealho comea com uma nova linha e termina com dois pontos (:). Os comandos ou instrues endentados que
seguem so chamados de bloco. A primeira instruo no endentada marca o fim do bloco. Um bloco de comandos
dentro de um comando composto ou instruo composta chamado de corpo do comando.
No existe limite para o nmero de instrues que podem aparecer no corpo de uma instruo if, mas tem que haver
pelo menos uma. Ocasionalmente, til ter um corpo sem nenhuma instruo (usualmente, como um delimitador de
espao para cdigo que voc ainda no escreveu). Nesse caso, voc pode usar o comando pass, que indica ao Python:
passe por aqui sem fazer nada.
Se o resto da diviso de x por 2 for 0, ento sabemos que x par, e o programa exibe a mensagem para esta condio.
Se a condio falsa, o segundo grupo de instrues executado. Desde que a condio deva ser verdadeira (True) ou
falsa (False), precisamente uma das alternativas vai ser executada. As alternativas so chamadas ramos (branches),
porque existem ramificaes no fluxo de execuo.
Por final, se voc precisa checar a paridade de nmeros com frequncia, pode colocar este cdigo dentro de uma
funo:
def imprimeParidade(x):
if x % 2 == 0:
print x, " par"
else:
print x, " impar"
Para qualquer valor de x, imprimeParidade exibe uma mensagem apropriada. Quando voc a chama, pode
fornecer uma expresso de resultado inteiro como um argumento:
>>> imprimeParidade(17)
>>> imprimeParidade(y+1)
37
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).
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 rapidamente. Em geral, uma boa ideia evitar o aninhamento quando for possvel.
Operadores lgicos frequentemente fornecem uma maneira de simplificar instrues condicionais aninhadas. Por
exemplo, podemos reescrever o cdigo a seguir usando uma nica condicional:
if 0 < x:
if x < 10:
print "x um nmero positivo de um s algarismo."
38
A instruo print executada somente se a fizermos passar por ambos os condicionais, ento, podemos usar um
operador and:
if 0 < x and x < 10:
print "x um nmero positivo de um s algarismo."
Esses tipos de condies so comuns, assim, Python prov uma sintaxe alternativa que similar notao matemtica:
if 0 < x < 10:
print "x um nmero positivo de um s algarismo."
A funo imprimeLogaritmo recebe um parmetro de nome x. A primeira coisa que ela faz checar se x menor
ou igual a 0, neste caso ela exibe uma mensagem de erro e ento usa return para sair da funo. O fluxo de execuo
imediatamente retorna ao ponto chamador, quer dizer, de onde a funo foi chamada, e as linhas restantes da funo
no so executadas.
Lembre-se que para usar uma funo do mdulo de matemtica, math, voc tem de import-lo.
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)
39
A execuo de contagemRegressiva comea com n=3, e desde que n no 0, produz como sada o valor 3, e
ento chama a si mesma...
A execuo de contagemRegressiva comea com n=2, e desde que n no 0, produz como sada o valor 2, e
ento chama a si mesma...
A execuo de contagemRegressiva comea com n=1, e desde que n no 0, produz como sada o valor 1, e
ento chama a si mesma...
A execuo de contagemRegressiva comea com n=0, e desde que n 0, produz como sada a palavra Fogo!
e ento retorna.
A contagemRegressiva que tem n=1 retorna.
A contagemRegressiva que tem n=2 retorna.
A contagemRegressiva que tem n=3 retorna.
E ento estamos de volta em __main__ (que viagem!). Assim, a sada completa se parece com:
3
2
1
Fogo!
Como um segundo exemplo, d uma olhada novamente nas funes novaLinha e tresLinhas:
def novaLinha():
print
def tresLinhas():
novaLinha()
novaLinha()
novaLinha()
Muito embora isso funcione, no seria muito til se precisssemos gerar como sada 2 novas linhas, ou 106. Uma
alternativa melhor seria esta:
def nLinhas(n):
if n > 0:
print
nLinhas(n-1)
Esse programa similar a contagemRegressiva. Sempre que n for maior que 0, ele gera como sada uma nova
linha e ento chama a si mesmo para gerar como sada n-1 linhas adicionais. Deste modo, o nmero total de novas
linhas 1 + (n-1) que, se voc estudou lgebra direitinho, vem a ser o prprio n.
O processo de uma funo chamando a si mesma chamado de recursividade, e tais funes so ditas recursivas.
40
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.
Na maioria dos ambientes de programao, um programa com recursividade infinita na verdade no roda para sempre.
Python reporta uma mensagem de erro quando a profundidade mxima de recursividade alcanada:
File "<stdin>", line 2, in recursiva
(98 repetitions omitted)
File "<stdin>", line 2, in recursiva
RuntimeError: Maximum recursion depth exceeded
Este traceback um pouco maior do que aquele que vimos no captulo anterior. Quando o erro ocorre, existem 100
quadros recursiva na pilha!
Como exerccio, escreva uma funo com recursividade infinita e rode-a no interpretador Python.
41
Antes de chamar raw_input, uma boa ideia exibir uma mensagem dizendo ao usurio o que ele deve entrar. Esta
mensagem uma como se fosse uma pergunta (prompt). Esta pergunta pode ser enviada como um argumento para
raw_input:
>>> nome = raw_input("Qual... o seu nome? ")
Qual... o seu nome? Arthur, Rei dos Bretes!
>>> print nome
Arthur, Rei dos Bretes!
Se o usurio digita uma string de nmeros, ela convertida para um inteiro e atribuda a velocidade. Infelizmente,
se o usurio digitar um caractere que no seja um nmero, o programa trava:
>>> velocidade = input(pergunta)
Qual... a velocidade de vo de uma andorinha?
De qual voc fala, uma andorinha Africana ou uma Europeia?
SyntaxError: invalid syntax
Para evitar esse tipo de erro, geralmente bom usar raw_input para pegar uma string e, ento, usar funes de
converso para converter para outros tipos.
42
43
44
CAPTULO 7
Tpicos
Captulo 5: Funes frutferas
5.1 Valores de retorno
5.2 Desenvolvimento de programas
5.3 Composio
5.4 Funes booleanas
5.5 Mais recursividade
5.6 Voto de confiana (Leap of faith)
5.7 Mais um exemplo
5.8 Checagem de tipos
5.9 Glossrio
45
J vimos a instruo return antes, mas em uma funo frutfera a instruo return inclui um valor de retorno.
Esta instruo significa: Retorne imediatamente desta funo e use a expresso em seguida como um valor de retorno. A expresso fornecida pode ser arbitrariamente complicada, de modo que poderamos ter escrito esta funo
de maneira mais concisa:
def area(raio):
return math.pi * raio**2
Por outro lado, variveis temporrias como temp muitas vezes tornam a depurao mais fcil.
s vezes til ter mltiplos comandos return, um em cada ramo de uma condicional:
def valorAbsoluto(x):
if x < 0:
return -x
else:
return x
J que estes comandos return esto em ramos alternativos da condicional, apenas um ser executado. To logo um
seja executado, a funo termina sem executar qualquer instruo ou comando subsequente.
O cdigo que aparece depois de uma instruo return, ou em qualquer outro lugar que o fluxo de execuo jamais
alcance, chamado cdigo morto (dead code).
Em uma funo frutfera, uma boa ideia assegurar que todo caminho possvel dentro do programa encontre uma
instruo return. Por exemplo:
def valorAbsoluto(x):
if x < 0:
return -x
elif x > 0:
return x
Este programa no est correto porque se x for 0, nenhuma das condies ser verdadeira, e a funo terminar sem
encontrar um comando return. Neste caso, o valor de retorno ser um valor especial chamado None:
>>> print valorAbsoluto(0)
None
Como exerccio, escreva uma funo compare que retorne 1 se x > y, 0 se x == y e -1 se x < y.
(5.1)
Neste caso, os dois pontos so as entradas, os quais podemos representar usando quatro parmetros. O valor de retorno
a distncia, que um valor em ponto flutuante.
J podemos escrever um esboo da funo:
def distancia(x1, y1, x2, y2):
return 0.0
Obviamente, esta verso da funo no calcula distncias; ela sempre retorna zero. Mas ela est sintaticamente correta,
e vai rodar, o que significa que podemos test-la antes de torn-la mais complicada.
Para testar a nova funo, vamos cham-la com valores hipotticos:
>>> distancia(1, 2, 4, 6)
0.0
Escolhemos estes valores de modo que a distncia horizontal seja igual a 3 e a distncia vertical seja igual a 4; deste
modo, o resultado 5 (a hipotenusa de um tringulo 3-4-5). Quando testamos uma funo, til sabermos qual o
resultado correto.
Neste ponto, j confirmamos que a funo est sintaticamente correta, e podemos comear a adicionar linhas de cdigo.
Depois de cada mudana adicionada, testamos a funo de novo. Se um erro ocorre em qualquer ponto, sabemos aonde
ele deve estar: nas linhas adicionadas mais recentemente.
Um primeiro passo lgico nesta operao encontrar as diferenas x2 - x1 e y2 - y1. Ns iremos guardar estes valores
em variveis temporrias chamadas dx e dy e imprimi-las:
def distancia(x1, y1, x2, y2):
dx = x2 - x1
dy = y2 - y1
print "dx vale", dx
print "dy vale", dy
return 0.0
Se a funo estiver funcionando, as sadas devero ser 3 e 4. Se assim, sabemos que a funo est recebendo os
parmetros corretos e realizando o primeiro clculo corretamente. Se no, existem poucas linhas para checar.
Em seguida, calcularemos a soma dos quadrados de dx e dy:
def distancia(x1, y1, x2, y2):
dx = x2 - x1
dy = y2 - y1
dquadrado = dx**2 + dy**2
print "dquadrado vale: ", dquadrado
return 0.0
Note que removemos os comandos print que havamos escrito no passo anterior. Cdigo como este ajuda a escrever
o programa, mas no parte do produto final (em ingls usado o termo scaffolding).
De novo, ns vamos rodar o programa neste estgio e checar a sada (que deveria ser 25).
Finalmente, se ns tnhamos importado o mdulo matemtico math, podemos usar a funo sqrt para computar e
retornar o resultado:
def distancia(x1, x2, y1, y2):
dx = x2 - x1
dy = y2 - y1
dquadrado = dx**2 + dy**2
resultado = math.sqrt(dquadrado)
return resultado
Se isto funcionar corretamente, voc conseguiu. Caso contrrio, talvez fosse preciso imprimir (exibir) o valor de
resultado antes da instruo return.
7.2. 5.2 Desenvolvimento de programas
47
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 processo, 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.
Chamamos esta funo de area2 para distinguir da funo area, definida anteriormente. S pode existir uma
nica funo com um determinado nome em um determinado mdulo.
As variveis temporrias raio e resultado so teis para o desenvolvimento e para depurao (debugging), mas
uma vez que o programa esteja funcionando, podemos torn-lo mais conciso atravs da composio das chamadas de
funo:
def area2(xc, yc, xp, yp):
return area(distancia(xc, yc, xp, yp))
Como exerccio, escreva uma funo coeficienteAngular(x1, y1, x2, y2) que retorne a coeficiente 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).
48
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
49
Se voc visse esta definio em um dicionrio, ficaria confuso. Por outro lado, se voc procurasse pela definio da
funo matemtica fatorial, voc encontraria algo assim:
0! = 1
n! = n.(n-1)!
Esta definio diz que o fatorial de 0 1, e que o fatorial de qualquer outro valor, n, n multiplicado pelo fatorial de
n-1.
Assim, 3! (l-se 3 fatorial ou fatorial de 3) 3 vezes 2!, o qual 2 vezes 1!, o qual 1 vezes 0!. Colocando tudo
isso junto, 3! igual 3 vezes 2 vezes 1 vezes 1, o que 6.
Se voc pode escrever uma definio recursiva de alguma coisa, voc geralmente pode escrever um programa em
Python para execut-la. O primeiro passo decidir quais so os parmetros para esta funo. Com pouco esforo,
voc dever concluir que fatorial recebe um nico parmetro:
def fatorial(n):
Por outro lado, e esta a parte interessante, temos que fazer uma chamada recursiva para encontrar o fatorial de n-1 e
ento multiplic-lo por n:
def fatorial(n):
if n == 0:
return 1
else:
recursivo = fatorial(n-1)
resultado = n * recursivo
return resultado
O fluxo de execuo para este programa similar ao fluxo de contagemRegressiva na Seo 4.9. Se chamarmos
fatorial com o valor 3:
J que 3 no 0, tomamos o segundo ramo e calculamos o fatorial de n-1 ...
J que 2 no 0, tomamos o segundo ramo e calculamos o fatorial de n-1 ...
J que 1 no 0, tomamos o segundo ramo e calculamos o fatorial de n-1 ...
J que 0 0, tomamos o primeiro ramo e retornamos 1 sem fazer mais qualquer chamada recursiva.
O valor retornado (1) multiplicado por n, que 1, e o resultado retornado.
O valor retornado (1) multiplicado por n, que 2, e o resultado retornado.
O valor retornado (2) multiplicado por n, que 3, e o resultado, 6, se torna o valor de retorno da chamada de funo
que iniciou todo o processo.
Eis o diagrama de pilha para esta sequncia de chamadas de funo:
50
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.
51
else:
return n * fatorial(n-1)
De agora em diante, tenderemos a utilizar um formato mais conciso, mas recomendamos que voc use a verso mais
explcita enquanto estiver desenvolvendo cdigo. Quando ele estiver funcionando, voc pode enxug-lo se estiver se
sentindo inspirado.
Depois de fatorial, o exemplo mais comum de uma funo matemtica definida recursivamente fibonacci,
a qual tem a seguinte definio:
fibonacci(0) = 1
fibonacci(1) = 1
fibonacci(n) = fibonacci(n-1) + fibonacci(n-2);
Se voc tentar seguir o fluxo de execuo aqui, mesmo para valores bem pequenos de n, sua cabea explodir. Mas,
de acordo com o voto de confiana, se voc assume que as duas chamadas recursivas funcionam corretamente, ento
claro que voc ter o resultado correto ao junt-las.
Parece um caso de recursividade infinita. Mas o que ser que de fato? Existe um caso base quando n == 0. O
problema que o valor de n nunca encontra o caso base.
Na primeira chamada recursiva, o valor de n 0.5. Na prxima, ele igual a -0.5. Da em diante, ele se torna cada vez
menor, mas jamais ser 0.
Temos ento duas alternativas. Podemos tentar generalizar a funo fatorial para que funcione com nmeros em
ponto flutuante, ou fazemos fatorial realizar a checagem de tipo de seus parmetros. A primeira chamada funo
gamma e est um pouco alm do escopo deste livro. Sendo assim, ficaremos com a segunda.
Podemos usar type para comparar o tipo do parmetro com o tipo de um valor inteiro conhecido (como 1). Ao
mesmo tempo em que fazemos isto, podemos nos certificar tambm de que o parmetro seja positivo:
def fatorial (n):
if type(n) != type(1):
print "Fatorial somente definido para inteiros."
return -1
elif n < 0:
print "Fatorial somente definido para inteiros positivos."
return -1
elif n ==0:
return 1
else:
return n * fatorial(n-1)
52
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 recursividade 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.
53
54
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
= 5
bruno,
= 7
bruno
A sada deste programa 5 7, porque na primeira vez que bruno impresso, seu valor 5 e na segunda vez, seu
valor 7. A vrgula no final do primeiro comando print suprime a nova linha no final da sada, que o motivo pelo
qual as duas sadas aparecem na mesma linha.
Veja uma reatribuio em um diagrama de estado:
55
Com a reatribuio torna-se ainda mais importante distinguir entre uma operao de atribuio e um comando de
igualdade. Como Python usa o sinal de igual ( = ) para atribuio, existe a tendncia de lermos um comando como a
= b como um comando de igualdade. Mas no !
Em primeiro lugar, igualdade comutativa e atribuio no . Por exemplo, em matemtica, se a = 7 ento 7 = a. Mas
em Python, o comando a = 7 permitido e 7 = a no .
Alm disso, em matemtica, uma expresso de igualdade sempre verdadeira. Se a = b agora, ento, a ser sempre
igual a b. Em Python, um comando de atribuio pode tornar duas variveis iguais, mas elas no tm que permanecer
assim:
a = 5
b = a # a e b agora so iguais
b = 3 # a e b no so mais iguais
A terceira linha muda o valor de a mas no muda o valor de b, ento, elas no so mais iguais. (Em algumas linguagens
de programao, um smbolo diferente usado para atribuio, como <- ou :=, para evitar confuso.)
Embora a reatribuio seja freqentemente til, voc deve us-la com cautela. Se o valor das variveis muda freqentemente, isto pode fazer o cdigo difcil de ler e de depurar.
56
# n par
# n impar
A condio para este loop n != 1, ento o loop vai continuar at que n seja 1, o que tornar a condio falsa.
Dentro de cada repetio (iterao) do loop, o programa gera o valor de n e ento checa se ele par ou impar. Se ele
for par, o valor de n dividido por 2. Se ele for impar, o valor substitudo por n*3+1. Por exemplo, se o valor
inicial (o argumento passado para seqncia) for 3, a seqncia resultante ser 3, 10, 5, 16, 8, 4, 2, 1.
J que n s vezes aumenta e s vezes diminui, no existe uma prova bvia de que n jamais venha a alcanar 1, ou de
que o programa termine. Para alguns valores particulares de n, podemos provar o trmino. Por exemplo, se o valor
inicial for uma potncia de dois, ento o valor de n ser par dentro de cada repetio (iterao) do loop at que alcance
1. O exemplo anterior termina com uma dessas seqncias comeando em 16.
Valores especficos parte, A questo interessante se h como provarmos que este programa termina para todos os
valores de n. At hoje, ningum foi capaz de provar que sim ou que no!
Como um exerccio, reescreva a funo nLinhas da seo 4.9 usando iterao em vez de recurso.
57
x = 1.0
while x < 10.0:
print x, \t, math.log(x)
x = x + 1.0
0.0
0.69314718056
1.09861228867
1.38629436112
1.60943791243
1.79175946923
1.94591014906
2.07944154168
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)
0.0
1.0
1.58496250072
2.0
2.32192809489
2.58496250072
2.80735492206
3.0
3.16992500144
Podemos ver que 1, 2, 4 e 8 so potncias de dois porque seus logaritmos na base 2 so nmeros redondos. Se
precisssemos encontrar os logaritmos de outras potncias de dois, poderamos modificar o programa deste modo:
x = 1.0
while x < 100.0:
print x, \t, math.log(x)/math.log(2.0)
x = x * 2.0
Agora, em vez de somar algo a x a cada iterao do loop, o que resulta numa seqncia aritmtica, ns multiplicamos
x por algo, resultando numa seqncia geomtrica. O resultado :
1.0
2.0
58
0.0
1.0
4.0
8.0
16.0
32.0
64.0
2.0
3.0
4.0
5.0
6.0
Por causa do caractere de tabulao entre as colunas, a posio da segunda coluna no depende do nmero de dgitos
na primeira coluna.
Tabelas de logaritmos podem no ser mais teis, mas para cientistas da computao, conhecer as potncias de dois !
Como um exerccio, modifique este programa de modo que ele produza as potncias de dois acima de 65.535 (ou seja,
216). Imprima e memorize-as.
O caractere de barra invertida em \t indica o incio de uma seqncia de escape. Seqncias de escape so usadas
para representar caracteres invisveis como de tabulao e de nova linha. A seqncia \n representa uma nova linha.
Uma seqncia de escape pode aparecer em qualquer lugar em uma string; no exemplo, a seqncia de escape de
tabulao a nica coisa dentro da string.
Como voc acha que se representa uma barra invertida em uma string?
Como um exerccio, escreva um nica string que
produza
esta sada.
A primeira linha inicializa a varivel chamada i, a qual age como um contador ou varivel de controle do loop.
Conforme o loop executado, o valor de i incrementado de 1 a 6. Quando i for 7, o loop termina. A cada repetio
(iterao) do loop, mostrado o valor de 2*i, seguido de trs espaos.
De novo, a vrgula no comando print suprime a nova linha. Depois que o loop se completa, o segundo comando
print inicia uma nova linha.
A sada do programa :
2
10
12
59
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
12
15
18
20
24
12
16
Agora voc provavelmente pode adivinhar como imprimir uma tabela de multiplicao - chamando
imprimeMultiplos repetidamente com argumentos diferentes. De fato, podemos usar um outro loop:
i = 1
while i <= 6:
imprimeMultiplos(i)
i = i + 1
Note o quanto este loop parecido com aquele dentro de imprimeMultiplos. Tudo o que fiz foi substituir o
comando print pela chamada funo.
A sada deste programa uma tabela de multiplicao:
1
2
3
4
5
6
2
4
6
8
10
12
3
6
9
12
15
18
4
8
12
16
20
24
5
10
15
20
25
30
6
12
18
24
30
36
Este processo um plano de desenvolvimento comum. Ns desenvolvemos cdigo escrevendo linhas de cdigo
fora de qualquer funo, ou digitando-as no interpretador. Quando temos o cdigo funcionando, extramos ele e o
embalamos em uma funo.
60
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.
61
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
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
Isto bom, exceto que ns provavelmente quereramos que a tabela fosse quadrada - com o mesmo nmero de linhas
e colunas. Para fazer isso, adicionamos outro parmetro a imprimeMultiplos para especificar quantas colunas a
tabela deveria ter.
S para confundir, chamamos este novo parmetro de altura, demonstrando que diferentes funes podem ter
parmetros com o mesmo nome (como acontece com as variveis locais). Aqui est o programa completo:
def imprimeMultiplos(n, altura):
i = 1
while i <= altura:
print n*i, t,
i = i + 1
print
def imprimeTabMult(altura):
i = 1
while i <= altura:
imprimeMultiplos(i, altura)
i = i + 1
Note que quando adicionamos um novo parmetro, temos que mudar a primeira linha da funo (o cabealho da
funo), e ns tambm temos que mudar o lugar de onde a funo chamada em imprimeTabMult.
Como esperado, este programa gera uma tabela quadrada de sete por sete:
1
2
3
4
5
6
7
2
4
6
8
10
12
14
3
6
9
12
15
18
21
4
8
12
16
20
24
28
5
10
15
20
25
30
35
6
12
18
24
30
36
42
7
14
21
28
35
42
49
Quando voc generaliza uma funo apropriadamente, voc muitas vezes tem um programa com capacidades que
voc no planejou. Por exemplo, voc pode ter notado que, porque ab = ba, todas as entradas na tabela aparecem duas
vezes. Voc poderia economizar tinta imprimindo somente a metade da tabela. Para fazer isso, voc tem que mudar
apenas uma linha em imprimeTabMult. Mude:
imprimeTabMult(i, altura)
para:
imprimeTabMult(i, i)
e voc ter:
62
1
2
3
4
5
6
7
4
6
8
10
12
14
9
12
15
18
21
16
20
24
28
25
30
35
36
42
49
Como um exerccio, trace a execuo desta verso de imprimeTabMult e explique como ela funciona.
63
plano de desenvolvimento (development plan) um processo definido para desenvolvimento de um programa. Neste
captulo, ns demonstramos um estilo de desenvolvimento baseado em escrever cdigo para executar tarefas
simples e especficas, usando encapsulamento e generalizao.
64
CAPTULO 9
Captulo 7: Strings
Tpicos
Captulo 7: Strings
7.1 Um tipo de dado composto
7.2 Comprimento
7.3 Travessia e o loop for
7.4 Fatias de strings
7.5 Comparao de strings
7.6 Strings so imutveis
7.7 Uma funo find (encontrar)
7.8 Iterando e contando
7.9 O mdulo string
7.10 Classificao de caracteres
7.11 Glossrio
7.11 Glossrio2
A expresso fruta[1] seleciona o caractere nmero 1 de fruta. A varivel letra referencia ou refere-se ao
resultado da expresso. Quando exibimos letra, temos uma surpresa:
65
A primeira letra de "banana" no a. A menos que voc seja um cientista da computao. Neste caso, voc
deve entender a expresso dentro dos colchetes como um deslocamento (offset,) a partir do comeo da string, e o
deslocamento da primeira letra zero. Assim, b a 0 (zero-sima) letra de "banana", a a 1 (um-sima,
diferente de primeira), e n a 2 (dois-sima, diferente de segunda) letra.
Para pegar a primeira letra de uma string, voc simplesmente pe 0, ou qualquer expresso que resulte o valor 0, dentro
dos colchetes:
>>> letra = fruta[0]
>>> print letra
b
A expresso entre colchetes chamada de ndice. Um ndice especifica um membro de um conjunto ordenado, neste
caso o conjunto de caracteres da string. O ndice indica aquele membro que voc quer, da seu nome. Ele pode ser
qualquer expresso inteira.
Para pegar a ltima letra de uma string, voc pode ficar tentado a fazer alguma coisa assim:
comprimento = len(fruta)
ultima = fruta[comprimento]
ERRO!
No vai funcionar. Isto vai causar o seguinte erro em tempo de execuo (runtime error): IndexError: string
index out of range. (ErroDeIndice: ndice da string fora do intervalo). A razo que no existe 6 letra em
"banana". J que comeamos a contar do zero, as seis letras so numeradas de 0 a 5. Para pegar o ltimo caractere,
temos que subtrair 1 de comprimento:
comprimento = len(fruta)
ultima = fruta[comprimento-1]
Como alternativa, podemos usar ndices negativos, os quais contam de trs pra frente os elementos da string. A
expresso fruta[-1] resulta a ltima letra, fruta[-2] resulta a penltima (a segunda de trs para frente), e
assim por diante.
66
Este loop percorre a string e exibe cada letra em sua prpria linha. A condio do loop indice < len(fruta),
assim, quando ndice igual ao comprimento da string, a condio se torna falsa, e o corpo do loop no executado.
O ltimo caractere acessado aquele com o ndice len(fruta)-1, que vem a ser o ltimo caractere da string.
Como um exerccio, escreva uma funo que tome uma string como argumento e devolva suas letras de
trs para frente, uma por linha.
Usar um ndice para percorrer um conjunto de valores to comum que Python oferece uma sintaxe alternativa
simplificada - o loop for:
for char in fruta:
print char
A cada vez atravs do loop, o prximo caractere da string atribudo varivel char. O loop continua at que no
reste mais caracteres.
O exemplo seguinte mostra como usar concatenao e um loop for para gerar uma srie abecedrio. Abecedrio
se refere a uma srie ou lista na qual os elementos aparecem em ordem alfabtica. Por exemplo, no livro de Robert
McCloskeys Make Way for Ducklings, os nomes dos ducklings so Jack, Kack, Lack, Mack, Nack, Ouack, Pack e
Quack. O loop seguinte, produz como sada aqueles nomes, em ordem:
prefixos = "JKLMNOPQ"
sufixo = "ack"
for letra in prefixos:
print letra + sufixo
Naturalmente, esta sada no est cem por cento certa porque Ouack e Quack esto escritos de maneira errada.
Como um exerccio, modifique o programa para corrigir este erro.
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:
67
Se voc omitir o primeiro ndice (antes dos dois pontos :), a fatia comea do incio da string. Se voc omitir o
segundo ndice, a fatia vai at o final da string. Assim:
>>> fruta = "banana"
>>> fruta[:3]
ban
>>> fruta[3:]
ana
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
ERRO!
Em vez de produzir a sada El, Mundo!, este cdigo produz o erro em tempo de execuo (runtime error):
TypeError: object doesnt support item assignment (ErroDeTipo: objeto no d suporte
atribuio de item.)
Strings so imutveis, o que significa que voc no pode mudar uma string que j existe. O melhor que voc pode
fazer criar uma nova string que seja uma variao da original:
saudacao = "Al, mundo!"
novaSaudacao = E + saudacao[1:]
print novaSaudacao
A soluo aqui concatenar uma nova primeira letra com uma fatia de saudacao. Esta operao no tem nenhum
efeito sobre a string original.
Num certo sentido, find (encontrar) o oposto do operador []. Em vez de pegar um ndice e extrair o caractere
correspondente, ela pega um caractere e encontra (finds) em qual ndice aquele caractere aparece. Se o caractere no
encontrado, a funo retorna -1.
Este o primeiro exemplo que vemos de uma instruo return dentro de um loop. Se str[indice] == ch, a
funo retorna imediatamente, abandonando o loop prematuramente.
Se o caractere no aparece na string, ento o programa sai do loop normalmente e retorna -1.
Este padro de computao s vezes chamado de travessia eureka, porque to logo ele encontra (find) o que est
procurando, ele pode gritar Eureka! e parar de procurar.
Como um exerccio, modifique a funo find (encontrar) de modo que ela receba um terceiro parmetro,
o ndice da string por onde ela deve comear sua procura.
Este programa demonstra um outro padro de computao chamado de contador. A varivel contador inicializada
em 0 e ento incrementada cada vez que um a encontrado. (Incrementar o mesmo que aumentar em um; o
oposto de decrementar, e no tem relao com excremento, que um substantivo.) Quando se sai do loop, contador
guarda o resultado - o nmero total de as.
69
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.
O mdulo string inclui uma funo chamada find (encontrar) que faz a mesma coisa que a funo que escrevemos.
Para cham-la, temos que especificar o nome do mdulo e o nome da funo usando a notao de ponto.:
>>> fruta = "banana"
>>> indice = string.find(fruta, "a")
>>> print indice
1
Este exemplo demonstra um dos benefcios dos mdulos - eles ajudam a evitar colises entre nomes de funes
nativas e nomes de funes definidas pelo usurio. Usando a notao de ponto podemos especificar que verso de
find (encontrar) ns queremos.
De fato, string.find mais generalizada que a nossa verso. Primeiramente, ela pode encontrar substrings, no
apenas caracteres:
>>> string.find("banana", "na")
2
Alm disso, ela recebe um argumento adicional que especifica o ndice pelo qual ela deve comear sua procura:
>>> string.find("banana", "na", 3)
4
Ou ela pode receber dois argumentos adicionais que especificam o intervalo de ndices:
>>> string.find("bob", "b", 1, 2)
-1
Neste exemplo, a busca falha porque a letra b no aparece no intervalo entre 1 e 2 (no incluindo o 2) do ndice.
70
Por exemplo, se
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
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.
71
72
CAPTULO 10
Captulo 8: Listas
Tpicos
Captulo 8: Listas
8.1 Valores da lista
8.2 Acessado elementos
8.3 Comprimento da lista
8.4 Membros de uma lista
8.5 Listas e laos for
8.6 Operaes em listas
8.7 Fatiamento de listas
8.8 Listas so mutveis
8.9 Remoo em lista
8.10 Ojetos e valores
8.11 Apelidos
8.12 Clonando listas
8.13 Lista como parmetro
8.14 Lista aninhadas
8.15 Matrizes
8.16 Strings e listas
8.17 Glossrio
Outros termos utilizados neste captulo
Uma lista um conjunto ordenado de valores, onde cada valor identificado por um ndice. Os valores que compem
uma lista so chamados elementos. Listas so similares a strings, que so conjuntos ordenados de caracteres, com a
diferena que os elementos de uma lista podem possuir qualquer tipo. Listas e strings XXX e outras coisas que se
comportam como conjuntos ordenados XXX so chamados seqncias.
73
O primeiro exemplo uma lista de quatro inteiros. O segundo uma lista de trs strings. Os elementos de uma lista
no necessitam ser do mesmo tipo. A lista a seguir contm uma string, um valor float, um valor inteiro, e mirabile
dictu uma outra lista:
>>> [alo, 2.0, 5, [10,20]]
A funo range pega dois argumentos e devolve uma lista que contm todos os inteiros do primeiro at o segundo,
incluindo o primeiro mas no incluindo o segundo!
Existem outras formas de range. Com um argumento simples, ela cria uma lista que inicia em 0:
>>> range(10)
[0,1, 2, 3, 4, 5, 6, 7, 8, 9]
Se existe um terceiro argumento, ele especifica o espao entre os valores sucessivos, que chamado de tamanho do
passo. Este exemplo conta de 1 at 10 em passos de 2:
>>> range(1, 10, 2)
[1, 3, 5, 7, 9]
Finalmente, existe uma lista especial que no contm elementos. Ela chamada lista vazia, e sua notao [].
Com todas estas formas de criar listas, seria decepcionante se no pudssemos atribuir valores de listas a variveis ou
passar listas como parmetros a funes. Felizmente, podemos.
>>> vocabulario = [melhorar, castigar, defenestrar]
>>> numeros = [17, 123]
>>> vazio = []
>>> print vocabulario, numeros, vazio
[melhorar, castigar, defenestrar] [17, 123] []
O operador colchete pode aparecer em qualquer lugar em uma expresso. Quando ele aparece no lado esquerdo de
uma atribuio, ele modifica um dos elementos em uma lista, de forma que o um-simo elemento de numeros, que
era 123, agora 5.
Qualquer expresso inteira pode ser utilizada como um ndice:
>>> numeros[3-2]
5
>>> numeros[1.0]
TypeError: sequence index must be integer
Se voc tentar ler ou escrever um elemento que no existe, voc recebe um erro de tempo de execuo (runtime error):
74
>>> numeros[2]=5
IndexError: list assignment index out of range
Se um ndice possui um valor negativo, ele conta ao contrrio a partir do final da lista:
>>> numeros[-1]
5
>>> numeros[-2]
17
>>> numeros[-3]
IndexError: list index out of range
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.
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 comprimento desta lista quatro:
>>> [spam!, 1, [Brie, Roquefort, Pol l Veq], [1, 2 3]]
Como um exerccio, escreva um lao que percorra a lista anterior e exiba o comprimento de cada elemento.
O que acontece se voc manda um inteiro para len?
75
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
i < len(LISTA):
VARIAVEL = LISTA[i]
XXX BODY
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) cavaleiro.
Qualquer expresso de lista pode ser utilizada num lao for:
>>> for numero in range(20):
if numero % 2 == 0:
print numero
>>> for fruta in ["banana", "abacaxi", "laranja"]:
print "Eu gosto de comer " + fruta + "s!"
O primeiro exemplo exibe todos os nmeros pares entre zero e dezenove. O segundo exemplo expressa o entusiasmo
por vrias frutas.
76
>>>
>>>
>>>
>>>
[1,
a = [1, 2, 3]
b = [4, 5, 6]
c = a + b
print c
2, 3, 4, 5, 6]
[0] * 4
0, 0, 0]
[1, 2, 3] * 3
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.
Tambm podemos remover elementos de uma lista atribuindo a lista vazia a eles:
>>> lista = [a, b, c, d, e, f]
>>> lista[1:3] = []
>>> print lista
[a, d, e, f]
E podemos adicionar elementos a uma lista enfiando-os numa fatia vazia na posio desejada:
77
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.
sabemos que a e b se referem a uma string com as letras banana. Mas no podemos dizer se elas apontam para a
mesma string.
Existem dois possveis estados:
Em um caso, a e b se referem a duas coisas diferentes que possuem o mesmo valor. No segundo caso, elas se referem
mesma coisa. Estas coisas possume nomes - elas so chamadas objetos. Um objeto algo ao qual uma varivel
pode se referenciar.
78
Todo objeto possui um identificador nico, que podemos obter com a funo id. Exibindo o identificador de a e b,
podemos dizer se elas se referem ao mesmo objeto.
>>> id(a)
135044008
>>> id(b)
135044008
De fato, obtivemos o mesmo identificador duas vezes, o que significa que Python criou apenas uma string, e tanto a
quanto b se referem a ela.
Interessantemente, listas se comportam de forma diferente. Quando criamos duas listas, obtemos dois objetos:
>>> a = [1, 2, 3]
>>> b = [1, 2, 3]
>>> id(a)
135045528
>>> id(b)
135041704
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]
79
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.
a = [1, 2, 3]
b = a[:]
print b
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.
O parmetro lista e a varivel numeros so apelidos para o mesmo objeto. O diagrama de estado se parece com
isto:
Uma vez que o objeto compartilhado pelos dois quadros, o desenhamos entre eles.
80
Se a funo modifica um parmetro da lista, a funo chamadora v a mudana. Por exemplo, removeCabeca
remove o primeiro elemento da lista:
>>> def removecabeca(lista):
del lista[0]
numeros = [1, 2, 3]
removeCabeca(numeros)
print numeros
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:]
numeros = [1, 2, 3]
resto = cauda(numeros)
print resto
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.
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.
81
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]
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.
Um argumento opcional chamado um delimitador pode ser utilizado para especificar qual caracter utilizar como
limites da palavra. O exemplo a seguir utiliza a string va:
>>> string.split(poesia, va)
[O or, lho no car, lho...]
82
83
84
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
Para criar uma tupla com um nico elemento, temos que incluir uma vrgula final:
>>> t1 = (a,)
>>> type(t1)
<type tuple>
Sem a vrgula, Python entende (a) como uma string entre parnteses:
85
>>> t2 = (a)
>>> type(t2)
<type string>
Questes de sintaxe de lado, as operaes em tuplas so as mesmas operaes das listas. O operador ndice seleciona
um elemento da tupla.
>>> tupla = (a, b, c, d, e)
>>> tupla[0]
a
Naturalmente, mesmo que no possamos modificar os elementos de uma tupla, podemos substitu-la por uma tupla
diferente:
>>> tupla = (A,) + tupla[1:]
>>> tupla
(A, b, c, d, e)
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
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):
x, y = y, x
# versao incorreta
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.
Para gerar um nmero aleatrio ente 0.0 e um limite superior, digamos superior, multiplique x por superior.
Como exerccio, gere um nmero aleatrio entre inferior e superior.
Como exerccio adicional, gere um nmero inteiro aleatrio entre inferior e superior, inclusive os dois
extremos.
87
Vamos realizar um teste desta funo com uma lista de oito elementos. Para efeitos de depurao, uma boa idia
comear com uma lista pequena.
>>> listaAleatoria(8)
0.15156642489
0.498048560109
0.810894847068
0.360371157682
0.275119183077
0.328578797631
0.759199803101
0.800367163582
Os nmeros gerados por random so supostamente uniformemente distribudos, o que significa que cada valor tem
uma probabilidade igual de acontecer.
Se ns dividirmos a faixa de valores possveis em intervalos do mesmo tamanho, e contarmos o nmero de vezes que
um determinado valor aleatrio caiu em seu respectivo intervalo, ns devemos obter o mesmo nmero aproximado de
valores em cada um dos intervalos.
Ns podemos testar esta teoria escrevendo um programa que divida a faixa de valores em intervalos e conte o nmero
de valores de cada intervalo.
O primeiro passo substituir fruta por lista e letra por numero. Isso no muda o programa, apenas o ajusta
para que ele se torne mais fcil de ler e entender.
O segundo passo mudar o teste. Ns no estamos interessados em procurar letras. Ns queremos ver se numero
est entre inferior e superior.:
88
contador = 0
for numero in lista
if inferior < numero < superior:
contador = contador + 1
print contador
O ltimo passo encapsular este cdigo em uma funo chamada noIntervalo. Os parmetros so a lista e os
valores inferior e superior:
def noIntervalo(lista, inferior, superior):
contador = 0
for numero in lista:
if inferior < numero < superior:
contador = contador + 1
return contador
Atravs da cpia e da modificao de um programa existente, estamos aptos a escrever esta funo rapidamente e
economizar um bocado de tempo de depurao. Este plano de desenvolvimento chamado de casamento de padres.
Se voc se encontrar trabalhando em um problema que voc j solucionou antes, reuse a soluo.
=
=
=
=
noIntervalo(a,
noIntervalo(a,
noIntervalo(a,
noIntervalo(a,
0.0, 0.25)
0.25, 0.5)
0.5, 0.75)
0.75, 1.0)
Existem aqui dois problemas. Um que temos que criar novos nomes de varivel para cada resultado. O outro que
temos que calcular os limites de cada intervalo.
Vamos resolver o segundo problema primeiro. Se o nmero de intervalos numeroDeIntervalos, ento a largura
de cada intervalo 1.0 / numeroDeIntervalos.
Vamos usar um lao (loop) para calcular a faixa, ou largura, de cada intervalo. A varivel do loop, i, conta de 0 at
numeroDeIntervalos-1:
larguraDoIntervalo = 1.0 / numeroDeIntervalos
for i in range(numeroDeIntervalos):
inferior = i * larguraDoIntervalo
superior = inferior + larguraDoIntervalo
print "do" inferior, "ao", superior
Para calcular o limite inferior (inferior) de cada intervalo, ns multiplicamos a varivel do loop (i) pela largura
do intervalo (larguraDoIntervalo). O limite superior (superior) est exatamente uma largura de intervalo
acima.
Com numeroDeIntervalos = 8, o resultado :
0.0 to 0.125
0.125 to 0.25
0.25 to 0.375
89
0.375 to 0.5
0.5 to 0.625
0.625 to 0.75
0.75 to 0.875
0.875 to 1.0
Voc pode confirmar que cada intervalo tem a mesma largura, que eles no se sobrepe, e que eles cobrem toda a faixa
de valores de 0.0 a 1.0.
Agora, de volta ao primeiro problema. Ns precisamos de uma maneira de guardar oito inteiros, usando a vriavel do
loop para indicar cada um destes inteiros. Voc deve estar pensando, Lista!
Ns temos que criar a lista de intervalos fora do loop, porque queremos fazer isto apenas uma vez. Dentro do loop,
ns vamos chamar noIntervalo repetidamente e atualizar o i-simo elemento da lista:
numeroDeIntervalos = 8
intervalos = [0] * numeroDeIntervalos
larguraDoIntervalo = 1.0 / numeroDeIntervalos
for i in range(numeroDeIntervalos):
inferior = i * larguraDoIntervalo
superior = inferior + larguraDoIntervalo
intervalos[i] = noIntervalo(lista, inferior, superior)
print intervalos
Com uma lista de 1000 valores, este cdigo vai produzir esta lista de quantidades de valores em cada intervalo:
[138, 124, 128, 118, 130, 117, 114, 131]
Esses nmeros esto razoavelmente pximos de 125, o que era o que espervamos. Pelo menos eles esto prximos o
bastante para nos fazer acreditar que o gerador de nmero aleatrios est funcionando.
Como exerccio, teste esta funo com algumas listas longas, e veja se o nmero de valores em cada um
dos intervalos tendem a uma distribuio nivelada.
90
Usamos a funo int para converter um nmero em ponto flutuante (float) para um inteiro.
Existe a possibilidade deste clculo produzir um ndice que esteja fora dos limites (seja negativo ou maior que
len(intervalos)-1)?
Uma lista como intervalos que contm uma contagem do nmero de valores em cada intervalo chamada de
histograma.
Como exerccio, escreva uma funo chamada histograma que receba uma lista e um nmero de
intervalos como argumentos e retorne um histograma com o nmero de intervalos solicitado.
91
92
CAPTULO 12
Tpicos
Captulo 10: Dicionrios
10.1 Operaes dos Dicionrios
10.2 Mtodos dos Dicionrios
10.3 Aliasing (XXX) e Copiar
10.4 Matrizes Esparsas
10.5 Hint XXX
10.6 Inteiros Longos
10.7 Contando Letras
10.8 Glossrio
Os tipos compostos que voce aprendeu - strings, listas e tuplas - utilizam inteiros como indices. Se voce tentar utilizar
qualquer outro tipo como indice, voce receber um erro.
Dicionrios sao similiares a outros tipos compostos exceto por eles poderem user qualquer tipo imutavel de dados
como indice. Como exemplo, nos criaremos um dicionrio para traduzir palavras em Ingls para Espanhol. Para esse
dicionrio, os indices sero strings.
Uma maneira de criar um dicionario comecando com um dicionrio vazio e depois adiconando elementos. Um
dicionrio vazio denotado assim {}:
>>> ing2esp = {}
>>> ing2esp[one] = uno
>>> ing2esp[two] = dos
A primeira atribuio cria um dicionario chamado ing2esp; as outras atribuies adicionam novos elementos para
o dicionrio. Nos podemos imprimir o valor corrente de um dicionario da maneira usual:
>>> print ing2esp
{one: uno, two: dos}
Os elementos de um dicionrio aparecem em uma lista separada por vrgulas. Cada entrada contm um indice e
um valor separado por dois-pontos. Em um dicionrio, os ndices sao chamados de chaves, entao os elementos so
chamados de pares chave-valor.
Outra maneira de criar dicionrios fornecendo uma lista de pares chaves-valor utilizando a mesma sintaxe da ltima
sada.
93
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.
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
Dessa forma o ponto especifica o nome da funo, keys, e o nome do objeto em que deve ser aplicada a funo,
ing2esp. Os parenteses indicam que esse mtodo no possui parameteros.
Ao invs de chamarmos um mtodo, dizemos que ele invocado, nesse caso, ns podemos dizer que ns estamos
invocando keys do objeto ing2esp.
94
O mtodo items retorna os dois, na forma de uma lista de tuplas - cada tupla com um par chave-valor:
>>> ing2esp.items()
[(one,uno), (three,tres), (two,dos)]
A sintaxe fornece uma informao util. Os colchetes indicam que isso uma lista. Os parentses indicam que os
elementos da lista so tuplas.
Se o mtodo recebe de algum parmetro, se utiliza a mesma sintaxe das funes. Por exemplo, o mtodo has_key
recebe uma chave e retorna verdadeiro (1) se a chave existe no dicionrio:
>>> ing2esp.has_key(one)
True
>>> ing2esp.has_key(deux)
False
Se voce tentar chamar um mtodo sem especificar em qual objeto, voce obter um erro. Nesse caso, a mensagem de
erro no muito til:
>>> has_key(one)
NameError: has_key
alias e opposites se referem ao mesmo objeto; copy se refere a um novo objeto igual ao dicionrio opposites. Se voc
modificar o alias, opposites tambm ser alterado.
>>> alias[right] = left
>>> opossites[right]
left
95
Uma alternativa usarmos um dicionrio. Para as chaves, ns podemos usar tuplas que contm os nmeros da linha e
a coluna. Abaixo uma representao em um dicinario da mesma matriz:
>>> matriz = {(0,3): 1, (2, 1): 2, (4, 3): 3}
Ns precisamos apenas de trs pares chave-valor, cada um sendo um elemento diferente de zero da matriz. Cada chave
uma tupla, e cada valor um nmero inteiro.
Para acessarmos um elemento da matriz, nos utilizamos o operador []:
>>> matriz[0,3]
1
Note que a sintaxe da representao de um dicionrio no a mesma que a sintaxe usada pela representao pelas
listas. Em vez de usarmos dois ndices inteiros, ns usamos apenas um ndice, que uma tupla de inteiros.
Mas existe um problema. Se tentarmos buscar um elemento zero, obteremos um erro, pois no existe uma entrada no
dicionrio para a chave especificada:
>>> matriz[1,3]
KeyError: (1,3)
O primeiro parmetro a chave; o segundo o valor que get retornar caso no existe a chave no dicionrio:
>>> matriz.get((1,3), 0)
0
Em uma das nossas mquinas, fibonacci(20) executa instantaneamente, fibonacci(30) demora cerca de um segundo,
e fibonacci(40) demora uma eternidade.
Para entender o porque, considere o grfico de chamadas para fibonacci com n=4:
O grfico mostra a estrutura da funo, com linhas conectando cada execuo com a execuo que a chamou. No
topo do grfico, fibonacci tem n=4, que chama fibonacci com n=3 e n=2. Em seguida, fibonacci com n=3 chama
fibonacci com n=2 e n=1. E assim por diante.
Conte quantas vezes fibonacci(0) e fibonacci(1) so chamadas. Essa uma soluo ineficiente para o problema, e
torna-se pior quando o parmetro recebido um nmero maior.
Uma boa soluo guardar os valores que j foram calculados armazenando-os em um dicionrio. Um valor previamente calculado que guardado para ser utilizado mais tarde chamado de hint. Abaixo uma implementao de
fibonacci usando hints:
>>> previous = {0:1, 1:1}
>>> def fibonacci(n):
if previous.has_key(n):
return previous[n]
else:
newValue = fibonacci(n-1) + fibonacci(n-2)
previous[n] = newValue
return newValue
O dicionrio chamado previous guarda os nmeros de Fibonacci que ns ja conhecemos. Ele comea com apenas
dois pares: 0 possui 1; e 1 possui 1.
12.5. 10.5 Hint XXX
97
Sempre que fibonacci chamada, ela verifica o dicionrio para determinar se ele j possui o resultado. Se o resultado
estiver ali, a funo pode retornar imediatamente sempre precisar fazer mais chamadas recursivas. Se o resultado no
estiver ali, ele calculado no newValue. O valor de newValue adicionado no dicionrio antes da funo retornar.
Usando essa verso de fibonacci, nossa mquina consegue calcular fibonacci(40) em um piscar de olhos. Mas quando
tentamos calcular fibonacci(50), ns veremos um problema diferente:
>>> fibonacci(50)
OverflowError: integer addition
A resposta, que voc ver em um minuto, 20.365.011.074. O problema que esse nmero muito grande para
guardarmos como um inteiro do Python 1 . Isso overflow. Felizmente, esse problema tem uma soluo simples.
A outra maneira usarmos a funo long que converte um valor para um long int. long pode receber qualquer valor
nmerico e at mesmo uma string de digitos:
>>> long(1)
1L
>>> long(3.9)
3L
>>> long(57)
57L
Todas as operaes matemticas funcionam com long int s, ento no precisamos modificar muito para adaptar fibonacci:
>>> previous = {0: 1L, 1:1L}
>>> fibonacci(50)
20365011074L
Somente trocando os valores iniciais de previous, conseguimos mudar o comportamento da fibonacci. Os dois
primeiros numeros da sequncia so long ints, ento todos os nmeros subsequentes da sequncia tambm sero.
Como exerccio, converta fatorial para produzir um inteiro longo como resultado.
N.T. A partir do Python 2. XXX este erro no ocorre mais, pois em caso de sobrecarga o valor inteiro automaticamente promovido para o
tipo long.
98
>>> 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 incrementamos. No final, o dicionrio contem pares de letras e as suas frequncias.
mais atraente mostrarmos o histograma na ordem alfabtica. Podemos fazer isso com os mtodos items e sort:
>>> letterItems = letterCounts.items()
>>> letterItems.sort()
>>> print letterItems
[(M, 1), (i, 4), (p, 2), (s, 4)]
Voc ja tinha visto o mtodo items antes, mas sort o primeiro mtodo que voc se depara para aplicar em listas.
Existem muitos outros mtodos de listas, incluindo append, extend, e reverse. Consulte a documentao do Python
para maiores detalhes.
99
100
CAPTULO 13
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
101
A funo open recebe dois argumentos. O primeiro o nome do arquivo, e o segundo o modo. Modo ?w? significa
que estamos abrindo o arquivo para gravao (?*write*?, escrever).
Se no existir nenhum arquivo de nome teste.dat, ele ser criado. Se j existir um, ele ser substitudo pelo
arquivo que estamos gravando (ou escrevendo).
Quando executamos um comando print sobre o objeto arquivo, visualizamos o nome do arquivo, o modo e a
localizao do objeto na memria.
Para colocar dados dentro do arquivo, invocamos o mtodo write do objeto arquivo:
>>> f.write("Agora hora")
>>> f.write("de fechar o arquivo")
Fechar o arquivo diz ao sistema que terminamos de escrever (gravar) e que o arquivo est livre para ser lido:
>>> f.close()
Agora podemos abrir o arquivo de novo, desta vez para leitura, e ler o seu contedo para uma string. Desta vez, o
argumento modo ?r? para leitura (?reading?):
>>> f = open("teste.dat", "r")
Sem nenhuma surpresa, o mtodo read l dados do arquivo. Sem argumentos, ele l todo o contedo do arquivo:
>>> texto = f.read()
>>> print texto
Agora horade fechar o arquivo
No existe espao entre ?hora? e ?de? porque ns no gravamos um espao entre as strings.
read tambm pode receber um argumento que indica quantos caracteres ler:
>>> f = open("teste.dat", "r")
>>> print f.read(9)
Agora h
Se no houver caracteres suficientes no arquivo, read retorna os caracteres restantes. Quando chegamos ao final do
arquivo, read retorna a string vazia:
>>> print f.read(1000006)
orade fechar o arquivo
>>> print f.read()
>>>
A funo seguinte, copia um arquivo, lendo e gravando at cinqenta caracteres de uma vez. O primeiro argumento
o nome do arquivo original; o segundo o nome do novo arquivo:
def copiaArquivo(velhoArquivo, novoArquivo):
f1 = open(velhoArquivo, "r")
f2 = open(novoArquivo, "w")
while 1:
102
texto = f1.read(50)
if texto == "":
break
f2.write(texto)
f1.close()
f2.close()
return
A comando break novo. O que ele faz saltar a execuo para fora do loop; o fluxo de execuo passa para o
primeiro comando depois do loop.
Neste exemplo, o loop while infinito porque o valor 1 sempre verdadeiro. O nico modo de sair do loop
executando o break, o que ocorre quando texto a string vazia, o que ocorre quando alcanamos o fim do arquivo.
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
>>>
Neste caso, a sada est em formado de lista, o que significa que as strings aparecem entre aspas e o caractere de nova
linha aparece como a seqncia de escape 012.
No fim do arquivo, readline retorna a string vazia e readlines retorna a lista vazia:
>>> print f.readline()
>>> print f.readlines()
[]
A seguir temos um exemplo de um programa de processamento de linhas. filtraArquivo faz uma cpia de
velhoArquivo, omitindo quaisquer linhas que comecem por #:
def filtraArquivo(velhoArquivo, novoArquivo):
f1 = open(velhoArquivo, "r")
f2 = open(novoArquivo, "w")
while 1:
texto = f1.readline()
if texto == "":
103
break
if texto[0] == #:
continue
f2.write(texto)
f1.close()
f2.close()
return
O comando continue termina a iterao corrente do loop, mas continua iterando o loop. O fluxo de execuo passa
para o topo do loop, checa a condio e prossegue conforme o caso.
Assim, se texto for a string vazia, o loop termina. Se o primeiro caractere de texto for o jogo da velha (? # ?), o
fluxo de execuo passa para o topo do loop. Somente se ambas as condies falharem que texto ser copiado
para dentro do novo arquivo.
Uma alternativa usar o operador de formatao %. Quando aplicado a inteiros, % o operador mdulo. Mas quando
o primeiro operador uma string, % o operador de formatao.
O primeiro operando a string de formatao, e o segundo operando uma tupla de expresses. O resultado uma
string que contm os valores das expresses, formatadas de acordo com a string de formatao.
Num exemplo simples, a seqncia de formatao ??%d?? significa que a primeira expresso na tupla deve ser
formatada como um inteiro. Aqui a letra d representa ?decimal?.
>>> carros = 52
>>> "%d" % carros
52
O resultado a string ?52?, que no deve ser confundida com o valor inteiro 52.
Uma seqncia de formatao pode aparecer em qualquer lugar na string de formatao, assim, podemos embutir um
valor em uma seqncia:
>>> carros = 52
>>> "Em julho vendemos %d carros." % carros
Em julho vendemos 52 carros.
A seqncia de formatao %f formata o prximo item da tupla como um nmero em ponto flutuante, e %s
formata o prximo como uma string:
>>> "Em %d dias fizemos %f milhes %s." % (34,6.1,reais)
Em 34 dias fizemos 6.100000 milhes de reais.
104
62
>>> "%12f" % 6.1
6,100000
O nmero depois do sinal de porcentagem o nmero mnimo de espaos que o valor ocupar. Se o valor fornecido
tiver um nmero menor de dgitos, espaos em branco sero adicionados antes para preencher o restante. Se o nmero
de espaos for negativo, os espaos sero adicionados depois:
>>> "%-6d" % 62
62
Para nmeros em ponto-flutuante, tambm podemos especificar o nmero de dgitos depois da vrgula:
>>> "%12.2f" % 6.1
6.10
Neste exemplo, o resultado reserva 12 espaos e inclui dois dgitos depois da vrgula. Esta formatao til para
exibir valores monetrios com os centavos alinhados.
Por exemplo, imagine um dicionrio que contm nomes de estudantes como chaves e salrios-hora como valores. Aqui
est uma funo que imprime o contedo do dicionrio como um relatrio formatado:
def relatorio(salarios):
estudantes = salarios.keys()
estudantes.sort()
for estudante in estudantes:
print "%-20s %12.02f" % (estudante, salarios[estudante])
Controlando a largura de cada valor, podemos garantir que as colunas ficaro alinhadas, desde que os nomes contenham
menos que vinte e um caracteres e os salrios sejam menores do que um bilho de reais por hora.
105
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.
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 comandos necessrios. Para us-lo, importe pickle e ento abra o arquivo da maneira usual:
>>> import pickle
>>> f = open(?test.pck?, ?w?)
Para armazenar uma estrutura de dados, use o mtodo dump e ento feche o arquivo do modo usual:
>>> pickle.dump(12.3, f)
>>> pickle.dump([1,2,3], f)
>>> f.close()
Ento, podemos abrir o arquivo para leitura e carregar as estruturas de dados que foram descarregadas (dumped):
>>> f = open(?test.pck?, ?r?)
>>> x = pickle.load(f)
>>> x
12,3
>>> type(x)
<type ?float?>
>>> y = pickle.load(f)
>>> y
[1, 2, 3]
>>> type(y)
<type ?list?>
Cada vez que invocamos load, obtemos um nico valor do arquivo, completo com seu tipo original.
106
Em cada caso, a mensagem de erro tem duas partes: o tipo do erro antes dos dois pontos, e especificidades do
erro depois dos dois pontos. Normalmente Python tambm exibe um ?*traceback*? de onde estava a execuo do
programa, mas ns temos omitido esta parte nos exemplos.
s vezes queremos executar uma operao que pode causar uma exceo, mas no queremos que o programa pare.
Ns podemos tratar a exceo usando as instrues try e except.
Por exemplo, podemos pedir ao usurio um nome de arquivo e ento tentar abr-lo. Se o arquivo no existe, no
queremos que o programa trave; queremos tratar a exceo:
nomedoarquivo = raw_input(?Entre com o nome do arquivo: ?)
try:
f = open (nomedoarquivo, ?r?)
except:
print ?No existe arquivo chamado?, nomedoarquivo
A instruo try executa os comandos do primeiro bloco. Se no ocorrerem excees, ele ignora a instruo except.
Se qualquer exceo acontece, ele executa os comandos do ramo except e continua.
Podemos encapsular esta habilidade numa funo: existe toma um nome de arquivo e retorna verdadeiro se o arquivo
existe e falso se no existe:
def existe(nomedoarquivo)
try:
f = open(nomedoarquivo)
f.close()
return 1
except:
return 0
Voc pode usar mltiplos blocos except para tratar diferentes tipos de excees. O Manual de Referncia de Python
(Python Reference Manual) tem os detalhes.
Se o seu programa detecta uma condio de erro, voc pode faz-lo lanar uma exceo. Aqui est um exemplo que
toma uma entrada do usurio e testa se o valor 17. Supondo que 17 no seja uma entrada vlida por uma razo
qualquer, ns lanamos uma exceo.
107
def entraNumero():
x = input (?Escolha um nmero: ?)
if x == 17:
raise ?ErroNumeroRuim?, ?17 um nmero ruim?
return x
O comando raise toma dois argumentos: o tipo da exceo e informaes especficas sobre o erro.
ErroNumeroRuim um novo tipo de exceo que ns inventamos para esta aplicao.
Se a funo que chamou entraNumero trata o erro, ento o programa pode continuar; de outro modo, Pyhton exibe
uma mensagem de erro e sai:
>>> entraNumero()
Escolha um nmero: 17
ErroNumeroRuim: 17 um nmero ruim
A mensagem de erro inclui o tipo da exceo e a informao adicional que voc forneceu.
Como um exerccio, escreva uma funo que use entraNumero para pegar um nmero do teclado e que
trate a exceo ErroNumeroRuim.
108
CAPTULO 14
Tpicos
Captulo 12: Classes e objetos
12.1 Tipos compostos definidos pelo usurio
12.2 Atributos
12.3 Instncias como parmetros
12.4 O significado de mesmo
12.5 Retngulos
12.6 Instancias como valores retornados
12.7 Objetos so mutveis
12.8 Copiando
12.9 Glossrio
109
class Ponto:
pass
Definies de classes podem aparecer em qualquer parte de um programa, mas elas costuma ficar prximas do comeo
do programa (aps os comandos import). As regras de sintaxe para a definio de classes so as mesmas de outros
comandos compostos (veja Seo 4.4).
A definio acima cria uma nova classe chamada Ponto. O comando pass no tem nenhum efeito; aqui ele
necessrio porque um comando composto precisa ter algo no seu corpo.
Quando criamos a classe Ponto, criamos um novo tipo de dado, tambm chamado Ponto. Os membros deste novo
tipo so chamados instncias deste tipo ou objetos. Criar uma nova instncia instanciar. Para instanciar o objeto
Ponto, invocamos a funo (adivinhou?) Ponto:
final = Ponto()
A varivel final agora contm uma referncia a um novo objeto da classe Ponto. Uma funo como Ponto, que
cria novos objetos, chamada construtor.
Esta sintaxe similar sintaxe para acessar uma varivel de um mdulo, como math.pi ou string.uppercase.
Neste caso, porm, estamos acessando um item de dado de uma instncia. Estes itens so chamados atributos.
O seguinte diagrama de estado mostra o resultado destas atribuies:
A varivel final refere a um objeto Ponto, que contm dois atributos. Cada atributo faz referncia a um nmero
em ponto flutuante.
Podemos ler o valor de um atributo usando a mesma sintaxe:
>>> print final.y
4.0
>>> x = final.x
>>> print x
3.0
A expresso final.x significa, V ao objeto final e pegue o valor de x. Neste caso, atribumos este valor
a uma varivel cujo nome x. No h conflito entre a varivel x e o atributo x. O propsito da notao
objeto.atributo identificar a qual varivel voc est fazendo referncia de forma que no ambguo.
Voc pode usar a notao objeto.atributo como parte de qualquer expresso; assim os seguintes comandos so
vlidos:
110
A primeira linha imprime (3.0, 4.0); a segunda linha calcula o valor 25.0.
tentador imprimir o valor do prprio objeto final:
>>> print final
<__main__.Ponto instance at 80f8e70>
O resultado indica que final uma instncia da classe Ponto e foi definida no prgrama principal: __main__.
80f8e70 o identificador nico deste objeto, escrito em hexadecimal (base 16). Esta no provavelmente a forma
mais informativa para mostrar um objeto Ponto. Logo voc ir ver como mudar isso.
Como exerccio, crie e imprima um objeto Ponto, e ento use id para imprimir o identificador nico do
objeto. Traduza a forma hexadecimal para a forma decimal e confirme se so compatveis.
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.
p1 =
p1.x
p1.y
p2 =
Ponto()
= 3
= 4
Ponto()
2 Nem todos os idiomas tm este problema. Por exemplo, em alemo h palavras diferentes para diferentes sentidos de mesmo. Mesmo
carro nesse contexto seria gleiche Auto, e mesma me seria selbe Mutter.
3 XXX LR: Eu no diria que devemos usar == para verificar se dois objetos so o mesmo. Isto uma falha do livro que talvez se origine no
original que falava de Java. Em Python o operador is faz o mesmo que o == de Java: compara referncias, e portanto serve para determinar se
duas variveis apontam para o mesmo objeto. No entanto, a o cdigo acima est correto porque em Python a implemetao default de == (mtodo
__eq__) comparar o id das instncias, porm as classes list e dict, por exemplo, implementam __eq__ comparando os valores contidos (ex.: isto
retorna True: l1 = [1,2,3]; l2 = [1,2,3]; l1 == l2).
111
>>> p2.x = 3
>>> p2.y = 4
>>> p1 == p2
False
Mesmo que p1 e p2 contenham as mesmas coordenadas, os dois no representam o mesmo objeto. Se atribuirmos p1
a p2, ento as duas variveis so pseudnimos do mesmo objeto.
>>> p2 = p1
>>> p1 == p2
True
Este tipo de igualdade chamado de igualdade rasa porque ela compara somente as referncias e no o contedo dos
objetos.
Para comparar o contedo dos objetos igualdade profunda podemos escrever uma funo chamada mesmoPonto:
def mesmoPonto(p1, p2) :
return (p1.x == p2.x) and (p1.y == p2.y)
Agora se criarmos dois diferentes objetos que contm os mesmos dados, podemos usar mesmoPonto para verificar se
eles representam o mesmo ponto.
>>> p1 = Ponto()
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = Ponto()
>>> p2.x = 3
>>> p2.y = 4
>>> mesmoPonto(p1, p2)
True
claro, se as duas variveis referirem ao mesmo objeto, elas tm igualdade rasa e igualdade profunda.
E instanci-la:
box = Rectangle()
box.width = 100.0
box.height = 200.0
Este cdigo cria um novo objeto Retngulo com dois atributos ponto-flutuante. Para especificar o canto superior
esquerdo, podemos embutir um objeto dentro de um objeto!
112
box.corner = Ponto()
box.corner.x = 0.0;
box.corner.y = 0.0;
A expresso box.corner.x significa, v ao objeto referenciado por box e selecione o atributo corner; ento v ao
objeto corner e deste, selecione o atributo de nome x.
A figura mostra o estado deste objeto:
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)
Poderamos encapsular este cdigo em um mtodo e generaliza-lo para aumentar o tamanho deste retngulo em qualquer medida:
def growRect(box, dwidth, dheight) :
box.width = box.width + dwidth
box.height = box.height + dheight
113
As variveis dwidth e dheight indicam em quanto vamos aumentar o tamanho do retngulo em cada direo.
Chamando este mtodo, teramos o mesmo efeito.
Por exemplo, poderamos criar um novo Retngulo com o nome de bob e passar este nome para o mtodo growRect:
>>>
>>>
>>>
>>>
>>>
>>>
bob = Rectangle()
bob.width = 100.00
bob.height = 200.00
bob.corner.x = 0.0;
bob.corner.y = 0.0;
growRect(bob, 50, 100)
Enquanto growRect est sendo executado, o parmetro box um alias (apelido) para bob. Qualquer mudana feita
em box, tambm ir afetar bob.
Como exerccio, escreva uma function (mtodo) com o nome de moveRect que pega um Rectangle e dois parmetros
com o nome de dx e dy. Esta funo dever mudar a localizao do retngulo atravs da adio de dx coordenada
x e da adio de dy coordenada y.
import copy
p1 = Ponto()
p1.x = 3
p1.y = 4
p2 = copy.copy(p1)
p1 == p2
mesmoPonto(p1, p2)
Uma vez que importamos o modulo copy, podemos usar o mtodo copy para criar um outro Ponto. p1 e p2 no
representam o mesmo ponto, mas eles contem os mesmo dados.
Para copiar um simples objeto como um Ponto, que no contem nenhum objeto embutido, copy suficiente. Isto
eh chamado shallow copia.
Mas para um objeto como um Rectangle, que contem uma referencia para um Ponto, o mtodo copy no ir
executar corretamente a copia. Ele ir copiar a referencia para o objeto Ponto, portanto o que acontece aqui que os
dois Rectangle (o novo e o antigo) iro fazer referencia a um simples Ponto.
Em outras palavras, se criarmos um box, c1, utilizando a forma usual, e depois fazer uma copia, c2, usando o mtodo
copy, o diagrama de estado resultante ficar assim:
114
o resultado no ser o que esperamos. Neste caso, invocando growRect em um dos retngulos (c1), isto no ir
afetar o outro retngulo (c2, neste exemplo). Mas se usarmos o mtodo moveRect em qualquer um deles, isto ir
inevitavelmente afetar o outro. Este comportamento confuso e propenso a erros!
Mas felizmente o modulo copy contem um mtodo chamado deepcopy que copia no somente o objeto, mas
tambm copia todo e qualquer objeto embutido neste objeto. Por isto, voc no ficar surpreso porque este mtodo
chama-se deepcopy (copia profunda) no ? Veja como funciona:
>>> c2 = copy.deepcopy(c1)
Como exerccio, re-escreva o mtodo moveRect para ele criar e retornar um novo Rectangle ao invs de apenas
modificar o antigo.
115
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 embedded), e dos objetos embutidos nestes, e assim por diante; implementada pela funo deepcopy do mdulo
copy.
116
CAPTULO 15
Tpicos
Captulo 13: Classes e funes
13.1 Horario
13.2 Funes Puras
13.3 Modificadores
13.4 O que melhor ?
13.5 Desenvolvimento Prototipado versus Desenvolvimento Planejamento
13.6 Generalizao
13.7 Algoritmos
13.8 Glossrio
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
117
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 Horario, h1 e h2, e retorne verdadeiro (1) se h1 vem depois de h2 cronologicamente, do contrrio, retorne
falso (0).
A funo cria um novo objeto Horario, inicializa os seus atributos, e retorna uma referncia para o novo objeto. Isso
chamado de funo pura pois ela no modifica nenhum dos objetos que so passados como parmetros e no tem
nenhum efeito colateral, como imprimir um valor ou pegar entrada do usurio.
Aqui est um exemplo de como usar esta funo. Ns vamos criar dois objetos Horario: horarioAtual, que
contm o horrio atual; e horarioDoPao, que contm a quantidade de tempo que a mquina de fazer po gasta
para fazer po. Ento vamos usar somaHorario para tentar saber quando o po estar pronto. Se voc no tiver
terminado de escrever imprimirHorario ainda, de uma olhada na seo 14.2 antes de voc continuar isso:
>>>
>>>
>>>
>>>
horarioAtual = Horario()
horarioAtual.horas = 9
horarioAtual.minutos = 14
horarioAtual.segundos = 30
>>>
>>>
>>>
>>>
horarioDoPao = Horario()
horarioDoPao.horas = 3
horarioDoPao.minutos = 35
horarioDoPao.segundos = 0
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
O problema que esta funo no lida com casos onde o nmero de segundos ou minutos acrescentado em mais de
sessenta. Quando isso acontece, temos de transportar os segundos extras para a coluna dos minutos ou os minutos
extras na coluna das horas.
Aqui est a segunda verso corrigida da funo:
def somaHorario(t1, t2):
soma = Horario()
soma.horas = t1.horas + t2.horas
soma.minutos = t1.minutos + t2.minutos
soma.segundos = t1.segundos + t2.segundos
if soma.segundos >= 60:
soma.segundos = soma.segundos - 60
soma.minutos = soma.minutos + 1
if soma.minutos >= 60:
soma.minutos = soma.minutos - 60
soma.horas = soma.horas + 1
return soma
Apesar desta funo estar correta, ela est comeando a ficar grande. Depois vamos sugerir uma aproximao alternativa que rende um cdigo menor. Clique aqui para feedback
A primeira linha executa a operao bsica; o resto lida com os caso especiais que vimos antes.
Esta funo esta correta ? O que aconteceria se o parametro segundos for muito maior que sessenta ? Nesse caso, no
suficiente transportar apenas uma vez; teramos de continuar fazendo isso at que segundos seja menor que sessenta.
Uma soluo seria substituir os comando if por comandos while:
def incrementar(horario, segundos):
horario.segundos = horario.segundos + segundos
while horario.segundos >= 60:
horario.segundos = horario.segundos - 60
horario.minutos = horario.minutos + 1
119
Agora, tudo que precisamos uma maneira de converter de um inteiro para um objeto Horario:
def criarHorario(segundos):
horario = Time()
horario.horas = segundos/3600
segundos = segundos - horario.horas * 3600
120
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
121
Por outro lado, o processo de projetar algoritmos interessante, intelectualmente desafiante, e uma parte central
daquilo que chamamos programao.
Algumas das coisas que as pessoas fazem naturalmente, sem dificuldade ou conscincia, so as mais difceis de se
expressar atravs de algoritmos. Entender a linguagem natural um bom exemplo. Todos ns fazemos isso, mas
at hoje ningum conseguiu explicar como fazemos isso, pelo menos no na forma de algoritmo. Clique aqui para
feedback.
122
CAPTULO 16
Tpicos
Captulo 14: Classes e mtodos
14.1 Caractersticas da orientao a objetos
14.2 exibeHora (printTime)
14.3 Um outro exemplo
14.4 Um exemplo mais complicado
14.10 Glossrio
ATENO As referncias cruzadas a nomes em cdigos de outros captulos (especialmente 13) ainda no foram
unificadas...
Esta observao a motivao por trs dos mtodos. J temos visto alguns mtodos, tais como keys (chaves)
e values (valores), os quais foram invocados em dicionrios. Cada mtodo associado com uma classe e
intended para ser invocado em instncias daquela classe.
Mtodos so simplesmente como funes, com duas diferenas:
Mtodos so definidos dentro da definio de uma classe para tornar explcita a relao entre a classe e o mtodo.
A sintaxe para a chamada do mtodo diferente da sintaxe para a chamada de uma funo.
Nas prximas sees, vamos pegar as funes dos dois captulos anteriores e transform-las em mtodos. Esta transformao 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.
horaCorrente = Hora()
horaCorrente.horas = 9
horaCorrente.minutos = 14
horaCorrente.segundos = 30
exibeHora(horaCorrente)
Para fazer de exibeHora um mtodo, tudo o que temos a fazer mover a definio da funo para dentro da definio
da classe. Note a mudana na endentao:
class Horario:
def exibeHora(time):
print str(time.horas) + ?:? + \
str(time.minutos) + ?:? + \
str(time.segundos)
Como usual, o objeto no qual o mtodo invocado aparece antes do ponto e o nome do mtodo aparece depois do
ponto.
O objeto no qual o mtodo invocado atribudo ao primeiro parmetro, ento, neste caso, horaCorrente
atribudo ao parmetro time.
Por conveno, o primeiro parmetro de um mtodo chamado self. A razo para isto um pouco convoluted, mas
baseada numa metfora til.
A sintaxe para uma chamada de funo, exibeHora(horaCorrente), sugere que a funo um agente ativo.
Diz algo como, ?Ei, exibeHora! Aqui est um objeto para voc exibir.?
124
A transformao puramente mecnica ? movemos a definio do mtodo para dentro da definio da classe e
mudamos o nome do primeiro parmetro.
Agora podemos chamar incremento como um mtodo:
horaCorrente.incremento(500)
De novo, o objeto no qual o mtodo chamado gets atribui ao primeiro parmetro, self. O segundo parmetro,
segundo toma(gets) o valor 500.
Como um exerccio, converta ?converteParaSegundos? (da Seo 13.5) para um mtodo na classe
?Time?.
125
override (sem traducao; termo consagrado) Substituir uma definio j pronta. Exemplos incluem substituir um
parmetro padro por um argumento particular e substituir um mtodo padro, fornecendo um novo mtodo
com o mesmo nome.
mtodo de inicializao (tambem chamado de construtor) Um mtodo especial que invocado automaticamente
quando um novo objeto criado e que inicializa os atributos deste objeto.
sobrecarga de operador Estender a funcionalidade dos operadores nativos (+, -, *, >, <, etc.) de forma que eles
funcionem tambm com tipos definidos pelo usurio.
produto escalar Operao definida na lgebra linear que multiplica dois pontos (com coordenadas (x,y,z)) e retorna
um valor numrico.
multiplicao por escalar Operao definida na lgebra linear que multiplica cada uma das coordenadas de um ponto
por um valor numrico.
polimrfica Uma funo que pode operar com mais de um tipo. Se todas as operaes de uma funo pode ser
aplicadas a um certo tipo, ento a funo pode ser aplicada a este tipo.
126
CAPTULO 17
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
127
Se quisermos definir um novo objeto para representar uma carta, bvio que os atributos devem ser posicao e
naipe. No to bvio so os tipos aos quais devem pertencer os atributos. Uma possibilidade usar strings contendo
palavras como Espada para naipes e Rainha para posies. Um problema com esta implementao que no
seria fcil comparar cartas para ver qual possui o maior naipe ou posio.
Uma alternativa usar inteiros para codificar as posies e naipes. Codificar, neste caso, no significa o mesmo
que as pessoas normalmente pensam, que criptografar ou traduzir para um cdigo secreto. O que um cientista da
computao quer dizer com codificar definir um mapeamento entre uma seqncia de nmeros e os itens que eu
quero representar. Por exemplo:
Espadas -> 3
Copas -> 2
Ouros -> 1
Paus -> 0
Uma caracterstica bvia deste mapeamento que os naipes so mapeados para inteiros na ordem, de modo que ns
podemos comparar naipes pela comparao de inteiros. O mapeamento de posies bastante bvio. Cada uma das
posies numricas mapeia para o inteiro correspondente e, as cartas com figura so mapeadas conforme abaixo:
Valete -> 11
Rainha -> 12
Rei -> 13
O motivo pelo qual ns estamos usando notao matemtica para estes mapeamentos que eles no so parte do
programa Python. Eles so parte do projeto do programa, mas eles nunca aparecem explicitamente no cdigo. A
definio de classe para o tipo Carta fica parecida com esta:
class Carta:
def __init__(self, naipe=0, posicao=0):
self.naipe = naipe
self.posicao = posicao
Como sempre, ns fornecemos um mtodo de inicializao que recebe um parmetro opcional para cada atributo.
Para criar um objeto que representa o 3 de Paus, usa-se este comando:
tresDePaus = Carta(0, 3)
128
Um atributo de classe definido fora de qualquer mtodo, e ele pode ser acessado por quaisquer mtodos da classe.
Dentro de __str__, ns podemos usar listaDeNaipes e listaDePosicoes para mapear os valores numricos de naipe e posicao para strings. Por exemplo, a expresso self.listaDeNaipes[self.naipe] significa use o atributo naipe do objeto self como um ndice para o atributo de classe chamado listaDeNaipes,
e selecione a string apropriada.
O motivo para o narf no primeiro elemento em listaDePosicoes preencher o lugar do 0-simo elemento
da lista, que nunca ser usado. As nicas posies vlidas so de 1 a 13. Este item desperdiado no inteiramente
necessrio. Ns poderamos ter iniciado com 0, como normal. Porm, menos confuso codificar 2 como 2, 3 como
3, e assim por diante.
Com os mtodos que ns temos at agora, ns podemos criar e imprimir cartas:
>>> carta1 = Carta(1, 11)
>>> print carta1
Valete de Ouros
Atributos de classe como listaDeNaipes so compartilhados por todos os objetos Carta. A vantagem disso
que ns podemos usar qualquer objeto Carta para acessar os atributos de classe:
>>> carta2 = Carta(1, 3)
>>> print carta2
3 de Ouros
>>> print carta2.listaDeNaipes[1]
Ouros
A desvantagem que se ns modificarmos um atributo de classe, isso afetar cada instncia da classe. Por exemplo, se
ns decidirmos que Valete de Ouros deveria realmente se chamar Valete de Baleias Rodopiantes, ns poderamos
fazer isso:
>>> carta1.listaDeNaipes[1] = "Baleias Rodopiantes"
>>> print carta1
Valete de Baleias Rodopiantes
129
O conjunto de cartas de jogo parcialmente ordenado, o que significa que s vezes voc pode comparar cartas, e s
vezes no. Por exemplo, voc sabe que o 3 de Paus maior do que o 2 de Paus, e que o 3 de Ouros maior do que o 3
de Paus. Mas qual o melhor, o 3 de Paus ou o 2 de Ouros? Um tem uma posio maior, mas o outro tem um naipe
maior.
Para tornar as cartas comparveis, voc tem que decidir o que mais importante: posio ou naipe. Para ser honesto,
a escolha arbitrria. Por questo de escolha, ns iremos dizer que naipe mais importante, porque um baralho de
cartas novo vem ordenado com todas as cartas de Paus juntas, seguidas pelas de Ouros, e assim por diante.
Com essa deciso, ns podemos escrever __cmp__:
def __cmp__(self, other):
# verificar os naipes
if self.naipe > other.naipe: return 1
if self.naipe < other.naipe: return -1
# as cartas tm o mesmo naipe... verificar as posies
if self.posicao > other.posicao: return 1
if self.posicao < other.posicao> return -1
# as posies so iguais... um empate
return 0
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.
130
Aqui, e a partir daqui, as reticncias (...) indicam que ns omitimos os outros mtodos da classe.
Como uma alternativa a imprimirBaralho, ns poderamos escrever um mtodo __str__ para a classe
Baralho. A vantagem de __str__ que ela mais flexvel. Em vez de apenas imprimir o contedo de um
objeto, ela gera uma representao em string que outras partes do programa podem manipular antes de imprimir ou
armazenar para uso posterior.
Abaixo, uma verso de __str__ que devolve uma representao em string de um Baralho. Para adicionar um
pouco de estilo, ela distribui as cartas em uma cascata, na qual cada carta indentada um espao a mais do que a carta
anterior:
class Baralho:
...
def __str__(self):
s = ""
for i in range(len(self.cartas)):
s = s + " "*i + str(self.cartas[i]) + "\n"
return s
Este exemplo demonstra diversas caractersticas. Primeiro, em vez de percorrer self.cartas e atribuir cada carta
a uma varivel, ns estamos usando i como uma varivel de lao e um ndice para a lista de cartas.
Segundo, ns estamos usando o operador de multiplicao de strings para indentar cada carta com um espao adicional
com relao anterior. A expresso " "*i produz um nmero de espaos igual ao valor atual de i.
Terceiro, em vez de usar o comando print para imprimir as cartas, ns usamos a funo str. Passar um objeto
como um argumento para str equivale a invocar o mtodo __str__ sobre o objeto.
Finalmente, ns estamos usando a varivel s como um acumulador. Inicialmente, s a string vazia. A cada repetio
do lao, uma nova string gerada e concatenada com o valor antigo de s para obter um novo valor. Quando o lao
termina, s contm a representao em string completa do Baralho, que se parece com:
>>> baralho = Baralho()
>>> print Baralho
s de Paus
2 de Paus
3 de Paus
4 de Paus
5 de Paus
6 de Paus
7 de Paus
8 de Paus
9 de Paus
10 de Paus
Valete de Paus
Rainha de Paus
Rei de Paus
s de Ouros
E assim por diante. Mesmo que o resultado aparea em 52 linhas, uma string longa que contm newlines.
131
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.
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 igualdade com os itens da lista. Como o mtodo __cmp__ da classe Carta verifica por igualdade profunda, o mtodo
removerCarta tambm testa por igualdade profunda.
Para distribuir as cartas, ns iremos remover e devolver a carta do topo. O mtodo de lista pop fornece uma maneira
conveniente de fazer isso:
class Baralho:
...
def distribuirCarta(self):
return self.cards.pop()
132
Na verdade, pop remove a ltima carta da lista. Portanto, ns estamos realmente distribuindo as cartas do fim para o
incio do baralho.
Uma ltima operao que ns poderamos querer a funo booleana estahVazio, que retorna verdadeiro se o
baralho no contm cartas:
class Baralho:
...
def estahVazio(self):
return (len(self.cartas) == 0)
133
134
CAPTULO 18
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
135
Esse comando indica que a nova classe Mao herda da classe existente Baralho.
O construtor de Mao inicializa os atributos da mo, que so nome e cartas. A string nome identifica essa mo,
provavelmente pelo nome do jogador que est segurando as cartas. O nome um parmetro opcional com a string
vazia como valor default. cartas a lista de cartas da mo, inicializada com uma lista vazia
class Mao(Baralho):
def __init__(self, nome=""):
self.cartas = []
self.nome = nome
Em praticamente todos os jogos de cartas, necessario adicionar e remover cartas do baralho. Remover cartas j est
resolvido, uma vez que Mao herda removerCarta de Baralho. Mas precisamos escrever adicionarCarta:
class Mao(Baralho):
#...
def adicionarCarta(self,carta):
self.cartas.append(carta)
De novo, a elipse indica que omitimos outros mtodos. O mtodo de listas append adiciona a nova carta no final da
lista de cartas.
136
if self.estahVazia(): break
# interromper se acabaram as cartas
carta = self.pegarCarta()
# pegar a carta do topo
mao = maos[i % nMaos]
# quem deve receber agora?
mao.adicionarCarta(carta)
# adicionar a carta mao
O segundo parmetro, nCartas, opcional; o default um nmero grande, o que na prtica significa que todas as
cartas do baralho sero dadas se este parmetro for omitido.
A varivel do lao i vai de 0 a nCartas-1. A cada volta do lao, uma carta removida do baralho, usando o mtodo
de lista pop, que remove e retorna o ltimo item na lista.
O operador mdulo (%) permite dar cartas em ao redor da mesa (uma carta de cada vez para cada mo). Quando i
igual ao numero de mos na lista, a expresso i % nMaos volta para o comeo da lista (ndice 0).
Nao l uma grande mo, mas tem potencial para um straight flush.
Embora seja conveniente herdar os mtodos existentes, h outras informacoes num objeto Mao que podemos querer
incluir quando ao exib-lo. Para fazer isso, podemos fornecer um mtodo __str__ para a classe Mao que sobrescreva
o da classe Baralho:
class Mao(Baralho)
#...
def __str__(self):
s = "Mao " + self.nome
if self.estahVazia():
return s + " est vazia\n"
else:
return s + " contm\n" + Baralho.__str__(self)
Inicialmente, s uma string que identifica a mo. Se a mo estiver vazia, o programa acrescenta as palavras est
vazia e retorna o resultado.
Se no, o programa acrescenta a palavra contm e a representao de string do Baralho, computada pela invocao
do mtodo __str__ na classe Baralho em self.
Pode parecer estranho enviar self, que se refere Mao corrente, para um mtodo Baralho, mas isso s at voce se
lembrar que um Mao um tipo de Baralho. Objetos Mao podem fazer tudo que os objetos Baralho fazem, entao,
permitido passar uma instncia de Mao para um mtodo Baralho.
Em geral, sempre permitido usar uma instncia de uma subclasse no lugar de uma instncia de uma classe me.
137
Este o primeiro dos casos que vimos at agora em que o mtodo de inicializao realiza uma computao significativa, para alm de inicializar atributos.
Para implementar jogos especficos, podemos herdar de JogoDeCartas e adicionar caracteristicas para o novo jogo.
Como exemplo, vamos escrever uma simulao de Mico.
O objetivo do jogo livrar-se das cartas que estiverem na mo. Para fazer isso, preciso combinar cartas formando
pares ou casais que tenham a mesma cor e o mesmo nmero ou figura. Por exemplo, o 4 de paus casa com o 4
de espadas porque os dois naipes so pretos. O Valete de copas combina com o Valete de ouros porque ambos so
vermelhos.
Antes de mais nada, a Dama de paus removida do baralho, para que a Dama de espadas fique sem par. A Dama
de espadas ento faz o papel do mico. As 51 cartas que sobram so distribuidas aos jogadores em ao redor da mesa
(uma carta de cada vez para cada mo). Depois que as cartas foram dadas, os jogadores devem fazer todos os casais
possveis que tiverem na mo, e em seguida descart-los na mesa.
Quando ningum mais tiver nenhum par para descartar, o jogo comea. Na sua vez de jogar, o jogador pega uma carta
(sem olhar) do vizinho mais proximo esquerda, que ainda tiver cartas. Se a carta escolhida casar com uma carta que
ele tem na mo, ele descarta esse par. Quando todos os casais possveis tiverem sido feitos, o jogador que tiver sobrado
com a Dama de espadas na mo perde o jogo.
Em nossa simulao computacional do jogo, o computador joga todas as mos. Infelizmente, algumas nuances do
jogo presencial se perdem. Num jogo presencial, o jogador que est com o mico na mo pode usar uns truques para
induzir o vizinho a pegar a carta, por exemplo, segurando-a mais alto que as outras, ou mais baixo, ou se esforando
para que ela no fique em destaque. J o computador simplesmente pega a carta do vizinho aleatoriamente...
Comeamos fazendo uma cpia da lista de cartas, para poder percorrer a cpia enquanto removemos cartas do original.
Uma vez que self.cartas modificada no lao, no queremos us-la para controlar o percurso. Python pode ficar
bem confuso se estiver percorrendo uma lista que est mudando!
138
Para cada carta na mo, verificamos qual a carta que faz par com ela e vamos procur-la. O par da carta tem o
mesmo valor (nmero ou figura) e naipe da mesma cor. A expresso 3 - carta.naipe transforma um paus
(naipe 0) numa espadas (naipe 3) e um ouros (naipe 1) numa copas (naipe 2). Voc deve analisar a frmula at se
convencer de que as operaes opostas tambm funcionam. Se o par da carta tambem estiver na mo, ambas as cartas
so removidas.
O exemplo a seguir demonstra como usar descartarCasais:
>>> jogo = JogoDeCartas()
>>> mao = MaoDeMico("fabio")
>>> jogo.baralho.distribuir([mao], 13)
>>> print mao
mo fabio contm
s de espadas
2 de ouros
7 de espadas
8 de paus
6 de copas
8 de espadas
7 de paus
Rainha de paus
7 de ouros
5 de paus
Valete de ouros
10 de ouros
10 de copas
>>> mao.descartarCasais()
Mo fabio: 7 de espadas faz par com 7 de paus
Mo fabio: 8 de espadas faz par com 8 de paus
Mo fabio: 10 de ouros faz par com 10 de copas
>>> print mao
Mo fabio contm
s de espadas
2 de ouros
6 de copas
Rainha de paus
7 de ouros
5 de paus
Valete de ouros
Observe que no existe um mtodo __init__ para a classe MaoDeMico. Ele herdado de Mao.
139
Algumas etapas do jogo foram separadas em mtodos. removerTodosOsCasais percorre a lista de mos e invoca
descartarCasais em cada uma:
class Mico(JogoDeCartas):
#...
def removerTodosOsCasais(self):
conta = 0
for mao in self.maos:
conta = conta + mao.descartarCasais()
return conta
Como exerccio, escreva exibirMaos que percorre self.maos e exibe cada mo.
conta uma acumulador que soma o nmero de pares em cada mo e retorna o total.
Quando o nmero total de pares alcana 25, 50 cartas foram removidas das mos, o que significa que sobrou s uma
carta e o jogo chegou ao fim.
A varivel vez mantm controle sobre de quem a vez de jogar. Comea em 0 e incrementa de um em um; quando
atinge numMaos, o operador mdulo faz ela retornar para 0.
O mtodo jogarVez recebe um argumento que indica de quem a vez de jogar. O valor de retorno o nmero de
pares feitos durante essa rodada:
class Mico(JogoDeCartas):
#...
def jogarVez(self, i):
if self.maos[i].estahVazia():
return 0
vizinho = self.buscarVizinho(i)
novaCarta = self.maos[vizinho].pegarCarta()
self.maos[i].adicionarCarta(novaCarta)
print "Mao", self.maos[i].nome, "pegou", novaCarta
conta = self.maos[i].descartarCasais()
self.maos[i].embaralhar()
return conta
140
Se a mo de um jogador estiver vazia, ele est fora do jogo, ento, ele no faz nada e retorna 0.
Do contrrio, uma jogada consiste em achar o primeiro jogador esquerda que tenha cartas, pegar uma carta dele, e
tentar fazer pares. Antes de retornar, as cartas na mo so embaralhadas, para que a escolha do prximo jogador seja
aleatria.
O mtodo buscarVizinho comea com o jogador imediatamente esquerda e continua ao redor da mesa at
encontrar um jogador que ainda tenha cartas:
class Mico(JogoDeCartas):
#...
def buscarVizinho(self, i):
numMaos = len(self.maos)
for next in range(1,numMaos):
vizinho = (i + next) % numMaos
if not self.maos[vizinho].estahVazia():
return vizinho
Se buscarVizinho alguma vez circulasse pela mesa sem encontrar cartas, retornaria None e causaria um erro em
outra parte do programa. Felizmente, podemos provar que isso nunca vai acontecer (desde que o fim do jogo seja
detectado corretamente).
No mencionamos o mtodo exibirBaralhos. Esse voc mesmo pode escrever.
A sada a seguir produto de uma forma reduzida do jogo, onde apenas as 15 cartas mais altas do baralho (do 10 para
cima) foram dadas, para trs jogadores. Com esse baralho reduzido, a jogada pra depois que 7 combinaes foram
feitas, ao invs de 25:
>>> import cartas
>>> jogo = cartas.Mico()
>>> jogo.jogar(["Alice","Jair","Clara"])
---------- As cartas foram dadas
Mo Alice contm
Rei de copas
Valete de paus
Rainha de espadas
Rei de espadas
10 de ouros
Mo Jair contm
Rainha de copas
Valete de espadas
Valete de copas
Rei de ouros
Rainha de ouros
Mo Clara contm
Valete of ouros
Rei de paus
10 de espadas
10 de copas
10 de paus
Mo Jair: Dama de copas faz par com Dama de ouros
Mo Clara: 10 de espadas faz par com 10 de paus
---------- Os pares foram descartados, o jogo comea
Mo Alice contm
Rei de copas
Valete de paus
Rainha de espadas
141
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
142
CAPTULO 19
Tpicos
Captulo 17: Listas encadeadas
17.1 Referncias Embutidas
17.2 A classe No (Node)
17.3 Listas como Colees
17.4 Listas e Recorrncia
17.5 Listas Infinitas
17.6 O Teorema da Ambigidade Fundamental
17.7 Modificando Listas
17.8 Envoltrios e Ajudadores
17.9 A Classe ListaLigada
17.10 Invariantes
17.11 Glossrio
143
Como de costume, os parmetros para o mtodo de inicializao so opcionais. Por omisso (default), ambos, a carga
e a ligao, proximo, so definidas como None.
A representao string de um n simplesmente a representao string da carga. Como qualquer valor pode ser
passado para a funo str, ns podemos armazenar qualquer valor em uma lista.
Para testar a implementao at agora, ns criamos um No e o imprimimos:
>>> no = No("teste")
>>> print no
teste
Este cdigo cria trs ns, mas ns ainda no temos uma lista ainda porque os ns no esto ligados. O diagrama de
estado parecido com este:
Para ligar os ns, temos que fazer o primeiro n da lista referir ao segundo e o segundo n referir ao terceiro:
>>> no1.proximo = no2
>>> no2.proximo = no3
A referncia do terceiro n None, que indica que ele o final da lista. Agora o diagrama de estado se parece com:
144
Agora voc sabe como criar ns e lig-los em uma lista. O que pode estar menos claro neste ponto por qu.
Dentro de imprimeLista ns temos uma referncia para o primeiro n da lista, mas no h variveis que refiram
aos outros ns. Ns temos que usar o valor proximo de cada n para alcanar o prximo n.
Para percorrer uma lista ligada, comum usar uma varivel lao como no para referir a cada um dos ns sucessivamente.
Este diagrama mostra o valor de lista e os valores que no assume:
Por conveno, listas so freqentemente impressas em braquetes com vrgulas entre os elementos, como em [1, 2, 3].
Como um exerccio, modifique imprimeLista para que ela gere uma sada neste formato.
145
A primeira linha trata o caso base fazendo nada. As prximas duas linhas dividem a lista em cabeca e rabo. As
duas ltimas linhas imprimem a lista. A vrgula no final da ltima linha impede o Python de imprimir uma nova linha
aps cada n.
Ns invocamos este mtodo como invocamos o imprimeLista:
>>> imprimeDeTrasParaFrente(no1)
3 2 1
146
Aps a primeira atribuio, cabeca e lista tm o mesmo tipo e o mesmo valor. Ento por que ns criamos uma
nova varivel?
A razo que as duas variveis tm diferentes papis. Quando pensamos em cabeca, pensamos como uma referncia
a um nico n, e quando pensamos em lista o fazemos como uma referncia ao primeiro n da lista. Estes papis
no so parte do programa; eles esto na mente do programador.
Em geral no podemos dizer olhando para o programa qual o papel que uma varivel tem. Esta ambigidade pode ser
til, mas tambm pode tornar os programas difceis de serem lidos. Usamos freqentemente nomes de variveis como
no e lista para documentar como pretendemos usar uma varivel e algumas vezes criamos variveis adicionais para
remover a ambigidade.
Poderamos ter escrito imprimeDeTrasParaFrente sem cabeca e rabo, que a tornaria mais concisa mas
possivelmente menos clara:
def imprimeDeTrasParaFrente(lista):
if lista == None : return
imprimeDeTrasParaFrente(lista.proximo)
print lista,
Olhando para as duas chamadas de funo, temos que lembrar que imprimeDeTrasParaFrente trata seu argumento como uma coleo e print trata seu argumento como um objeto nico.
O teorema da ambigidade fundamental descreve a ambigidade que inerente referncia a um n:
147
Uma varivel que refere a um n pode tratar o n como um objeto nico ou como o primeiro em
uma lista de ns.
Novamente, estamos usando variveis temporrias para tornar o cdigo mais fcil de ser lido. Aqui est como usar
este mtodo:
>>>
1 2
>>>
>>>
2
>>>
1 3
imprimeLista(no1)
3
removido = removeSegundo(no1)
imprimeLista(removido)
imprimeLista(no1)
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.
148
imprimir 3, 2, mas queremos um metodo separado para imprimir os braquetes e o primeiro n. Vamos cham-lo de
imprimeDeTrasParaFrenteLegal:
def imprimeDeTrasParaFrenteLegal(lista):
print "[",
if lista != None :
cabeca = lista
rabo = lista.proximo
imprimeDeTrasParaFrente(rabo)
print cabeca,
print "]",
Novamente, uma boa idia verificar mtodos como este para ver se eles funcionam com casos especiais como uma
lista vazia ou um singleton.
Quando usamos este mtodo em algum lugar no programa, invocamos imprimeDeTrasParaFrenteLegal
diretamente,
e
ele
invoca
imprimeDeTrasParaFrente
por
ns.
Neste
sentido,
imprimeDeTrasParaFrenteLegal atua como um envoltrio, e usa imprimeDeTrasParaFrente
como um ajudador.
Uma coisa legal acerca da classe ListaLigada que ela prov um lugar natural para se colocar funes envoltrias
como imprimeDeTrasParaFrenteLegal, que podemos transformar em um mtodo da classe ListaLigada:
class ListaLigada:
...
def imprimeDeTrasParaFrente(self):
print "[",
if self.cabeca != None :
self.cabeca.imprimeDeTrasParaFrente()
print "]",
class No:
...
def imprimeDeTrasParaFrente(self):
if self.proximo != None:
rabo = self.proximo
rabo.imprimeDeTrasParaFrente()
print self.carga,
149
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?
150
envoltrio (wrapper) Um mtodo que atua como um intermedirio (middleman) entre um chamador e um mtodo
ajudador (helper), freqentemente tornando a invocao do mtodo mais fcil ou menos propensa a erros.
ajudador (helper) Um mtodo que no invocado diretamente pelo chamador (caller) mas usado por outro mtodo
para realizar parte de uma operao.
invariante (invariant) Uma assero que deveria ser verdadeira sempre para um objeto (exceto talvez enquanto o
objeto estiver sendo modificado).
151
152
CAPTULO 20
Tpicos
Captulo 18: Pilhas
18.1 Tipos abstratos de dados
18.2 O TAD Pilha
18.3 Implementando pilhas com listas de Python
18.4 Empilhando e desempilhando
18.5 Usando uma pilha para avaliar expresses ps-fixas
18.6 Anlise sinttica
18.7 Avaliando em ps-fixo.
* 18.9 Glossrio
Um objeto Stack contm um atributo chamado items que uma lista de tens na pilha. O mtodo de inicializao
define items como uma lista vazia.
Para adicionar um novo tem na pilha, push o coloca em items. Para remover um tem da pilha, pop usa o mtodo
de lista homnimo para remover e retornar um ltimo tem da lista.
Finalmente, para verificar se a pilha est vazia, isEmpty comprara items a uma lista vazia.
Uma implementao como esta, na qual os mtodos consistem de simples invocaes de mtodos existentes,
chamado revestimento. Na vida real, revestimento uma fina camada de madeira de boa qualidade usado em
XXX*furniture-making* para esconder madeira de menor qualidade embaixo. Cientistas da Computao usam esta
metfora para descrever um pequeno trecho de cdigo que esconde os detalhes de uma implementao e fornece uma
interface mais simples, ou mais padronizada.
154
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.
155
Neste caso, o delimitador o caracter de espao, ento a string dividida a cada espao.
A funo re.split mais poderosa, permitindo-nos fornecer uma expreso regular ao invs de um delimitador.
Uma expresso regular uma maneira de especificar um conjunto de strings. Por exemplo, [A-z] o conjunto de todas
as letras e [0-9] o conjunto de todos os dgitos. O operador ^nega um conunto, ento [^0-9] o conjunto de tudo o
que no nmero, que exatamente o que queremos para dividir expresses ps-fixas.
>>> import re
>>> re.split ("[^0-9]", "123+456*/")
[123, +, 456, *, , /, ]
Note que a ordem dos argumentos diferente de string.split, o delimitador vem antes da string.
A lista resultante inclui os operandos 123 e 456, e os operadores * e /. Tambm inclui duas strings vazias que so
inseridas depois dos operadores.
A primeira condio cuida de espaos e strings vazias. As duas prximas condies manipulam os operadores. Ns
assumimos, agora que qualquer coisa um operador. claro, seria melhor chegar por entrada errnea e enviar uma
mensagem de erro, mas faremos isto depois.
Vamos test-lo avaliando a forma ps-fixa de (56 + 47) * 2
>>> print evalPostfix("56 47 + 2 *")
206
156
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.
157
158
CAPTULO 21
Este captulo apresenta dois TDAs: Fila e Fila por Prioridade. Na nossa vida diria, fila um alinhamento de consumidores aguardando algum tipo de servio. Na maioria dos casos, o primeiro da fila o primeiro a ser atendido.
Mas h excees. No aeroporto, passageiros cujo vo vai decolar logo, s vezes so chamados primeiro ao balco do
check-in, mesmo que estejam no meio da fila. No supermercado, comum na fila do caixa algum deixar passar na
frente uma pessoa que chega fila s com um ou dois produtos na mo.
A regra que determina quem o prximo da fila chama-se poltica de enfileiramento. A poltica de enfileiramento
mais simples chama-se FIFO, sigla de first-in-first-out: primeiro a entrar, primeiro a sair. A poltica de enfileiramento
mais geral o enfileiramento por prioridade, em que se atribui uma prioridade a cada pessoa da fila e a que tiver maior
prioridade vai primeiro, independente da sua ordem de chegada. Dizemos que essa a poltica mais geral de todas,
porque a prioridade pode ser baseada em qualquer coisa: hora de partida do vo; quantos produtos a pessoa vai passar
pelo caixa; o grau de prestgio da pessoa. claro que nem todas as polticas de enfileiramento so justas, mas o que
justo depende do ponto de vista.
O TDA Fila e o TDA Fila por Prioridade tm o mesmo conjunto de operaes. A diferena est na semntica das operaes: a fila usa a poltica FIFO; e a fila por prioridade (como o prprio nome sugere) usa a poltica de enfileiramento
por prioridade.
159
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
160
At agora, a nica mudana o atributo last. Ele usado nos mtodos insert e remove:
class ImprovedQueue:
# ...
def insert(self, cargo):
node = Node(cargo)
node.next = None
if self.length == 0:
# if list is empty, the new node is head and last
self.head = self.last = node
else:
# find the last node
last = self.last
# append the new node
last.next = node
self.last = node
self.length = self.length + 1
Uma vez que last no perde de vista o ultimo n, no necessrio busc-lo. Como resultado, esse mtodo tem
tempo constante.
Mas essa rapidez tem preo. preciso adicionar um caso especial a remove, para configurar last para None
quando o ultimo n removido:
class ImprovedQueue:
#...
def remove(self):
cargo
= self.head.cargo
self.head = self.head.next
self.length = self.length - 1
if self.length == 0:
161
self.last = None
return cargo
Essa implementao mais complicada que a primeira, e mais difcil de se demonstrar que est correta. A vantagem
que o objetivo foi atingido tanto insert quanto remove so operaes de tempo constante.
Como exerccio, escreva uma implementao do TDA Fila usando uma lista nativa do Python. Compare
a performance dessa implementao com a de ImprovedQueue, para filas de diversos comprimentos.
O mtodo de inicializao, isEmpty, e insert so apenas uma fachada para operaes bsicas de lista. O nico
mtodo interessante remove:
class PriorityQueue:
# ...
def remove(self):
maxi = 0
for i in range(1,len(self.items)):
if self.items[i] > self.items[maxi]:
maxi = i
item = self.items[maxi]
self.items[maxi:maxi+1] = []
return item
No incio de cada iterao, maxi armazena o ndice do maior item (a prioridade mais alta de todas) que vimos at
agora. A cada volta do lao, o programa compara o i-simo item ao campeo. Se o novo item for maior, maxi recebe
o valor de i.
162
Quando o comando for se completa, maxi o ndice do maior item. Esse item removido da lista e retornado.
Vamos testar a implementao:
>>>
>>>
>>>
>>>
>>>
>>>
14
13
12
11
q = PriorityQueue()
q.insert(11)
q.insert(12)
q.insert(14)
q.insert(13)
while not q.isEmpty(): print q.remove()
Se a fila contm nmeros ou strings simples, eles so removidas em ordem numrica decrescente ou alfabtica invertida
(de Z at A). Pyhton consegue achar o maior inteiro ou string porque consegue compar-los usando os operadores de
comparao nativos.
Se a fila contm objetos de outro tipo, os objetos tm que prover um mtodo __cmp__. Quando remove usa o
operador > para comparar dois itens, o mtodo __cmp__ de um dos itens invocado, recebendo o segundo item
como argumento. Desde que o mtodo __cmp__ funcione de forma consistente, a Fila por Prioridade vai funcionar.
O mtodo __str__ usa o operador de formato para colocar nomes e pontuaes em colunas arrumadas.
Em seguida, definimos uma verso de __cmp__, ma qual a pontuao mais baixa fica com prioridade mxima. Como
sempre, __cmp__ retorna 1 se self maior que other, -1 se self menor que other, e 0 se eles so iguais.
class Golfer:
#...
def __cmp__(self, other):
if self.score < other.score: return 1
if self.score > other.score: return -1
return 0
# less is more
Agora estamos prontos para testar a fila por prioridade com a classe Golfer:
>>>
>>>
>>>
>>>
>>>
>>>
>>>
163
>>> 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.
164
CAPTULO 22
Tpicos
Captulo 20: rvores
20.1 Construindo rvores
20.2 Percorrendo rvores
20.3 rvores de expresses
20.4 Percurso de rvores
20.5 Construindo uma rvore de expresso
20.6 Manipulando erros
20.7 A rvore dos animais
20.8 Glossrio
Nota: Veja a discusso sobre o vocabulrio usado no fim da pgina.
Como listas ligadas, rvores so constitudas de clulas. Uma espcie comum de rvores a rvore binria, em
que cada clula contm referncias a duas outras clulas (possivelmente nulas). Tais referncias so chamadas de
subrvore esquerda e direita. Como as clulas de listas ligadas, as clulas de rvores tambm contm uma carga. Um
diagrama de estados para uma rvore pode aparecer assim:
165
Figura 1
166
class Tree :
def __init__(self, cargo, left=None, right=None) :
self.cargo = cargo
self.left = left
self.right = right
def __str__(self) :
return str(self.cargo)
A carga pode ser de qualquer tipo, mas os parmetros left e right devem ser clulas. left e right so
opcionais; o valor default None.
Para imprimir uma clula, imprimimos apenas a sua carga.
Uma forma de construir uma rvore de baixo para cima. Aloque os filhos primeiro:
left = Tree(2)
right = Tree(3)
O caso base a rvore vazia, que no contm nenhuma carga, logo a soma das cargas 0. O passo recursivo faz
duas chamadas recursivas para achar a soma das cargas das subrvores dos filhos. Ao finalizar a chamada recursiva,
adicionamos a carga do pai e devolvemos o valor total.
167
Figura 2
As clulas de uma rvore de expresso podem ser operandos como 1 e 2 ou operaes como + e *. As clulas
contendo operandos so folhas; aquelas contendo operaes devem ter referncias aos seus operandos. (Todos os
nossos operandos so binrios, significando que eles tem exatamente dois operandos.)
Podemos construir rvores assim:
>>> tree = Tree(+, Tree(1), Tree(*, Tree(2), Tree(3)))
Examinando a figura, no h dvida quanto ordem das operaes; a multiplicao feita primeiro para calcular o
segundo operando da adio.
rvores de expresso tem muitos usos. O exemplo neste captulo usa rvores para traduzir expresses para as notaes
psfixa, prefixa e infixa. rvores similares so usadas em compiladores para analisar sintaticamente, otimizar e
traduzir programas.
168
Em outras palavras, para imprimir uma rvore, imprima primeiro o contedo da raiz, em seguida imprima toda a
subrvore esquerda e finalmente imprima toda a subrvore direita. Esta forma de percorrer uma rvore chamada de
prordem, porque o contedo da raiz aparece antes dos contedos dos filhos. Para o exemplo anterior, a sada :
>>> tree = Tree(+, Tree(1), Tree(*, Tree(2), Tree(3)))
>>> printTree(tree)
+ 1 * 2 3
Esta notao diferente tanto da notao psfixa quanto da infixa; uma notao chamada de prefixa, em que os
operadores aparecem antes dos seus operandos.
Voc pode suspeitar que se Voc percorre a rvore numa ordem diferente, Voc produzir expresses numa notao
diferente. Por exemplo, se Voc imprime subrvores primeiro e depois a raiz, Voc ter:
def printTreePostorder(tree) :
if tree == None : return
printTreePostorder(tree.left)
printTreePostorder(tree.right)
print tree.cargo,
O parmetro level registra aonde estamos na rvore. Por default, o nvel inicialmente zero. A cada chamada
recursiva repassamos level+1 porque o nvel do filho sempre um a mais do que o nvel do pai. Cada item
indentado dois espaos por nvel. Para o nosso exemplo obtemos:
>>> printTreeIndented(tree)
3
*
2
169
+
1
Se Voc deitar a sada acima Voc enxerga uma verso simplificada da figura original.
170
J que tokenList refere a um objeto mutvel, as alteraes feitas aqui so visveis para qualquer outra varivel que
se refira ao mesmo objeto.
A prxima funo, getNumber, trata de operandos. Se o primeiro token na tokenList for um nmero ento
getNumber o remove da lista e devolve uma clula folha contendo o nmero; caso contrrio ele devolve None.
def getNumber(tokenList) :
x = tokenList[0]
if type(x) != type(0) : return None
del tokenList[0]
return Tree(x, None, None)
Antes de continuar, convm testar getNumber isoladamente. Atribumos uma lista de nmeros a tokenList,
extramos o primeiro, imprimimos o resultado e imprimimos o que resta na lista de tokens:
>>> tokenList = [9, 11, end]
>>> x = getNumber(tokenList)
>>> printTreePostorder(x)
9
>>> print tokenList
[11, end]
Em seguida precisaremos da funo getProduct, que constri uma rvore de expresso para produtos. Os dois
operandos de um produto simples so nmeros, como em 3 * 7.
Segue uma verso de getProduct que trata de produtos simples.
def getProduct(tokenList) :
a = getNumber(tokenList)
if getToken(tokenList, *) :
b = getNumber(tokenList)
return Tree(*, a, b)
else :
return a
Supondo que a chamada de getNumber seja bem sucedida e devolva uma rvore de uma s clula atribumos o
primeiro operando a . Se o prximo caractere for *, vamos buscar o segundo nmero e construir a rvore com a, b
e o operador.
Se o caractere seguinte for qualquer outra coisa, ento simplesmente devolvemos uma clula folha com a. Seguem
dois exemplos:
>>> tokenList = [9, *, 11, end]
>>> tree = getProduct(tokenList)
>>> printTreePostorder(tree)
9 11 *
O segundo exemplo sugere que ns consideramos um operando unitrio como uma espcie de produto. Esta definio
de produto talvez no seja intuitiva, mas ela ser til.
Agora tratamos produtos compostos, como 3 * 5 * 13. Encaramos esta expresso como um produto de produtos,
mais precisamente como 3 * (5 * 13). A rvore resultante :
171
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)
return Tree(*, a, b)
else :
return a
Em outras palavras, um produto pode ser um singleton ou uma rvore com * na raiz, que tem um nmero como filho
esquerdo e um produto como filho direito. Este tipo de definio recursiva devia comear a ficar familiar.
Testemos a nova verso com um produto composto:
>>>
>>>
>>>
2 3
A seguir adicionamos o tratamento de somas. De novo, usamos uma definio de soma que ligeiramente no
intuitiva. Para ns, uma soma pode ser uma rvore com + na raiz, que tem um produto como filho esquerdo e uma
soma como filho direito. Ou, uma soma pode ser simplesmente um produto.
Se Voc est disposto a brincar com esta definio, ela tem uma propriedade interessante: podemos representar qualquer expresso (sem parntesis) como uma soma de produtos. Esta propriedade a base do nosso algoritmo de anlise
sinttica.
getSum tenta construir a rvore com um produto esquerda e uma soma direita. Mas, se ele no encontra uma +,
ele simplesmente constri um produto.
def getSum(tokenList) :
a = getProduct(tokenList)
if getToken(tokenList, +) :
b = getSum(tokenList)
return Tree(+, a, b)
172
else :
return a
Quase terminamos, mas ainda temos que tratar dos parntesis. Em qualquer lugar numa expresso onde podemos
ter um nmero, podemos tambm ter uma soma inteira envolvida entre parntesis. Precisamos, apenas, modificar
getNumber para que ela possa tratar de subexpresses:
def getNumber(tokenList) :
if getToken(tokenList, () :
x = getSum(tokenList)
# get subexpression
getToken(tokenList, ))
# eat the closing parenthesis
return x
else :
x = tokenList[0]
if type(x) != type(0) : return None
tokenList[0:1] = []
# remove the token
return Tree(x, None, None)
# return a leaf with the number
O comando raise cria uma exceo; neste caso criamos um novo tipo de exceo, chamada de
BadExpressionError. Se a funo que chamou getNumber, ou uma das outras funes no traceback, manipular a exceo, ento o programa pode continuar. caso contrrio Python vai imprimir uma mensagem de erro e
terminar o processamento em seguida.
A ttulo de exerccio, encontre outros locais nas funes criadas onde erros possam ocorrer e adiciona
comandos raise apropriados. Teste seu cdigo com expresses mal formadas.
22.6. 20.6 Manipulando erros
173
No comeo de cada rodada, o programa parte do topo da rvore e faz a primeira pergunta. Dependendo da resposta,
ele segue pelo filho esquerdo ou direito e continua at chegar numa folha. Neste ponto ele arrisca um palpite. Se o
palpite no for correto, ele pergunta ao usurio o nome de um novo animal e uma pergunta que distingue o palpite
errado do novo animal. A seguir, adiciona uma clula rvore contendo a nova pergunta e o novo animal.
174
A funo yes um auxiliar; ele imprime um prompt e em seguida solicita do usurio uma entrada. Se a resposta
comear com y ou Y, a funo devolve um valor verdadeiro:
def yes(ques) :
from string import lower
ans = lower(raw_input(ques))
return (ans[0:1] == y)
A condio do lao externo 1, que significa que ele continuar at a execuo de um comando break, caso o
usurio no pense num animal.
O lao while interno caminha na rvore de cima para baixo, guiado pelas respostas do usurio.
Quando uma nova clula adicionada rvore, a nova pergunta substitui a carga e os dois filhos so o novo animal e
a carga original.
Uma falha do programa que ao sair ele esquece tudo que lhe foi cuidadosamente ensinado!
175
A ttulo de exerccio, pense de vrias jeitos para salvar a rvore do conhecimento acumulado num arquivo. Implemente aquele que Voc pensa ser o mais fcil.
176
CAPTULO 23
Apndice A: Depurao
Tpicos
Apndice A: Depurao
A.1 Erros de sintaxe
* A.1.1 Eu no consigo fazer meu programa executar no importa o que eu faa
A.2 Erros de tempo de execuo
* A.2.1 Meu programa no faz absolutamente nada
* A.2.2 Meu programa trava
Lao Infinito
Recurso Infinita
Fluxo de Execuo
A.2.3
Quando eu executo o programa, recebo uma exceo
*
A.2.4
Eu adicionei tantas declaraes print que a sada do programa ficou bagunada
*
A.3 Erros de semntica
* A.3.1 Meu programa no funciona
* A.3.2 Eu tenho uma grande expresso cabeluda e ela no faz o que eu espero
* A.3.3 Eu tenho uma funo ou mtodo que no retorna o que eu espero
* A.3.4 Eu estou empacado mesmo e eu preciso de ajuda
* A.3.5 No, eu preciso mesmo de ajuda
Diferentes tipos de erros podem acontecer em um programa, e til distinguir entre eles para os localizar mais
rapidamente:
Erros de sintaxe so produzidos por Python quando o interpretador est traduzindo o cdigo fonte em bytecode.
Estes erros geralmente indicam que existe algo errado com a sintaxe do programa. Exemplo: Omitir o sinal de
dois pontos (:) no final de uma declarao def produz a mensagem um tanto redundante SintaxError:
invalid sintax (Erro de sintaxe: sintaxe invlida).
Erros de tempo de execuo so produzidos se algo de errado acontece enquanto o programa est em execuo.
A maioria das mensagens de tempo de execuo incluem informao sobre onde o erro ocorreu e que funo
estava em execuo. Exemplo: Uma recurso infinita eventualmente causa um erro em tempo de execuo identificado como maximum recursion depth exceeded (Excedida a mxima profundidade de recurso).
Erros de semntica, chamado por alguns autores de erros de lgica, so problemas com um programa que
compila e executa mas no tem o resultado esperado. Exemplo: Uma expresso pode no ser avaliada da forma
que voc espera, produzindo um resultado inesperado.
177
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.
178
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.
0:
x
y
179
Agora, quando voc executar o programa, sero exibidas trs linhas de sada para cada execuo do lao. Na ltima
execuo do lao, a condio deveria ser False (falso). Se o lao continuar, voc ter condies de ver os valores de
x e y, podendo, assim, descobrir o porqu das variveis no serem atualizadas corretamente.
Recurso Infinita
Na maioria das vezes, uma recurso infinita far com que um programa execute por um determinado tempo e ento
produza um erro de Maximum recursion depth exceeded (Excedida a profundidade mxima de recurso).
Se voc suspeita que uma funo ou mtodo est causando uma recurso infinita, comece verificando para se assegurar
que exista um caso bsico. Em outras palavras, deve existir alguma condio que faa com que a funo ou mtodo
finalize sem fazer uma chamada recursiva. Se no existe tal condio, voc precisa repensar o algoritmo e identificar
um caso base.
Se existe um caso base mas o programa parece no estar alcanando-o, adicione uma declarao print no incio
da funo ou mtodo que imprime o(s) parmetro(s). Agora, quando voc executar o programa, voc ver umas
poucas linhas de sada todas as vezes que a funo ou mtodo for executado, e voc ver o(s) parmetro(s). Se o(s)
parmetro(s) no est(o) se movendo em direo ao caso base, voc ter ideias de por que no, e poder ento corrigir
o problema.
Fluxo de Execuo
Se voc no est certo de como o seu programa est fluindo, adicione declaraes print ao incio de cada funo
com uma mensagem semelhante a entrando na funo foo, onde foo o nome da funo.
Agora quando voc executar o programa, ser exibido um rastro de cada funo medida em que ela invocada.
180
KeyError (Erro de Chave): Voc est tentando acessar um elemento de um dicionrio utilizando um valor de chave
que o dicionrio no contm.
AttributeError (Erro de Atributo): Voc est tentando acessar um atributo ou mtodo que no existe em um objeto.
IndexError (Erro de ndice): O ndice que voc est usando para acessar uma lista, string ou tupla no existe
no objeto, ou seja, maior que seu comprimento menos um. Imediatamente antes do ponto do erro, adicione uma
delarao print para mostrar o valor do ndice e o comprimento do objeto. O objeto do tamanho correto? O ndice
est com o valor adequado?
23.2.4 A.2.4 Eu adicionei tantas declaraes print que a sada do programa ficou
bagunada
Um dos problemas com o uso de declaraes print para a depurao que a sada pode ficar confusa, dificultando a
depurao, ao invs de facilitar. H duas coisas que podem ser feitas: simplificar a sada ou simplificar o programa.
Para simplificar a sada, voc pode remover ou comentar as declaraes print que no esto ajudando, ou combin-las,
ou, ainda, formatar a sada para facilitar o entendimento.
Para simplificar o programa, existem vrias coisas que voc pode fazer: Primeiro, reduza o problema no qual o
programa est trabalhando. Por exemplo, se voc est ordenando um array, ordene um * array* pequeno. Se o
programa recebe entrada do usurio, d a ele a entrada mais simples capaz de causar o problema.
Segundo, limpe o programa. Remova cdigo intil e reorganize o programa para torn-lo to fcil de ler quanto
possvel. Por exemplo, se voc suspeita que o problema est numa parte profundamente aninhada do programa, tente
reescrever aquela parte com uma estrutura mais simples. Se voc suspeita de uma funo longa, tente dividi-la em
funes menores e test-las separadamente.
Muitas vezes o processo de encontrar o caso de teste mnimo leva voc ao erro. Se voc descobrir que o programa
funciona em uma situao, mas no em outra, voc j tem uma boa dica a respeito do que est acontecendo.
De forma semelhante, reescrever pedaos de cdigo pode ajuda a encontrar erros sutis. Se voc faz uma alterao que
voc pensa que no afeta o programa, e ela afeta, voc tambm tem uma dica.
181
No est acontecendo alguma coisa que no deveria acontecer? Encontre o cdigo no seu programa que executa
a funo e veja se ele est executando no momento errado ou de forma errada.
Uma parte do cdigo est produzindo o efeito esperado? Cetifique-se que voc entende o cdigo em questo,
especialmente se ele envolve chamadas de funes ou mtodos em outros mdulos da linguagem. Leia a documentao das funes e mdulos que voc est utilizando. Teste as funes escrevendo casos simples de teste e
verificando os resultados.
Para programar, voc precisa ter um modelo mental de como seus programas trabalham. Se voc escreve um programa
que no faz aquilo que voc espera, muito comum que o problema no esteja no programa, mas sim no seu modelo
mental.
A melhor maneira de corrigir seu modelo mental quebrar o programa em seus componentes (geralmente as funes
e mtodos) e testar cada componente de forma independente. Uma vez que voc tenha encontrado a diferena entre
seu modelo e a realidade, voc pode resolver o problema.
Obviamente, componentes devem ser desenvolvidos e testado medida que o seu programa vai ganhando vida. Se
voc encontra um problema, haver uma pequena quantidade de novo cdigo com funcionamento incerto.
23.3.2 A.3.2 Eu tenho uma grande expresso cabeluda e ela no faz o que eu espero
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())
A verso explcita mais fcil de ler, pois os nomes das variveis fornecem documentao adicional, e mais fcil
depurar, j que voc pode verificar os tipos das variveis intermedirias e mostrar seus valores.
Um outro problema que pode ocorrer com expresses longas que a ordem de avaliao pode no ser o que voc
espera. Por exemplo, se voc est traduzido a expresso x / 2pi (XXX fazer a equao matemtica) para Python, voc
poderia escrever:
>>> y = x / 2 * math.pi
Isto est correto por que a multiplicao e a diviso possuem a mesma precedncia e so avalidadas da esquerda pra
direita. Ento a expresso calcula *x*pi/2 (XXX fazer a equao matemtica).
Uma boa maneira de depurar expresses adicionar parnteses para tornar a ordem de avaliao explcita:
>>> y = x / (2 * math.pi)
Sempre que voc no estiver seguro sobe a ordem de avaliao, utilize parnteses. No apenas o programa estar
correto(no sentido de fazer aquilo que voc tinha a inteno), ele tambm ser mais legvel por outras pessoas que no
tenham memorizado as regras de precedncia.
182
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()
def pega_encontrados(self):
qtEncontrados = self.mao[i].devolveEncontrados()
return qtEncontrados
183
Lembre-se, o objetivo no apenas fazer o programa funcionar. O objetivo aprender como fazer o programa funcionar.
184
CAPTULO 24
Tpicos
Apndice B: Criando um novo tipo de dado
B.1 Multiplicao de fraes
B.2 Soma de fraes
B.3 Simplificando fraes: O algoritmo de Euclides
B.4 Comparando fraes
B.5 Indo mais alm...
* B.5.1 Exerccio
B.6 Glossrio
Em linguagens com suporte orientao a objetos, programadores podem criar novos tipos de dados que se comportam
de forma semelhante aos tipos de dados built-in. Vamos explorar esse recurso criando uma classe chamada Fracao.
Esta classe ter comportamento muito semelhante aos tipos numricos da linguagem: int, long e float.
Fraes, tambm conhecidas como nmeros racionais, so valores que podem ser expressos como uma razo de dois
nmeros inteiros, por exemplo, 5/6. No exemplo fornecido, o 5 representa o numerador, o nmero que fica em cima,
que dividido, e o 6 representa o denominador, o nmero que fica embaixo, pelo qual a diviso feita. A frao 5/6
pode ser lida cinco dividido por seis.
O primeiro passo definir a classe Fracao com o mtodo __init__ que recebe como parmetros o numerador e o
denominador, sendo ambos do tipo int:
class Fracao:
def __init__(self, numerador, denominador=1):
self.numerador = numerador
self.denominador = denominador
A passagem do denominador opcional. Uma Fracao com apenas um parmetro representa um nmero inteiro. Sendo
o numerador n, a frao construda ser n/1.
O prximo passo escrever o mtodo __str__ que exibe as fraes corretamente: a forma numerador/denominador.
class Fracao:
...
185
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
O mtodo funciona, mas pode ser aprimorado! Podemos melhorar o mtodo visando possibilitar a multiplicao de
uma frao por um inteiro. Usaremos a funo isinstance para verificar se o objeto other um inteiro, para em
seguida convert-lo em uma frao.
class Fracao:
...
def __mul__(self, other):
if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador * other.numerador,
self.denominador * ohter.denominador)
Agora conseguimos multiplicar funes por inteiros, mas s se a frao estiver esquerda do operador *. Vejamos um
exemplo em que nossa multiplicao funciona e outro no qual ela no funciona:
>>> print Fracao(5, 6) * 4
20/6
>>> print 4 * Fracao(5, 6)
TypeError: __mul__ nor __rmul__ defined for these operands
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.
Os dois primeiros exemplos chamam o mtodo __add__, enquanto o ltimo exemplo chama o mtodo __radd__.
187
De forma geral, sempre que um objeto do tipo Fracao for criado, a frao deve ser simplificada, atravs da diviso
do numerador e do denominador pelo seu MDC. Quando a frao j est em sua forma mais simples, o MDC vale 1.
Euclides de Alexandria (aprox. 325 a. C. 365 a. C.) desenvolveu um algoritmo para encontrar o MDC de dois
inteiros m e n:
Se n mltiplo de m, ento n o MDC. Caso contrrio, o MDC o MDC de n e o resto da diviso de m
por n.
Esta definio recursiva pode ser representada de forma concisa pela funo:
def mdc(m, n):
if m % n == 0:
return n
else:
return mdc(n, m % n)
Na primeira linha da funo, utilizamos o operador de mdulo para checar se m divisvel por n. Na ltima linha,
usamos o mesmo operador para obter o resto da diviso de m por n.
J que todas as operaes que escrevemos criam um novo objeto do tipo Fracao, podemos utilizar a funo mdc no
mtodo __init__ de nossa classe:
class Fracao:
def __init__(self, numerador, denominador=1):
m = mdc(numerador, denominador)
self.numerador = numerador / m
self.denominador = denominador / m
Sempre que o denominador negativo, o sinal negativo deve passar para o numerador. O interessante que, ao usarmos
o Algoritmo de Euclides, esta operao ocorre de forma transparente.
Antes de seguirmos para o prximo passo, vamos ver como est nossa classe Fracao completa?
class Fracao:
def __init__(self, numerador, denominador=1):
m = mdc(numerador, denominador)
self.numerador = numerador / m
self.denominador = denominador / m
def __str__(self):
return "%d/%d" %(self.numerador, self.denominador)
def __mul__(self, other):
if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador * other.numerador,
self.denominador * ohter.denominador)
__rmul__ = __mul__
def __add__(self, other):
if isinstance(other, int):
other = Fracao(other)
return Fracao(self.numerador
* other.denominador +
self.denominador * other.numerador,
188
self.denominador * other.denominador)
__radd__ = __add__
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.
189
190
CAPTULO 25
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
191
Banco de dados so como super arquivos, que armazenam dados em esquemas predefinidos, e mantm relaes
entre itens de dados que lhe permitem acessar os dados de vrias formas. Python tem vrios mdulos que
possibilitam ao usurio conectar seus programas a diversos sistemas gerenciadores de banco de dados, tanto
sistemas livres (Open source) quanto sistemas comerciais.
A programao multitarefa (multithread) permite que voc execute vrias tarefas (threads) dentro de um nico
programa. Se voc j teve a experincia de usar um navegador web para se deslocar por uma pgina web
enquanto o navegador ainda est carregando ela, ento voc j tem uma ideia do que da pra fazer usando a
programao multitarefa.
Quando o desempenho primordial, voc pode escrever extenses para o Python em linguagens compiladas,
como C e C++. Este abordagem vastamente utilizada na biblioteca padro do Python, formando a sua base.
O mecanismo de ligao de dados e funes um pouco complexo. Existe uma ferramenta, chamada SWIG
(Simplified Wrapper and Interface Generator), que faz este processo de ligao ser mais simples.
192
193
194
CAPTULO 26
Coligi aqui os links para tradues da Licensa Pblica GNU fornecidos pelo professor Imre Simon:
http://creativecommons.org/licenses/GPL/2.0/legalcode.pt
http://www.magnux.org/doc/GPL-pt_BR.txt
http://www.ead.unicamp.br/minicurso/bw/texto/fdl.pt.html (esta no consegui abrir...)
Encontrei tambm uma reproduo neste texto em pdf, alis sobre o incentivo do governo ao uso do Software Livre:
http://www.inf.ufpr.br/info/techrep/RT_DINF004_2002.pdf.gz
Parecem haver pequenas discrepncias entre as vrias tradues, mas acho que deveramos escolher uma para publicar
aqui como referncia.
195
196
CAPTULO 27
genindex
modindex
search
197