Sei sulla pagina 1di 98

Como pensar como um cientista da

Como pensar como um cientista da


Computao usando Python
Computao usando Python
A//en Dawney A//en Dawney
Jeqrey E/kner Jeqrey E/kner
Chr/s Meyers Chr/s Meyers
Tradaa: Eqa/pe da prajeta Tradaa: Eqa/pe da prajeta http://pensarpythan./ncabadara.fapesp.br http://pensarpythan./ncabadara.fapesp.br
Ed/a: Cr//ssan Ga/d/na Ed/a: Cr//ssan Ga/d/na
Como pensar como um cientista da Computao usando Python
Copyright (c) 2002 Allen Downey, Jefrey Elkner, and Chris Meyers.
Edited by Shannon Turlington and Lisa Cutler. Cover design by Rebecca
Gimenez.
Printing history:
April 2002: First edition.
Green Tea Press
1 Grove St.
P.O. Box 812901
Wellesley, MA 02482
Permission is granted to copy, distribute, and/or modify this document under the
terms of the GNU Free Documentation License, Version 1.1 or any later version
published by the Free Software Foundation; with the Invariant Sections being
Foreword, Preface, and Contributor List, with no Front-Cover Texts, and
with no BackCover Texts. A copy of the license is included in the appendix
entitled GNU Free Documentation License.
The GNU Free Documentation License is available from www.gnu.org or by
writing to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307, USA.
Como pensar como um cientista da Computao usando Python
Verso atual: 1.0
Data de Publicao: 16 de janeiro de 2008
Classificao: Tutorial
Autor: Jeffrey Elkner (traduzido pelo projeto Pensar Python -
http://pensarpython.incubadora.fapesp.br)
Publicao: Cyaneus.net
#2
Como pensar como um cientista da Computao usando Python
ndice ndice
Foreword........................................... .........................5
Apresentao.................................................. ............6
Preface......................................................... ...............7
How and why I came to use Python...............................7
Finding a textb o ok........................................................7
Intro ducing programming with Python.........................7
Building a community.....................................................8
Prefcio................................................................... ....9
Como e porque eu vim a usar Python.............................9
Encontrando um livro texto............................................9
Introduzindo programao com Python.......................10
Construindo uma comunidade......................................10
Contributor List...................................................... ..11
Verso Brasileira.....................................................13
Captulo 1: O caminho do programa......................14
1.1 A linguagem de programao Python....................14
1.2 O que um programa?............................................15
1.3 O que depurao (debugging)?............................15
1.3.1 Erros de sintaxe.........................................15
1.3.2 Erros em tempo de execuo (runtime errors)
........................................................................ ....15
1.3.3 Erros de semntica.....................................15
1.3.4 Depurao experimental (Debugging)........16
1.4 Linguagens naturais e linguagens formais.............16
1.5 O primeiro programa...............................................17
1.6 Glossrio.................................................................17
Captulo 2: Variveis, expresses e comandos......18
2.1 Valores e tipos.........................................................18
2.2 Variveis.................................................................18
2.3 Nomes de variveis e palavras reservadas..............18
2.4 Comandos................................................................19
2.5 Avaliando expresses..............................................19
2.6 Operadores e operandos..........................................19
2.7 Ordem dos operadores............................................20
2.8 Operaes com strings............................................20
2.9 Composio.............................................................20
2.11 Glossrio...............................................................20
Captulo 3: Funes.................................. ...............22
3.1 Chamadas de funes..............................................22
3.2 Converso entre tipos..............................................22
3.3 Coero entre tipos.................................................22
3.4 Funes matemticas..............................................22
3.5 Composio.............................................................23
3.6 Adicionando novas funes....................................23
3.7 Definies e uso......................................................24
3.8 Fluxo de execuo...................................................24
3.9 Parmetros e argumentos........................................24
3.10 Variveis e parmetros so locais.........................25
3.11 Diagramas da pilha...............................................25
3.12 Funes com resultados........................................25
3.13 Glossrio...............................................................26
Captulo 4: Condicionais e recursividade...............27
4.1 O operador mdulo.................................................27
4.2 Expresses booleanas..............................................27
4.3 Operadores lgicos..................................................27
4.4 Execuo condicional.............................................27
4.5 Execuo alternativa...............................................28
4.6 Condicionais encadeados........................................28
4.7 Condicionais aninhados..........................................28
4.8 A instruo return....................................................28
4.9 Recursividade..........................................................29
4.10 Diagramas de pilha para funes recursivas........29
4.11 Recursividade infinita...........................................30
4.12 Entrada pelo teclado..............................................30
4.13 Glossrio...............................................................30
Captulo 5: Funes frutferas.................................31
5.1 Valores de retorno...................................................31
5.2 Desenvolvimento de programas.............................31
5.3 Composio.............................................................32
5.4 Funes booleanas..................................................32
5.5 Mais recursividade..................................................33
5.6 Voto de confiana (Leap of faith)...........................33
5.7 Mais um exemplo....................................................34
5.8 Checagem de tipos..................................................34
5.9 Glossrio.................................................................34
Captulo 6: Iterao.................................................36
6.1 Reatribuies...........................................................36
6.2 O comando while....................................................36
6.3 Tabelas....................................................................37
6.4 Tabelas de duas dimenses (ou bi-dimensionais). .38
6.5 Encapsulamento e generalizao............................38
6.6 Mais encapsulamento..............................................38
6.7 Variveis locais.......................................................38
6.8 Mais generalizao..................................................39
6.9 Funes...................................................................39
6.10 Glossrio...............................................................40
Captulo 7: Strings................................... ................41
7.1 Um tipo de dado composto.....................................41
7.2 Comprimento..........................................................41
7.3 Travessia e o loop for..............................................41
7.4 Fatias de strings.......................................................42
7.5 Comparao de strings............................................42
7.6 Strings so imutveis..............................................42
7.7 Uma funo find (encontrar)...................................42
7.8 Iterando e contando.................................................43
7.9 O mdulo string......................................................43
7.10 Classificao de caracteres...................................43
7.11 Glossrio...............................................................43
7.11 Glossrio2.............................................................44
Captulo 8: Listas......................................... ............45
8.1 Valores da lista........................................................45
8.2 Acessado elementos................................................45
8.3 Comprimento da lista..............................................45
8.4 Membros de uma lista.............................................46
8.5 Listas e laos for.....................................................46
8.6 Operaes em listas.................................................46
8.7 Fatiamento de listas.................................................46
8.8 Listas so mutveis.................................................46
8.9 Remoo em lista....................................................47
8.10 Ojetos e valores.....................................................47
8.11 Apelidos................................................................47
8.12 Clonando listas......................................................48
8.13 Lista como parmetro...........................................48
8.14 Lista aninhadas......................................................48
8.15 Matrizes.................................................................48
8.16 Strings e listas.......................................................49
8.17 Glossrio...............................................................49
Captulo 9: Tuplas................................................... .50
#3
Como pensar como um cientista da Computao usando Python
9.1 Mutabilidade e tuplas..............................................50
9.2 Atribuies de tupla................................................50
9.3 Tuplas como valores de retorno..............................50
9.4 Nmeros aleatrios.................................................50
9.5 Lista de nmeros aleatrios....................................51
9.6 Contando.................................................................51
9.7 Vrios intervalos.....................................................51
9.8 Uma soluo em um s passo.................................52
9.9 Glossrio.................................................................52
Captulo 10: Dicionrios.........................................54
10.1 Operaes dos Dicionrios...................................54
10.2 Mtodos dos Dicionrios......................................54
10.3 Aliasing (XXX) e Copiar......................................55
10.4 Matrizes Esparsas..................................................55
10.5 Hint........................................................................55
10.6 Inteiros Longos.....................................................56
10.7 Contando Letras....................................................56
10.8 Glossrio...............................................................56
Captulo 11: Arquivos e excees..........................58
Arquivos e excees......................................................58
11.1 Arquivos texto.......................................................58
11.2 Gravando variveis...............................................59
11.3 Diretrios...............................................................60
11.4 Pickling.................................................................60
11.5 Excees................................................................60
11.6 Glossrio...............................................................61
Captulo 12: Classes e objetos................................62
12.1 Tipos compostos definidos pelo usurio..............62
12.2 Atributos................................................................62
12.3 Instncias como parmetros..................................63
12.4 O significado de "mesmo"....................................63
12.5 Retngulos.............................................................63
12.6 Instancias como valores retornados......................64
12.7 Objetos so mutveis............................................64
12.8 Copiando...............................................................64
12.9 Glossrio...............................................................65
Captulo 13: Classes e funes................................ 66
13.1 Horario..................................................................66
13.2 Funes Puras.......................................................66
13.3 Modificadores.......................................................66
13.4 O que melhor ?...................................................67
13.5 Desenvolvimento Prototipado versus
Desenvolvimento Planejado.........................................67
13.6 Generalizao........................................................67
13.7 Algoritmos.............................................................68
13.8 Glossrio...............................................................68
Captulo 14: Classes e mtodos..............................69
14.1 Caractersticas da orientao a objetos.................69
14.2 exibeHora (printTime)..........................................69
14.3 Um outro exemplo................................................70
14.10 Glossrio.............................................................70
Captulo 15: Conjuntos de objetos..........................71
15.1 Composio...........................................................71
15.2 Objetos Carta.........................................................71
15.3 Atributos de classe e o mtodo __str__................71
15.4 Comparando cartas................................................72
15.5 Baralhos.................................................................72
15.6 Imprimindo o baralho...........................................72
15.7 Embaralhando.......................................................73
15.8 Removendo e distribuindo cartas.........................73
15.9 Glossrio...............................................................74
Capitulo 16: Herana.................................. .............75
16.1 Herana.................................................................75
16.2 Uma mo de cartas................................................75
16.3 Dando as cartas.....................................................75
16.4 Exibindo a mao.....................................................76
16.5 A classe JogoDeCartas..........................................76
16.6 Classe MaoDeMico...............................................76
16.7 Classe Mico...........................................................77
16.8 Glossrio...............................................................78
Captulo 17: Listas encadeadas...............................79
17.1 Referncias Embutidas.........................................79
17.2 A classe No (Node)...............................................79
17.3 Listas como Colees...........................................79
17.4 Listas e Recorrncia..............................................80
17.5 Listas Infinitas.......................................................80
17.6 O Teorema da Ambigidade Fundamental...........80
17.7 Modificando Listas...............................................81
17.8 Envoltrios e Ajudadores......................................81
17.9 A Classe ListaLigada............................................81
17.10 Invariantes...........................................................82
17.11 Glossrio.............................................................82
Captulo 18: Pilhas................................................ ...83
18.1 Tipos abstratos de dados.......................................83
18.2 O TAD Pilha.........................................................83
18.3 Implementando pilhas com listas de Python........83
18.4 Empilhando e desempilhando...............................83
18.5 Usando uma pilha para avaliar expresses ps-
fixas...............................................................................84
18.6 Anlise sinttica....................................................84
18.7 Avaliando em ps-fixo..........................................84
18.8 Clientes de fornecedores.......................................84
18.9 Glossrio...............................................................85
Captulo 19: Filas................................................ .....86
19.1 Um TDA Fila........................................................86
19.2 Fila encadeada.......................................................86
19.3 Caractersticas de performance.............................86
19.4 Fila encadeada aprimorada...................................86
19.5 Fila por prioridade.................................................87
19.6 A classe Golfer......................................................88
19.7 Glossrio...............................................................88
Captulo 20: rvores...............................................89
20.1 Construindo rvores..............................................89
20.2 Percorrendo rvores..............................................89
20.3 rvores de expresses...........................................89
20.4 Percurso de rvores...............................................90
20.5 Construindo uma rvore de expresso..................90
20.6 Manipulando erros................................................92
20.7 A rvore dos animais............................................92
20.8 Glossrio...............................................................93
GNU Free Documentation License.........................94
0. PREAMBLE ............................................................94
1. APPLICABILITY AND DEFINITIONS ................94
2. VERBATIM COPYING ..........................................95
3. COPYING IN QUANTITY .....................................95
4. MODIFICATIONS ..................................................95
5. COMBINING DOCUMENTS .................................96
6. COLLECTIONS OF DOCUMENTS ......................96
7. AGGREGATION WITH INDEPENDENT WORKS .
96
8. TRANSLATION ......................................................96
9. TERMINATION ......................................................96
10. FUTURE REVISIONS OF THIS LICENSE.........96
How to use this License for your documents.......96
#4
Como pensar como um cientista da Computao usando Python
Foreword Foreword
By David Beazley
As an educator, researcher, and book author, I
am delighted to see the completion of this book. Python is a
fun and extremely easy-to-use programming language that has
steadily gained in popularity over the last few years.
Developed over ten years ago by Guido van Rossum,
Python`s simple syntax and overall feel is largely derived
from ABC, a teaching language that was developed in the
1980`s. However, Python was also created to solve real
problems and it borrows a wide variety of features from
programming languages such as C++, Java, Modula-3, and
Scheme. Because of this, one of Python`s most remarkable
features is its broad appeal to professional software
developers, scientists, researchers, artists, and educators.
Despite Python`s appeal to many diferent
communities, you may still wonder why Python? or why
teach programming with Python? Answering these questions
is no simple task-especially when popular opinion is on the
side of more masochistic alternatives such as C++ and Java.
However, I think the most direct answer is that programming
in Python is simply a lot of fun and more productive.
When I teach computer science courses, I want
to cover important concepts in addition to making the material
interesting and engaging to students. Unfortunately, there is a
tendency for introductory programming courses to focus far
too much attention on mathematical abstraction and for
students to be come frustrated with annoying problems related
to low-level details of syntax, compilation, and the
enforcement of seemingly arcane rules. Although such
abstraction and formalism is important to professional
software engineers and students who plan to continue their
study of computer science, taking such an approach in an
introductory course mostly succeeds in making computer
science boring. When I teach a course, I don`t want to have a
room of uninspired students. I would much rather see them
trying to solve interesting problems by exploring diferent
ideas, taking unconventional approaches, breaking the rules,
and learning from their mistakes. In doing so, I don`t want to
waste half of the semester trying to sort out obscure syntax
problems, unintelligible compiler error messages, or the
several hundred ways that a program might generate a general
protection fault.
One of the reasons why I like Python is that it
provides a really nice balance between the practical and the
conceptual. Since Python is interpreted, beginners can pick up
the language and start doing neat things almost immediately
without getting lost in the problems of compilation and
linking. Furthermore, Python comes with a large library of
modules that can be used to do all sorts of tasks ranging from
web-programming to graphics. Having such a practical focus
is a great way to engage students and it allows them to
complete significant pro jects. However, Python can also
serve as an excellent foundation for introducing important
computer science concepts. Since Python fully supports
procedures and classes, students can be gradually introduced
to topics such as procedural abstraction, data structures, and
ob ject-oriented programming-all of which are applicable to
later courses on Java or C++. Python even borrows a number
of features from functional programming languages and can
be used to introduce concepts that would be covered in more
detail in courses on Scheme and Lisp.
In reading Jefrey`s preface, I am struck by his
comments that Python allowed him to see a higher level of
success and a lower level of frustration and that he was able
to move faster with better results. Although these comments
refer to his introductory course, I sometimes use Python for
these exact same reasons in advanced graduate level computer
science courses at the University of Chicago. In these courses,
I am constantly faced with the daunting task of covering a lot
of dimcult course material in a blistering nine week quarter.
Although it is certainly possible for me to infict a lot of pain
and sufering by using a language like C++, I have often
found this approach to be counterproductive- especially
when the course is about a topic unrelated to just
programming. I fnd that using Python allows me to better
focus on the actual topic at hand while allowing students to
complete substantial class pro jects.
Although Python is still a young and evolving
language, I believe that it has a bright future in education. This
book is an important step in that direction.
David Beazley
University of Chicago
Author of the Python Essential Reference
Foreword #5
Como pensar como um cientista da Computao usando Python
Apresentao Apresentao
Traduo do captulo anterior, que foi mantido por ter sido marcado como seo invariante pelo autor original.
Como educador, pesquisador e autor de livros, regozija-me
ver completo este trabalho. Python uma linguagem de
programao divertida e extremamente fcil de usar que tem
ganho forte popularidade nestes ltimos poucos anos.
Desenvolvida dez anos atrs por Guido van Rossun, a sintaxe
simples do Python e seu sentido geral so grandemente
derivados do ABC, uma linguagem didtica que foi
desenvolvida nos anos 80. Entretanto, Python tambm foi
criado para solucionar problemas reais e tomou emprestado
uma grande quantidade de caractersticas de linguagens de
programao como C++, Java, Modula-3 e Scheme. Por causa
disso, uma das mais notveis caractersticas do Python o
grande apelo que tem junto a desenvolvedores profissionais de
software, cientistas, pesquisadores, artistas e educadores.
A Despeito deste apelo do Python junto s mais
variadas comunidades, voc pode ainda estar pensando ?por
que Python?? ou ?por que ensinar programao com
Python??. Responder estas perguntas no uma tarefa fcil ?
especialmente se a opinio pblica est do lado de alternativas
mais masoquistas como C++ e Java. Entretanto, eu acho que a
resposta mais direta que programar com Python um
bocado divertido e mais produtivo.
Quando ministro cursos de cincias da
computao, o que desejo cobrir conceitos importantes alm
de tornar a matria interessante e os alunos participativos.
Infelizmente, existe uma tendncia entre os cursos
introdutrios de programao a focar ateno demais em
abstraes matemticas, e de frustrao entre os alunos com
problemas enfadonhos e inoportunos relacionados a detalhes
de sintaxe em baixo nvel, compilao e a imposio de regras
que aparentemente s um expert pode compreender. Embora
alguma abstrao e formalismo sejam importantes para
engenheiros profissionais de software e estudantes que
planejam continuar seus estudos em cincias da computao,
escolher tal abordagem em um curso introdutrio faz da
cincia da computao algo entediante. Quando ministro um
curso, no desejo uma sala cheia de alunos sem inspirao.
Em vez disso, preferiria muito mais v-los tentando solucionar
problemas interessantes explorando idias diferentes,
trilhando caminhos no convencionais, quebrando regras, e
aprendendo a partir de seus erros. Fazendo assim, no
pretendo desperdiar metade de um semestre tentando explicar
problemas obscuros de sintaxe, mensagens ininteligveis de
compiladores ou as vrias centenas de maneiras pelas quais
um programa pode gerar uma falha geral de proteo.
Uma das razes pelas quais eu gosto de Python
que ele oferece um equilbrio realmente bom entre o lado
prtico e o lado conceitual. Sendo Python interpretado, os
iniciantes podem pegar a linguagem e comear a fazer coisas
legais quase imediatamente sem se perderem em problemas de
compilao e ligao. Alm disso, Python vem com uma
grande biblioteca de mdulos que podem ser utilizados para
fazer todo tipo de tarefa, desde a programao para a web at
grficos. Com tal enfoque prtico temos uma bela maneira de
alcanar o engajamento dos alunos e permitir que eles
finalizem projetos significativos. Entretanto, Python tambm
pode servir de excelente embasamento para a introduo de
conceitos importantes em cincia da computao. J que
Python suporta plenamente procedimentos (procedures) e
classes, os alunos podem ser gradualmente introduzidos a
tpicos como abstrao procedural, estruturas de dados, e
programao orientada a objetos ? todos aplicveis em cursos
posteriores de Java ou C++. 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 em
cincia da computao na Universidade de Chicago. Nestes
cursos, enfrento constantemente a assustadora tarefa de cobrir
muitos tpicos difceis em um rapidssimo trimestre 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
Apresentao #6
Como pensar como um cientista da Computao usando Python
Preface Preface
By Jef Elkner
This book owes its existence to the
collaboration made possible by the Internet and the free
software movement. Its three authors-a college professor, a
high school teacher, and a professional programmer-have yet
to meet face to face, but we have been able to work closely
together and have been aided by many wonderful folks who
have donated their time and energy to helping make this book
better.
We think this book is a testament to the benefts
and future possibilities of this kind of collaboration, the
framework for which has been put in place by Richard
Stallman and the Free Software Foundation.
How and why I came to use Python
In 1999, the College Board`s Advanced Placement (AP)
Computer Science exam was given in C++ for the frst time.
As in many high schools throughout the country, the decision
to change languages had a direct impact on the computer
science curriculum at Yorktown High School in Arlington,
Virginia, where I teach. Up to this point, Pascal was the
language of instruction in both our frst-year and AP courses.
In keeping with past practice of giving students two years of
exposure to the same language, we made the decision to
switch to C++ in the frst-year course for the 1997-98 school
year so that we would be in step with the College Board`s
change for the AP course the following year.
Two years later, I was convinced that C++ was
a poor choice to use for introducing students to computer
science. While it is certainly a very powerful programming
language, it is also an extremely dimcult language to learn and
teach. I found myself constantly fghting with C++`s dimcult
syntax and multiple ways of doing things, and I was losing
many students unnecessarily as a result. Convinced there had
to be a better language choice for our frst-year class, I went
looking for an alternative to C++.
I needed a language that would run on the
machines in our Linux lab as well as on the Windows and
Macintosh platforms most students have at home. I wanted it
to be free and available electronically, so that students could
use it at home regardless of their income. I wanted a language
that was used by professional programmers, and one that had
an active developer community around it. It had to support
both procedural and ob ject-oriented programming. And most
importantly, it had to be easy to learn and teach. When I
investigated the choices with these goals in mind, Python
stood out as the best candidate for the job.
I asked one of Yorktown`s talented students,
Matt Ahrens, to give Python a try. In two months he not only
learned the language but wrote an application called pyTicket
that enabled our staf to report technology problems via the
Web. I knew that Matt could not have fnished an application
of that scale in so short a time in C++, and this
accomplishment, combined with Matt`s positive assessment of
Python, suggested that Python was the solution I was looking
for.
Finding a textb o ok
Having decided to use Python in both of my introductory
computer science classes the following year, the most pressing
problem was the lack of an available textbook.
Free content came to the rescue. Earlier in the
year, Richard Stallman had introduced me to Allen Downey.
Both of us had written to Richard expressing an interest in
developing free educational content. Allen had already written
a frst-year computer science textbook, How to Think Like a
Computer Scientist. When I read this book, I knew
immediately that I wanted to use it in my class. It was the
clearest and most helpful computer science text I had seen. It
emphasized the processes of thought involved in
programming rather than the features of a particular language.
Reading it immediately made me a better teacher.
How to Think Like a Computer Scientist was not
just an excellent book, but it had been released under a GNU
public license, which meant it could be used freely and
modifed to meet the needs of its user. Once I decided to use
Python, it occurred to me that I could translate Allen`s original
Java version of the book into the new language. While I would
not have been able to write a textbook on my own, having
Allen`s book to work from made it possible for me to do so, at
the same time demonstrating that the cooperative development
model used so well in software could also work for
educational content.
Working on this book for the last two years has
been rewarding for both my students and me, and my students
played a big part in the process. Since I could make instant
changes whenever someone found a spelling error or dimcult
passage, I encouraged them to look for mistakes in the book
by giving them a bonus point each time they made a
suggestion that resulted in a change in the text. This had the
double beneft of encouraging them to read the text more
carefully and of getting the text thoroughly reviewed by its
most important critics, students using it to learn computer
science.
For the second half of the book on ob ject-
oriented programming, I knew that someone with more real
programming experience than I had would be needed to do it
right. The book sat in an unfnished state for the better part of
a year until the free software community once again provided
the needed means for its completion.
I received an email from Chris Meyers
expressing interest in the book. Chris is a professional
programmer who started teaching a programming course last
year using Python at Lane Community College in Eugene,
Oregon. The prospect of teaching the course had led Chris to
the book, and he started helping out with it immediately. By
the end of the school year he had created a companion project
on our Website at http://www.ibiblio.org/obp called Python
for Fun and was working with some of my most advanced
students as a master teacher, guiding them beyond where I
could take them.
Intro ducing programming with Python
The process of translating and using How to Think Like a
Computer Scientist for the past two years has confrmed
Python`s suitability for teaching beginning students. Python
greatly simplifes programming examples and makes
important programming ideas easier to teach.
The frst example from the text illustrates this
point. It is the traditional hello, world program, which in the
Preface #7
Como pensar como um cientista da Computao usando Python
C++ version of the book looks like this:
#1hcude <1os1Jeam.h>
vo1d ma1h{)
{
cou1 << "heo, woJd." << ehd,
}
in the Python version it becomes:
pJ1h1 "heo, WoJd!"
Even though this is a trivial example, the
advantages of Python stand out. Yorktown`s Computer
Science I course has no prerequisites, so many of the students
seeing this example are looking at their frst program. Some of
them are undoubtedly a little nervous, having heard that
computer programming is dimcult to learn. The C++ version
has always forced me to choose between two unsatisfying
options: either to explain the #include, void main(), {, and
statements and risk confusing or intimidating some of the
students right at the start, or to tell them, Just don`t worry
about all of that stuf now; we will talk about it later, and risk
the same thing. The educational ob jectives at this point in the
course are to introduce students to the idea of a programming
statement and to get them to write their frst program, thereby
introducing them to the programming environment. The
Python program has exactly what is needed to do these things,
and nothing more.
Comparing the explanatory text of the program
in each version of the book further illustrates what this means
to the beginning student. There are thirteen paragraphs of
explanation of Hello, world! in the C++ version; in the
Python version, there are only two. More importantly, the
missing eleven paragraphs do not deal with the big ideas in
computer programming but with the minutia of C++ syntax. I
found this same thing happening throughout the book. Whole
paragraphs simply disappear from the Python version of the
text because Python`s much clearer syntax renders them
unnecessary.
Using a very high-level language like Python
allows a teacher to postpone talking about low-level details of
the machine until students have the background that they need
to better make sense of the details. It thus creates the ability to
put frst things frst pedagogically. One of the best examples
of this is the way in which Python handles variables. In C++ a
variable is a name for a place that holds a thing. Variables
have to be declared with types at least in part because the size
of the place to which they refer needs to be predetermined.
Thus, the idea of a variable is bound up with the hardware of
the machine. The powerful and fundamental concept of a
variable is already dimcult enough for beginning students (in
both computer science and algebra). Bytes and addresses do
not help the matter. In Python a variable is a name that refers
to a thing. This is a far more intuitive concept for beginning
students and is much closer to the meaning of variable that
they learned in their math courses. I had much less dimculty
teaching variables this year than I did in the past, and I spent
less time helping students with problems using them.
Another example of how Python aids in the
teaching and learning of programming is in its syntax for
functions. My students have always had a great deal of
dimculty understanding functions. The main problem centers
around the diference between a function defnition and a
function call, and the related distinction between a parameter
and an argument. Python comes to the rescue with syntax that
is nothing short of beautiful. Function defnitions begin with
the keyword def, so I simply tell my students, When you
defne a function, begin with def, followed by the name of the
function that you are defning; when you call a function,
simply call (type) out its name. Parameters go with
defnitions; arguments go with calls. There are no return types,
parameter types, or reference and value parameters to get in
the way, so I am now able to teach functions in less than half
the time that it previously took me, with better
comprehension.
Using Python has improved the efectiveness of
our computer science program for all students. I see a higher
general level of success and a lower level of frustration than I
experienced during the two years I taught C++. I move faster
with better results. More students leave the course with the
ability to create meaningful programs and with the positive
attitude toward the experience of programming that this
engenders.
Building a community
I have received email from all over the globe from people
using this book to learn or to teach programming. A user
community has begun to emerge, and many people have been
contributing to the pro ject by sending in materials for the
companion Website at http://www.thinkpython.com.
With the publication of the book in print form, I
expect the growth in the user community to continue and
accelerate. The emergence of this user community and the
possibility it suggests for similar collaboration among
educators have been the most exciting parts of working on this
pro ject for me. By working together, we can increase the
quality of materials available for our use and save valuable
time. I invite you to join our community and look forward to
hearing from you. Please write to the authors at
feedback@thinkpython.com.
Jefrey Elkner
Yorktown High School
Arlington, Virginia
Preface #8
Como pensar como um cientista da Computao usando Python
Prefcio Prefcio
Traduo do captulo anterior, que foi mantido por ter sido marcado como seo invariante pelo autor original.
Este livro deve sua existncia colaborao tornada possvel
pela Internet e pelo movimento do software livre. Seus trs
autores ? um professor universitrio, um secundrio e um
programador profissional ? ainda no se encontraram
pessoalmente, mas temos podido trabalhar bem de perto e
temos sido ajudados por muitos colegas maravilhosos que tm
dedicado seu tempo e energia a ajudar a fazer deste um livro
cada vez melhor.
Achamos que este livro um testemunho dos
benefcios e possibilidades futuras deste tipo de colaborao,
cujo modelo tem sido colocado por Richard Stallman e pela
Free Software Foundation.
Como e porque eu vim a usar Python
Em 1999, o Exame de Colocao Avanada em Cincia da
Computao da Comisso de Faculdades (College Board?s
Advanced Placement (AP) Computer Science) foi aplicado em
C++ pela primeira vez. Como em muitas escolas secundrias
atravs do pas, a deciso de mudar linguagens teve um
impacto direto no currculo de cincia da computao na
Yorktown High School em Arlington, Virginia, onde leciono.
At ento, Pascal era a linguagem didtica para nossos cursos
de primeiro ano e avanado. Mantendo a prtica corrente de
dar aos estudantes dois anos de exposio mesma
linguagem, tomamos a deciso de mudar para C++ no curso
de primeiro ano para o ano letivo de 1997-98 de modo que
estaramos em sincronismo com a mudana da Comisso de
Faculdades (College Board?s) em relao ao curso avanado
para o ano seguinte.
Dois anos depois, eu estava convencido que
C++ foi uma escolha infeliz para introduzir os alunos em
cincia da computao. Ao mesmo tempo em que
certamente uma linguagem de programao muito poderosa,
tambm uma linguagem extremamente difcil de aprender e
de ensinar. Eu me encontrava constantemente lutando com a
sintaxe difcil do C++ e as mltiplas maneiras de fazer a
mesma coisa, e estava, como resultado, perdendo muitos
alunos desnecessariamente. Convencido de que deveria existir
uma linguagem melhor para a nossa classe de primeiro ano,
fui procurar por uma alternativa ao C++.
Eu precisava de uma linguagem que pudesse
rodar nas mquinas em nosso laboratrio Linux bem como nas
plataformas Windows e Macintosh que a maioria dos alunos
tinha em casa. Eu precisava que ela fosse gratuita e disponvel
eletronicamente, assim os alunos poderiam utiliz-la em casa
independentemente de suas rendas. Eu queria uma linguagem
que fosse utilizada por programadores profissionais, e que
tivesse uma comunidade de desenvolvimento ativa em torno
dela. Ela teria que suportar ambas, programao procedural e
orientada a objetos. E, mais importante, deveria ser fcil de
aprender e de ensinar. Quando considerei as alternativas tendo
em mente aquelas metas, Python sobressaiu-se como a melhor
candidata para a tarefa.
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++, esta realizao,
combinada com a avaliao positiva do Python dada por Matt,
sugeriam que Python era a soluo que eu estava procurando.
Encontrando um livro texto
Tendo decidido usar Python em ambas as minhas classes
introdutrias de cincia da computao do ano seguinte, o
problema mais urgente era a falta de um livro texto disponvel.
O contedo livre veio em socorro.
Anteriormente naquele ano, Richard Stallman tinha me
apresentado a Allen Downey. Ambos havamos escrito a
Richard expressando interesse em desenvolver contedo
educacional livre. Allen j tinha escrito um livro texto para o
primeiro ano de cincia da computao, How to Think Like a
Computer Scientist. Quando li este livro, soube imediatamente
que queria utiliz-lo nas minhas aulas. Era o texto mais claro e
proveitoso em cincia da computao que eu tinha visto. Ele
enfatizava o processo de reflexo envolvido em programao
em vez de caractersticas de uma linguagem em particular. L-
lo fez de mim imediatamente um melhor professor.
O How to Think Like a Computer Scientist era
no s um excelente livro, como tambm fora lanado sob
uma licena pblica GNU, o que significava que ele poderia
ser usado livremente e modificado para atender as
necessidades de seu usurio. Uma vez que eu havia decidido
usar Python, me ocorreu que eu poderia traduzir a verso
original do livro de Allen do Java para a nova linguagem.
Apesar de no estar capacitado para escrever eu mesmo um
livro texto, tendo o livro de Allen a partir do qual trabalhar
tornou possvel para mim faz-lo, ao mesmo tempo
demonstrando que o modelo de desenvolvimento cooperativo
to bem utilizado em software poderia tambm funcionar para
contedo educacional.
Trabalhar neste livro pelos ltimos dois anos
tem sido recompensador para mim e meus alunos, e eles
tiveram um grande papel neste processo. A partir do momento
em que eu podia fazer mudanas instantneas assim que
algum encontrasse um erro ortogrfico ou um trecho difcil,
eu os encorajei a procurar por erros no livro, dando a eles
pontos de bonificao cada vez que eles fizessem uma
sugesto que resultasse em uma mudana no texto. Isto teve o
duplo benefcio de encoraj-los a ler o texto mais
cuidadosamente e de ter o texto totalmente revisado por seus
crticos mais importantes: alunos utilizando-o para aprender
cincia da computao.
Para a segunda metade do livro, sobre
programao orientada a objetos, eu sabia que seria preciso
algum com uma maior experincia do que a minha em
programao real para faz-lo corretamente. O livro esteve em
estado inacabado por quase um ano at que a comunidade de
software livre providenciasse mais uma vez os meios
necessrios para sua concluso.
Eu recebi um e-mail de Chris Meyers mostrando
interesse no livro. Chris um programador profissional que
comeou a dar um curso de programao no ano anterior
usando Python no Lane Community College em Eugene,
Oregon. A perspectiva de dar aquele curso ligou Chris ao
livro, e ele comeou a ajudar o trabalho imediatamente. Pelo
final do ano letivo ele tinha criado um projeto colaborativo em
nosso Website em http://www.ibiblio.org/obp chamado
Python for Fun e estava trabalhando com alguns dos meus
alunos mais avanados como um guru, guiando-os alm de
onde eu poderia lev-los.
Prefcio #9
Como pensar como um cientista da Computao usando Python
Introduzindo programao com Python
O processo de traduzir e utilizar How to Think Like a
Computer Scientist pelos ltimos dois anos tem confirmado a
convenincia de Python no ensino de alunos iniciantes.
Python simplifica tremendamente os programas exemplo e
torna idias importantes de programao mais fceis de
ensinar.
O primeiro exemplo do texto ilustra este ponto.
o tradicional programa ?Al mundo?, do qual na verso
C++ do livro se parece com isto:
#1hcude <1os1Jeam.h>
vo1d ma1h{)
{
cou1 << "A, muhdo." << ehd,
}
Na verso Python, ele se transforma em:
pJ1h1 "A, huhdo!"
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 do texto para
Python porque a sintaxe muito mais clara do 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 ?por em primeiro
lugar as primeiras coisas?, pedagogicamente. 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 (em ambas, cincia da computao e lgebra).
Bytes e endereos no ajudam neste caso. Em Python uma
varivel um nome que se refere a uma coisa. Este um
conceito muito mais intuitivo para alunos iniciantes e est
muito mais prximo do significado de ?varivel? que eles
aprenderam em seus cursos de matemtica. Eu tive muito
menos dificuldade em ensinar variveis este ano do que tive
no passado, e gastei menos tempo ajudando aos alunos com
problemas no uso delas.
Um outro exemplo de como Python ajuda no
ensino e aprendizagem de programao em sua sintaxe para
funo. Meus alunos tm sempre tido grande dificuldade na
compreenso de funes. O problema principal gira em torno
da diferena entre a definio de uma funo e a chamada de
uma funo, e a distino relacionada entre um parmetro e
um argumento. Python vem em auxlio com uma sintaxe no
apenas curta quanto bela. As definies de funo comeam
com def, ento eu simplesmente digo aos meus alunos ?
Quando voc define uma funo, comece com def, seguido do
nome da funo que voc est definindo; quando voc chama
uma funo, simplesmente chame-a digitando o nome dela?.
Parmetros ficam nas definies; argumentos vo com as
chamadas. No existem tipos de retorno, tipos de parmetro
ou passagem de parmetros por valor ou por referncia no
meio do caminho, permitindo-me ensinar funes em menos
da metade do tempo que isto me tomava anteriormente, com
uma melhor compreenso.
A utilizao do Python tem melhorado a
efetividade de nosso programa em cincia da computao para
todos os estudantes. Eu vejo um nvel geral de sucesso muito
mais alto e um nvel mais baixo de frustrao do que
experimentei durante os dois anos em que ensinei C++. Eu
avano mais rpido com melhores resultados. Mais alunos
deixam o curso com a habilidade de criar programas
significativos e com uma atitude positiva em relao a
experincia de programao que isso traz.
Construindo uma comunidade
Tenho recebido e-mails de todo o planeta de pessoas
utilizando este livro para aprender ou ensinar programao.
Uma comunidade de usurios tem comeado a emergir e
muitas pessoas tm contribudo com o projeto enviando seus
materiais para o Website cooperativo em:
http://www.thinkpython.com
Com a publicao do livro em formato
impresso, minha expectativa quanto ao crescimento da
comunidade de usurios que ela seja contnua e acelerada. O
surgimento desta comunidade de usurios e a possibilidade
que sugere de colaborao semelhante entre educadores tem
sido para mim a parte mais excitante do trabalho neste projeto.
Trabalhando juntos, podemos aumentar a qualidade do
material disponvel para o nosso uso e poupar tempo valioso.
Eu convido voc a se juntar a nossa comunidade e espero
ouvir algo de voc. Por favor, escreva para os autores em
feedback@thinkpython.com.
Jeffrey Elkner
Yorktown High School
Arlington, Virginia
Prefcio #10
Como pensar como um cientista da Computao usando Python
Contributor List Contributor List
To paraphrase the philosophy of the Free Software
Foundation, this book is free like free speech, but not
necessarily free like free pizza. It came about because of a
collaboration that would not have been possible without the
GNU Free Documentation License. So we thank the Free
Software Foundation for developing this license and, of
course, making it available to us.
We also thank the more than 100 sharp-eyed
and thoughtful readers who have sent us suggestions and
corrections over the past few years. In the spirit of free
software, we decided to express our gratitude in the form of a
contributor list. Unfortunately, this list is not complete, but we
are doing our best to keep it up to date.
If you have a chance to look through the list,
you should realize that each person here has spared you and
all subsequent readers from the confusion of a technical error
or a less-than-transparent explanation, just by sending us a
note.
Impossible as it may seem after so many
corrections, there may still be errors in this book. If you
should stumble across one, please check the online version of
the book at http://thinkpython.com, which is the most up-to-
date version. If the error has not been corrected, please take a
minute to send us email at feedback@thinkpython.com. If we
make a change due to your suggestion, you will appear in the
next version of the contributor list (unless you ask to be
omitted). Thank you!
e Lloyd Hugh Allen sent in a correction to Section 8.4.
e Yvon Boulianne sent in a correction of a semantic
error in Chapter 5.
e Fred Bremmer submitted a correction in Section 2.1.
e Jonah Cohen wrote the Perl scripts to convert the
LaTeX source for this book into beautiful HTML.
e Michael Conlon sent in a grammar correction in
Chapter 2 and an improvement in style in Chapter 1,
and he initiated discussion on the technical aspects of
interpreters.
e Benoit Girard sent in a correction to a humorous
mistake in Section 5.6.
e Courtney Gleason and Katherine Smith wrote
horsebet.py, which was used as a case study in an
earlier version of the book. Their program can now
be found on the website.
e Lee Harr submitted more corrections than we have
room to list here, and indeed he should be listed as
one of the principal editors of the text.
e James Kaylin is a student using the text. He has
submitted numerous corrections.
e David Kershaw fxed the broken catTwice function in
Section 3.10.
e Eddie Lam has sent in numerous corrections to
Chapters 1, 2, and 3. He also fxed the Makefle so
that it creates an index the frst time it is run and
helped us set up a versioning scheme.
e Man-Yong Lee sent in a correction to the example
code in Section 2.4.
e David Mayo pointed out that the word
unconsciously in Chapter 1 needed to be changed
to subconsciously.
e Chris McAloon sent in several corrections to
Sections 3.9 and 3.10.
e Matthew J. Moelter has been a long-time contributor
who sent in numerous corrections and suggestions to
the book.
e Simon Dicon Montford reported a missing function
defnition and several typos in Chapter 3. He also
found errors in the increment function in Chapter 13.
e John Ouzts corrected the defnition of return value
in Chapter 3.
e Kevin Parks sent in valuable comments and
suggestions as to how to improve the distribution of
the book.
e David Pool sent in a typo in the glossary of Chapter
1, as well as kind words of encouragement.
e Michael Schmitt sent in a correction to the chapter on
fles and exceptions.
e Robin Shaw pointed out an error in Section 13.1,
where the printTime function was used in an example
without being defned.
e Paul Sleigh found an error in Chapter 7 and a bug in
Jonah Cohen`s Perlscript that generates HTML from
LaTeX.
e Craig T. Snydal is testing the text in a course at Drew
University. He has contributed several valuable
suggestions and corrections.
e Ian Thomas and his students are using the text in a
programming course. They are the frst ones to test
the chapters in the latter half of the book, and they
have made numerous corrections and suggestions.
e Keith Verheyden sent in a correction in Chapter 3.
e Peter Winstanley let us know about a longstanding
error in our Latin in Chapter 3.
e Chris Wrobel made corrections to the code in the
chapter on fle I/O and exceptions.
e Moshe Zadka has made invaluable contributions to
this pro ject. In addition to writing the frst draft of
the chapter on Dictionaries, he provided continual
guidance in the early stages of the book.
e Christoph Zwerschke sent several corrections and
pedagogic suggestions, and explained the diference
between gleich and selbe.
e James Mayer sent us a whole slew of spelling and
typographical errors, including two in the contributor
list.
e Hayden McAfee caught a potentially confusing
inconsistency between two examples.
e Angel Arnal is part of an international team of
translators working on the Spanish version of the
text. He has also found several errors in the English
version.
e Tauhidul Hoque and Lex Berezhny created the
Contributor List #11
Como pensar como um cientista da Computao usando Python
illustrations in Chapter 1 and improved many of the
other illustrations.
e Dr. Michele Alzetta caught an error in Chapter 8 and
sent some interesting pedagogic comments and
suggestions about Fibonacci and Old Maid.
e Andy Mitchell caught a typo in Chapter 1 and a
broken example in Chapter 2.
e Kalin Harvey suggested a clarifcation in Chapter 7
and caught some typos.
e Christopher P. Smith caught several typos and is
helping us prepare to update the book for Python 2.2.
e David Hutchins caught a typo in the Foreword.
e Gregor Lingl is teaching Python at a high school in
Vienna, Austria. He is working on a German
translation of the book, and he caught a couple of bad
errors in Chapter 5.
e Julie Peters caught a typo in the Preface.
e Florin Oprina sent in an improvement in makeTime,
a correction in printTime, and a nice typo.
e D. J. Webre suggested a clarifcation in Chapter 3.
e Ken found a fstful of errors in Chapters 8, 9 and 11.
e Ivo Wever caught a typo in Chapter 5 and suggested
a clarifcation in Chapter 3.
e Curtis Yanko suggested a clarifcation in Chapter 2.
e Ben Logan sent in a number of typos and problems
with translating the book into HTML.
e Jason Armstrong saw the missing word in Chapter 2.
e Louis Cordier noticed a spot in Chapter 16 where the
code didn`t match the text.
e Brian Cain suggested several clarifcations in
Chapters 2 and 3.
e Rob Black sent in a passel of corrections, including
some changes for Python 2.2.
e Jean-Philippe Rey at Ecole Centrale Paris sent a
number of patches, including some updates for
Python 2.2 and other thoughtful improvements.
e Jason Mader at George Washington University made
a number of useful suggestions and corrections.
e Jan Gundtofte-Bruun reminded us that a error is an
error.
e Abel David and Alexis Dinno reminded us that the
plural of matrix is matrices, not matrixes. This
error was in the book for years, but two readers with
the same initials reported it on the same day. Weird.
e Charles Thayer encouraged us to get rid of the semi-
colons we had put at the ends of some statements and
to clean up our use of argument and parameter.
e Roger Sperberg pointed out a twisted piece of logic
in Chapter 3.
Contributor List #12
Como pensar como um cientista da Computao usando Python
Verso Brasileira Verso Brasileira
A verso traduzida para Portugus Brasileiro foi feita pela
equipe do site http://pensarpython.incubadora.fapesp.br,
abaixo relacionada:
Adrovane Kade (adrovane)
Alex Augusto da Luz dos Santos (nowayx)
Claudio Fernando Berrondo Soares (cl-audio)
Daniel Rosa Franzini (danielt3)
Douglas Soares de Andrade (dsa)
Fabio Rizzo Matos (fabrizmat)
Imre Simon (imres)
Joao Paulo Liberato (jpliberato)
Joo Paulo Gomes Vanzuita (taken)
Julio Monteiro (jmonteiro)
Luciano Ramalho (luciano)
Marcus Pereira (mvmendes)
Mario O. de Menezes (modemene)
Paulo J. S. Silva (pjssilva)
Victor Rafael da Paixo Lopes (reije)
marta mello (martamello)
vitor gurgel (vitor_gurgel)
Esta diagramao foi feita por Crlisson
Galdino <bardo@castelodotempo.com>, com algumas
modificaes visando a facilitar a publicao em duas colunas.
Alguns comentrios de depurao feitos pela equipe de
traduo foram omitidos.
Verso Brasileira #13
Como pensar como um cientista da Computao usando Python
Captulo 1: O caminho do programa Captulo 1: O caminho do programa
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 idias (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.
1.1 A linguagem de programao Python
Python a linguagem de programao que voc vai estudar
neste livro. Python um exemplo de linguagem de
programao de alto nvel; outras linguagens de alto nvel
de que voc j pode ter ouvido falar so C, C++, Perl e Java.
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"). Dito
de maneira 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 mais
provvel que estejam 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: ora lendo algumas linhas,
ora realizando computaes.
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, porque 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:
$ py1hoh
Py1hoh 2.4.3 {#2, 0c1 6 2006, 07.49.22)
|CCC 4.0.3 {bbuh1u 4.0.3-1ubuh1u5)] oh 1hux2
Type "hep", "copyJ1gh1", "cJed11s" oJ "1cehse" 1oJ
moJe 1h1oJma11oh.
>>> pJ1h1 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. 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:
pJ1h1 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:
$ py1hoh e11c1a.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
Captulo 1: O caminho do programa #14
Como pensar como um cientista da Computao usando Python
tem um programa que funciona, deve guard-lo em um script,
de forma a poder execut-lo ou modific-lo no futuro.
1.2 O que um programa?
Um programa uma seqncia de instrues que
especificam como executar uma computao. A computao
pode ser algo matemtico, como solucionar um sistema de
equaes ou encontrar as razes de um polinmio, mas
tambm pode ser uma computao simblica, como buscar e
substituir uma palavra em um documento ou (estranhamente)
compilar um programa.
Os detalhes so diferentes em diferentes
linguagens, mas algumas instrues bsicas aparecem em
praticamente todas as linguagens:
entrar Pegar dados do teclado, de um arquivo
ou de algum outro dispositivo.
sair Mostrar dados na tela ou enviar dados
para um arquivo ou outro dispositivo.
calcular Executar operaes matemticas
bsicas, como adio e multiplicao.
executar
condicionalmente
Checar certas condies e executar a
seqncia apropriada de instrues.
repetir Executar alguma ao repetidamente,
normalmente com alguma variao.
Acredite se quiser: isso praticamente tudo.
Todos os programas que voc j usou, no importa quo
complicados, so feitos de instrues mais ou menos
parecidas com essas. Assim, poderamos definir programao
como o processo de dividir uma tarefa grande e complexa em
sub-tarefas cada vez menores, at que as sub-tarefas sejam
simples o suficiente para serem executadas com uma dessas
instrues bsicas.
Isso pode parecer um pouco vago, mas vamos
voltar a esse tpico mais adiante, quando falarmos sobre
algoritmos.
1.3 O que depurao (debugging)?
Programar um processo complicado e, como feito por
seres humanos, freqentemente conduz a erros. Por mero
capricho, erros em programas so chamados de bugs e o
processo de encontr-los e corrigi-los chamado de
depurao (debugging).
Trs tipos de erro podem acontecer em um
programa: erros de sintaxe, erros em tempo de execuo
(runtime errors) e erros de semntica. Distinguir os trs tipos
ajuda a localiz-los mais rpido:
1.3.1 Erros de sintaxe
Python s executa um programa se ele estiver sintaticamente
correto; caso contrrio, o processo falha e retorna uma
mensagem de erro. Sintaxe se refere estrutura de um
programa e s regras sobre esta estrutura. Por exemplo, em
portugus, uma frase deve comear com uma letra maiscula
e terminar com um ponto.
esta frase contm um erro de sintaxe. Assim
como esta
Para a maioria dos leitores, uns errinhos de
sintaxe no chegam a ser um problema significativo e por
isso que conseguimos ler a poesia moderna de e. e. cummings
sem cuspir mensagens de erro. Python no to indulgente.
Se o seu programa tiver um nico erro de sintaxe em algum
lugar, o interpretador Python vai exibir uma mensagem de
erro e vai terminar - e o programa no vai rodar. Durante as
primeiras semanas da sua carreira como programador, voc
provavelmente perder um bocado de tempo procurando erros
de sintaxe. Conforme for ganhando experincia, entretanto,
cometer menos erros e os localizar mais rpido.
1.3.2 Erros em tempo de execuo (runtime errors)
O segundo tipo de erro o erro de runtime, ou erro em tempo
de execuo, assim chamado porque s aparece quando voc
roda o programa. Esses erros so tambm conhecidos como
excees, porque normalmente indicam que alguma coisa
excepcional (e ruim) aconteceu.
Erros de runtime so raros nos programas
simples que voc vai ver nos primeiros captulos - ento, vai
demorar um pouco at voc se deparar com um erro desse
tipo.
1.3.3 Erros de semntica
O terceiro tipo de erro o erro de semntica (mais
comumente chamado erro de lgica). Mesmo que o seu
programa tenha um erro de semntica, ele vai rodar com
sucesso, no sentido de que o computador no vai gerar
nenhuma mensagem de erro. S que o programa no vai fazer
a coisa certa, vai fazer alguma outra coisa. Especificamente,
aquilo que voc tiver dito para ele fazer.
O problema que o programa que voc
escreveu no aquele que voc queria escrever. O significado
do programa (sua semntica ou lgica) est errado. Identificar
erros semnticos pode ser complicado, porque requer que
voc trabalhe de trs para frente, olhando a sada do programa
e tentando imaginar o que ele est fazendo.
1.3.4 Depurao experimental (Debugging)
Uma das habilidades mais importantes que voc vai adquirir
a de depurar. Embora possa ser frustrante, depurar uma das
partes intelectualmente mais ricas, desafiadoras e
interessantes da programao.
De certa maneira, a depurao como um
trabalho de detetive. Voc se depara com pistas, e tem que
deduzir os processos e eventos que levaram aos resultados
que aparecem.
Depurar tambm como uma cincia
experimental. Uma vez que voc tem uma idia do que est
errado, voc modifica o seu programa e tenta de novo. Se a
sua hiptese estava correta, ento voc consegue prever o
resultado da modificao e fica um passo mais perto de um
programa que funciona. Se a sua hiptese estava errada, voc
tem que tentar uma nova. Como Sherlock Holmes mostrou,
"Quando voc tiver eliminado o impossvel, aquilo que
restou, ainda que improvvel, deve ser a verdade." (Arthur
Conan Doyle, O signo dos quatro).
Para algumas pessoas, programao e
depurao so a mesma coisa. Ou seja, programar o
processo de gradualmente depurar um programa, at que ele
faa o que voc quer. A idia comear com um programa
que faa alguma coisa e ir fazendo pequenas modificaes,
depurando-as conforme avana, de modo que voc tenha
sempre um programa que funciona.
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 User's Guide Verso Beta 1)
Captulos posteriores faro mais sugestes
Captulo 1: O caminho do programa #15
Como pensar como um cientista da Computao usando Python
sobre depurao e outras prticas de programao.
1.4 Linguagens naturais e linguagens formais
Linguagens naturais so as linguagens que as pessoas falam,
como o portugus, o ingls e o espanhol. Elas no foram
projetadas pelas pessoas (muito embora as pessoas tentem
colocar alguma ordem nelas); elas evoluram naturalmente.
Linguagens formais so linguagens que foram
projetadas por pessoas, para aplicaes especficas. Por
exemplo, a notao que os matemticos usam uma
linguagem formal, que particularmente boa em denotar
relaes entre nmeros e smbolos. Os qumicos usam uma
linguagem formal para representar a estrutura qumica das
molculas. E, mais importante:
Linguagens de programao so linguagens
formais que foram desenvolvidas para expressar
computaes.
As linguagens formais tendem a ter regras
estritas quanto sintaxe. Por exemplo, 3 + 3 = 6 uma
expresso matemtica sintaticamente correta, mas 3=+6$ no
. H2O um nome qumico sintaticamente correto, mas 2Zz
no .
As regras de sintaxe so de dois tipos, um
relacionado aos tokens, outro estrutura. "Tokens" so os
elementos bsicos da linguagem, como as palavras, nmeros,
e elementos qumicos. Um dos problemas com 3=+6$ que $
no um token vlido em linguagem matemtica (pelo menos
at onde sabemos). Do mesmo modo, 2Zz invlida porque
no existe nenhum elemento cuja abreviatura seja Zz.
O segundo tipo de erro de sintaxe est
relacionado estrutura de uma expresso -- quer dizer, ao
modo como os tokens esto arrumados. A expresso 3=+6$
estruturalmente invlida, porque voc no pode colocar um
sinal de "mais" imediatamente aps um sinal de "igual". Do
mesmo modo, frmulas moleculares devem ter ndices
subscritos colocados depois do nome do elemento, no antes.
Faa este exerccio: crie o que parea ser uma
frase bem estruturada em portugus com "tokens"
irreconhecveis dentro dela. Depois escreva outra frase com
todos os "tokens" vlidos, mas com uma estrutura invlida.
Quando voc l uma frase em portugus ou
uma expresso em uma linguagem formal, voc tem de
imaginar como a estrutura da frase (embora, em uma
linguagem natural, voc faa isso inconscientemente). Este
processo chamado parsing (anlise sinttica).
Por exemplo, quando voc ouve a frase, "Caiu a
ficha", entende que "a ficha" o sujeito e "caiu" o verbo.
Uma vez que voc analisou a frase, consegue entender o seu
significado, ou a semntica da frase. Assumindo que voc
saiba o que uma ficha e o que significa cair, voc entender
o sentido geral dessa frase.
Muito embora as linguagens formais e as
naturais tenham muitas caractersticas em comum -- tokens,
estrutura, sintaxe e semntica -- existem muitas diferenas:
ambigidade As linguagens naturais esto cheias de
ambigidades, que as pessoas contornam
usando pistas contextuais e outras
informaes. J as linguagens formais so
desenvolvidas para serem quase ou
totalmente desprovidas de ambigidade, o
que significa que qualquer expresso tem
precisamente s um sentido,
independentemente do contexto.
redundncia Para compensar a ambigidade e reduzir
mal-entendidos, emprega-se muita
redundncia nas linguagens naturais, o que
freqentemente as torna prolixas. As
linguagens formais so menos redundantes e
mais concisas.
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 ambigidade no apenas freqente, 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 tokens 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 idia ler de cima para baixo, da esquerda para a
direita. Em vez disso, aprenda a analisar o programa na sua
cabea, identificando os tokens 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.
1.5 O primeiro programa
Tradicionalmente, o primeiro programa escrito
em uma nova linguagem de programao chamado de "Al,
Mundo!" porque tudo que ele faz apresentar as palavras
"Al, Mundo!". Em Python, ele assim:
pJ1h1 "A, huhdo!"
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:
A, huhdo!
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.
1.6 Glossrio
soluo de
problemas
O processo de formular um problema,
encontrar uma soluo e expressar esta
Captulo 1: O caminho do programa #16
Como pensar como um cientista da Computao usando Python
(problem
solving)
soluo.
linguagem de
alto nvel (high-
level language)
Uma linguagem de programao como
Python: projetada para ser fcil para os
seres humanos a 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)
portabilidade
(portability)
Propriedade que um programa tem, de
rodar em mais de um tipo de
computador.
interpretar
(interpret)
Executar um programa escrito em uma
linguagem de alto nvel, traduzindo-o
uma linha de cada vez.
compilar
(compile)
Traduzir todo um programa escrito em
uma linguagem de alto nvel para uma de
baixo nvel de um s vez, em preparao
para uma execuo posterior.
cdigo fonte
(source code)
Um programa em uma linguagem de alto
nvel, antes de ter sido compilado.
cdigo objeto
(object code)
A sada do compilador, depois que ele
traduziu o programa.
executvel
(executable)
Um outro nome para cdigo objeto que
est pronto para ser executado.
script Um programa guardado em um arquivo
(normalmente um que ser interpretado).
programa
(program)
Conjunto de instrues que especifica
uma computao.
(algorithm) categoria de problemas.
bug Erro em um programa.
depurao
(debugging)
O processo de encontrar e remover
qualquer um dos trs tipos de erros de
programao.
sintaxe (syntax) A estrutura de um programa.
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.
erro de
semntica
(semantic error)
Erro em um programa, que o leva a fazer
algo diferente do que pretendia o
programador.
semntica
(semantics)
O significado de um programa.
linguagem
natural (natural
language)
Qualquer lngua falada pelos seres
humanos que tenha evoludo
naturalmente.
linguagem
formal (formal
language)
Qualquer linguagem desenvolvida pelas
pessoas para propsitos especficos, tais
como, a representao de idias
matemticas ou programas de
computadores; todas as linguagens de
programao so linguagens formais.
tomo (token) Um elemento bsico da estrutura
sinttica de um programa, anlogo a uma
palavra em uma linguagem natural.
anlise sinttica
(parse)
Examinar um programa e analisar sua
estrutura sinttica.
comando print Instruo que leva o interpretador
Captulo 1: O caminho do programa #17
Como pensar como um cientista da Computao usando Python
(`print`
statement)
Python a apresentar um valor na tela.
Captulo 1: O caminho do programa #18
Como pensar como um cientista da Computao usando Python
Captulo 2: Variveis, expresses e comandos Captulo 2: Variveis, expresses e comandos
2.1 Valores e tipos
O valor (por exemplo, letras e nmeros) uma das coisas
fundamentais que um programa manipula. Os valores que j
vimos at agora foram o 2 (como resultado, quando
adicionamos 1 + 1) e "Al, Mundo!".
Esses valores pertencem a tipos diferentes: 2
um inteiro, e "Al, Mundo!" uma string, assim chamada
porque "string", em ingls, quer dizer seqncia, srie, cadeia
(de caracteres), ou neste caso, "srie de letras". Voc (e o
interpretador) consegue identificar strings porque elas
aparecem entre aspas.
O comando print tambm funciona com
inteiros:
>>> pJ1h1 4
4
Se voc estiver em dvida sobre qual o tipo de
um determinado valor, o interpretador pode revelar:
>>> 1ype{"A, huhdo!")
<1ype `s1J1hg`>
>>> 1ype{17)
<1ype `1h1`>
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
:
>>> 1ype{3.2)
<1ype `1oa1`>
O que dizer de valores como "17" e "3.2"? Eles
parecem nmeros, mas esto entre aspas, como strings:
>>> 1ype{"17")
<1ype `s1J1hg`>
>>> 1ype{"3.2")
<1ype `s1J1hg`>
Eles so strings.
Ao digitar um nmero grande, tentador usar
pontos entre grupos de trs dgitos, assim: 1.000.000. Isso no
funciona porque 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:
>>> pJ1h1 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.
2.2 Variveis
Uma das caractersticas mais poderosas de uma linguagem de
programao a habilidade de manipular variveis. Uma
1 N.T.: Observe o uso de ponto no lugar da vrgula para
separar a parte inteira da parte fracionria.
varivel um nome que se refere a um valor.
O comando de atribuio cria novas variveis e
d a elas valores:
>>> mehsagem = "E a1, 0ou1oJ?"
>>> h = 17
>>> p1 = 3.14159
Este exemplo faz trs atribuies. A primeira
atribui a string "E a, Doutor?" a uma nova varivel chamada
mensagem. A segunda d o valor inteiro 17 a n, e a terceira
atribui o nmero de ponto flutuante 3.14159 varivel
chamada pi.
Uma maneira comum de representar variveis
no papel escrever o nome delas com uma seta apontando
para o valor da varivel. Esse tipo de figura chamado de
diagrama de estado porque mostra em que estado cada
varivel est (pense nisso como o estado de esprito da
varivel). O diagrama a seguir mostra o resultado das
instrues de atribuio:
O comando print tambm funciona com
variveis:
>>> pJ1h1 mehsagem
E a1, 0ou1oJ?
>>> pJ1h1 h
17
>>> pJ1h1 p1
3.14159
Em cada um dos casos, o resultado o valor da
varivel. Variveis tambm tm tipo; novamente, podemos
perguntar ao interpretador quais so eles:
>>> 1ype{mehsagem)
<1ype `s1J1hg`>
>>> 1ype{h)
<1ype `1h1`>
>>> 1ype{p1)
<1ype `1oa1`>
O tipo de uma varivel o tipo do valor ao qual
ela se refere.
2.3 Nomes de variveis e palavras reservadas
Os programadores geralmente escolhem nomes significativos
para suas variveis -- eles documentam para o qu a varivel
usada.
Nomes de variveis podem ser arbitrariamente
longos. Eles podem conter tanto letras quanto nmeros, mas
Captulo 2: Variveis, expresses e comandos #19
Como pensar como um cientista da Computao usando Python
tm de comear com uma letra. Embora seja vlida a
utilizao de letras maisculas, por conveno, no usamos.
Se voc o fizer, lembre-se de que maisculas e minsculas so
diferentes. Bruno e bruno so variveis diferentes.
O caractere para sublinhado ( _ ) pode aparecer
em um nome. Ele muito utilizado em nomes com mltiplas
palavras, tal como em meu_nome ou preco_do_cha_na_china.
Se voc der a uma varivel um nome invlido,
causar um erro de sintaxe:
>>> 761Jombohes = "gJahde paJada"
Syh1axEJJoJ. 1hva1d syh1ax
>>> mu11o$ = 1000000
Syh1axEJJoJ. 1hva1d syh1ax
>>> cass = "C1ehc1as da Compu1acao 101"
Syh1axEJJoJ. 1hva1d syh1ax
76trombones invlida porque no comea com
uma letra. muito$ invlida porque contm um caractere
ilegal, o cifro. Mas o que est errado com class?
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:
ahd de1 exec 11 ho1 Je1uJh
asseJ1 de 11hay 1mpoJ1 oJ 1Jy
bJeak e11 1oJ 1h pass wh1e
cass ese 1Jom 1s pJ1h1 y1ed
coh11hue excep1 goba ambda Ja1se
Pode ser til ter essa lista mo. Se o
interpretador acusar erro sobre um de seus nomes de varivel
e voc no souber porqu, veja se o nome est na lista.
2.4 Comandos
Um comando uma instruo que o interpretador Python
pode executar. Vimos at agora dois tipos de comandos: de
exibio (print) e de atribuio.
Quando voc digita um comando na linha de
comando, o Python o executa e mostra o resultado, se houver
um. O resultado de um comando print a exibio de um
valor. Comandos de atribuio no produzem um resultado
visvel.
Um script normalmente contm uma seqncia
de comandos. Se houver mais de um comando, os resultados
aparecero um de cada vez, conforme cada comando seja
executado.
Por exemplo, o "script":
pJ1h1 1
x = 2
pJ1h1 2
produz a sada:
1
2
Novamente, o comando de atribuio no
produz sada.
2.5 Avaliando expresses
Uma expresso uma combinao de valores, variveis e
operadores. Se voc digitar uma expresso na linha de
comando, o interpretador avalia e exibe o resultado:
>>> 1 + 1
2
Embora expresses contenham valores,
variveis e operadores, nem toda expresso contm todos estes
elementos. Um valor por si s considerado uma expresso,
do mesmo modo que uma varivel:
>>> 17
17
>>> x
2
Avaliar uma expresso no exatamente a
mesma coisa que imprimir um valor:
>>> mehsagem = "E a1, 0ou1oJ?"
>>> mehsagem
`E a1, 0ou1oJ?`
>>> pJ1h1 mehsagem
E a1, 0ou1oJ?
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
[#]_. 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
"A, huhdo!"
1 + 1
no produz qualquer sada. Como voc mudaria
o "script" para exibir os valores destas quatro expresses?
2.6 Operadores e operandos
Operadores so smbolos especiais que representam
computaes como adio e multiplicao. Os valores que o
operador usa so chamados operandos.
Todas as expresses seguintes so vlidas em
Python e seus significados so mais ou menos claros:
20+32 hoJa-1 hoJa*60+m1hu1o m1hu1o/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:
>>> m1hu1o = 59
>>> m1hu1o/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
Captulo 2: Variveis, expresses e comandos #20
Como pensar como um cientista da Computao usando Python
como este, em que o inteiro seguinte est muito prximo:
>>> m1hu1o*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.
2.7 Ordem dos operadores
Quando mais de um operador aparece em uma expresso, a
ordem de avaliao depende das regras de precedncia.
Python segue as mesmas regras de precedncia para seus
operadores matemticos que a matemtica. O acrnimo
PEMDAS uma maneira prtica de lembrar a ordem das
operaes:
e Parnteses tm a mais alta precedncia e podem ser
usados para forar uma expresso a ser avaliada na
ordem que voc quiser. J que expresses entre
parnteses so avaliadas primeiro, 2 * (3-1) 4, e
(1+1)**(5-2) 8. Voc tambm pode usar parnteses
para tornar uma expresso mais fcil de ler, como em
(minuto * 100) / 60, ainda que isso no altere o
resultado.
e Exponenciao ou potenciao tem a prxima
precedncia mais alta, assim 2**1+1 3 e no 4, e
3*1**3 3 e no 27.
e Multiplicao e Diviso tm a mesma precedncia,
que mais alta do que a da Adio e da Subtrao,
que tambm tm a mesma precedncia. Assim 2*3-1
d 5 em vez de 4, e 2/3-1 -1, no 1 (lembre-se de
que na diviso inteira, 2/3=0).
e Operadores com a mesma precedncia so avaliados
da esquerda para a direita. Assim, na expresso
minuto*100/60, a multiplicao acontece primeiro,
resultando em 5900/60, o que se transforma
produzindo 98. Se as operaes tivessem sido
avaliadas da direita para a esquerda, o resultado
poderia ter sido 59*1, que 59, que est errado.
2.8 Operaes com strings
De maneira geral, voc no pode executar operaes
matemticas em strings, ainda que as strings se paream com
nmeros. O que segue invlido (assumindo que mensagem
do tipo string):
mehsagem-1 "A"/123 mehsagem*"A" "15"+2
Interessante o operador +, que funciona com
strings, embora ele no faa exatamente o que voc poderia
esperar. Para strings, o operador + representa concatenao,
que significa juntar os dois operandos ligando-os pelos
extremos. Por exemplo:
1Ju1a = "bahaha"
assada = " com cahea"
pJ1h1 1Ju1a + 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?
2.9 Composio
At agora, vimos os elementos de um programa -- variveis,
expresses, e instrues ou comandos -- isoladamente, sem
mencionar como combin-los.
Uma das caractersticas mais prticas das
linguagens de programao a possibilidade de pegar
pequenos blocos e combin-los numa composio. Por
exemplo, ns sabemos como somar nmeros e sabemos como
exibi-los; acontece que podemos fazer as duas coisas ao
mesmo tempo:
>>> pJ1h1 17 + 3
20
Na realidade, a soma tem que acontecer antes da
impresso, assim, as aes no esto na realidade acontecendo
ao mesmo tempo. O ponto que qualquer expresso
envolvendo nmeros, strings, e variveis pode ser usada
dentro de um comando print. Voc j tinha visto um exemplo
disto:
pJ1h1 "hmeJo de m1hu1os desde a me1a-ho11e. ", \
hoJa*60+m1hu1o
Esta possibilidade pode no parecer muito
impressionante agora, mas voc ver outros exemplos em que
a composio torna possvel expressar computaes
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.
2.11 Glossrio
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.
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).
ponto-
flutuante
(floating-point)
Formato para representar nmeros que
possuem partes fracionrias.
varivel
(variable)
Nome que se refere a um valor.
comando
(statement)
Trecho de cdigo que representa uma
instruo ou ao. At agora, os comandos
vistos foram de atribuio e exibio.
atribuio
(assignment)
Comando que atribui um valor a uma
varivel.
diagrama de
estado (state
diagram)
Representao grfica de um conjunto de
variveis e os valores aos quais elas se
referem.
Captulo 2: Variveis, expresses e comandos #21
Como pensar como um cientista da Computao usando Python
palavra-chave
(keyword)
Palavra reservada usada pelo compilador
para analisar o programa; voc no pode
usar palavras-chave como if, def, e while
como nomes de variveis.
operador
(operator)
Smbolo especial que representa uma
computao simples, como adio,
multiplicao ou concatenao de strings.
operando
(operand)
Um dos valores sobre o qual o operador
opera.
expresso
(expression)
Combinao de variveis, operadores e
valores, que representa um resultado nico.
avaliar
(evaluate)
Simplificar uma expresso atravs da
realizao de operaes, para produzir um
valor nico.
diviso inteira
(integer
division)
Operao que divide um inteiro por outro e
resulta em um inteiro. A diviso inteira
resulta no nmero de vezes que o
numerador divisvel pelo denominador e
descarta qualquer resto.
regras de
precedncia
(rules of
precedence)
O conjunto de regras que governa a ordem
em que expresses envolvendo mltiplos
operadores e operandos so avaliadas.
concatenar
(concatenate)
Juntar dois operandos lado a lado.
composio
(composition)
Habilidade de combinar expresses e
comandos simples em expresses e
comandos compostos, de forma a
representar computaes complexas de
forma concisa.
comentrio
(comment)
Informao em um programa dirigida a
outros programadores (ou qualquer pessoa
que esteja lendo o cdigo fonte) e que no
tem efeito na execuo do programa.
Captulo 2: Variveis, expresses e comandos #22
Como pensar como um cientista da Computao usando Python
Captulo 3: Funes Captulo 3: Funes
3.1 Chamadas de funes
Voc j viu um exemplo de uma chamada de funo:
>>> 1ype{`32`)
<1ype `s1J`>
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 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:
>>> b1a = 1ype{`32`)
>>> pJ1h1 b1a
<1ype `s1J`>
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:
>>> 1d{3)
134882108
>>> b1a = 3
>>> b1a{be1h)
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.
3.2 Converso entre tipos
Python prov uma coleo de funes nativas que convertem
valores de um tipo em outro. A funo int recebe um valor e o
converte para inteiro, se possvel, ou, se no, reclama:
>>> 1h1{`32`)
32
>>> 1h1{`A`)
vaueEJJoJ. 1hva1d 11eJa 1oJ 1h1{) . A
int tambm pode converter valores em ponto
flutuante para inteiro, mas lembre que isso trunca a parte
fracionria:
>>> 1h1{3.99999)
3
>>> 1h1{-2.3)
-2
A funo float converte inteiros e strings em
nmeros em ponto flutuante:
>>> 1oa1{32)
32.0
>>> 1oa1{`3.14159`)
3.14159
Finalmente, a funo str converte para o tipo
string:
>>> s1J{32)
`32`
>>> s1J{3.14149)
`3.14149`
Pode parecer curioso que Python faa distino
entre o valor inteiro 1 e o valor em ponto flutuante 1.0. Eles
podem representar o mesmo nmero, mas pertencem a tipos
diferentes. A razo que eles so representados de modo
diferente dentro do computador.
3.3 Coero entre tipos
Agora que podemos converter entre tipos, temos outra
maneira de lidar com a diviso inteira. Voltando ao exemplo
do captulo anterior, suponha que queiramos calcular a frao
de hora que j passou. A expresso mais bvia, minuto / 60,
faz aritmtica inteira, assim, o resultado sempre 0, mesmo
aos 59 minutos passados da hora.
Uma soluo converter minuto para ponto
flutuante e fazer a diviso em ponto flutuante:
>>> m1hu1o = 59
>>> 1oa1{m1hu1o) / 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:
>>> m1hu1o = 59
>>> m1hu1o / 60.0
0.983333333333
Fazendo o denominador um float, foramos o
Python a fazer a diviso em ponto flutuante.
3.4 Funes matemticas
Em matemtica, voc provavelmente j viu funes como
seno (sin) e log, e aprendeu a resolver expresses como
sin(pi/2) e log(1/x). Primeiro voc resolve e expresso entre
parnteses (o argumento). Por exemplo, pi/2
aproximadamente 1,571, e 1/x 0.1 (se x for 10,0).
A voc avalia a funo propriamente dita, seja
procurando numa tabela ou realizando vrios clculos. O sin
de 1,571 1 e o log de 0,1 -1 (assumindo que log indica o
logaritmo na base 10).
Este processo pode ser aplicado repetidamente
para avaliar expresses mais complicadas, como
log(1/sin(pi/2)). Primeiro voc avalia o argumento na funo
mais interna, depois avalia a funo e assim por diante.
Python tem um mdulo matemtico que prov a
maioria das funes matemticas mais familiares. Um mdulo
um arquivo que contm uma coleo de funes
relacionadas agrupadas juntas.
Antes de podermos usar as funes contidas em
um mdulo, temos de import-lo:
>>> 1mpoJ1 ma1h
Captulo 3: Funes #23
Como pensar como um cientista da Computao usando Python
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:
>>> dec1be = ma1h.og10{17.0)
>>> ahguo = 1.5
>>> a1uJa = ma1h.s1h{ahguo)
A primeira instruo atribui a decibel o
logaritmo de 17 na base 10. Existe tambm uma funo
chamada log, que pega o logaritmo na base e.
A terceira instruo encontra o seno do valor da
varivel angulo. sin e as outras funes trigonomtricas (cs,
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:
>>> gJaus = 45
>>> ahguo = gJaus * 2 * ma1h.p1 / 360.0
>>> ma1h.s1h{ahguo)
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:
>>> ma1h.sqJ1{2) / 2.0
0.707106781187
3.5 Composio
Do mesmo modo como nas funes matemticas, as funes
do Python podem ser compostas, o que significa que voc
pode usar uma expresso como parte de outra. Por exemplo,
voc pode usar qualquer expresso como um argumento para
uma funo:
>>> x = ma1h.cos{ahguo + p1/2)
Esta instruo toma o valor de pi, divide-o por
2, e soma o resultado ao valor de angulo. A soma ento
passada como um argumento para a funo cos.
Voc tambm pode pegar o resultado de uma
funo e pass-lo como um argumento para outra:
>>> x = ma1h.exp{ma1h.og{10.0))
Esta instruo encontra o logaritmo base e de 10
e ento eleva e quela potncia. O resultado atribudo a x.
3.6 Adicionando novas funes
At aqui, temos utilizado somente as funes que vm com
Python, mas tambm possvel adicionar novas funes. Criar
novas funes para resolver seus prprios problemas uma
das coisas mais teis de uma linguagem de programao de
propsito geral.
No contexto de programao, funo uma
seqncia nomeada de instrues ou comandos, que realizam
uma operao desejada. Esta operao especificada numa
definio de funo. At agora, as funes que usamos neste
livro so pr-definidas e suas definies no foram
apresentadas. Isso demonstra que podemos usar funes sem
ter que nos preocupar com os detalhes de suas definies.
A sintaxe para uma definio de funo :
de1 h0hE{ LTSTA 0E PARAhETR0S ) .
C0hAh00S
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:
de1 hovaL1hha{).
pJ1h1
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:
pJ1h1 `PJ1me1Ja L1hha.`
hovaL1hha{)
pJ1h1 `Seguhda L1hha.`
A sada deste programa :
PJ1me1Ja L1hha.
Seguhda L1hha.
Observe o espao extra entre as duas linhas. E
se quisssemos mais espao entre as linhas? Poderamos
chamar a mesma funo repetidamente:
pJ1h1 `PJ1me1Ja L1hha.`
hovaL1hha{)
hovaL1hha{)
hovaL1hha{)
pJ1h1 `Seguhda L1hha.`
Ou poderamos escrever uma nova funo
chamada tresLinhas, que produzisse trs novas linhas:
de1 1JesL1hhas{) .
hovaL1hha{)
hovaL1hha{)
hovaL1hha{)
pJ1h1 `PJ1me1Ja L1hha.`
1JesL1hhas{)
pJ1h1 `Seguhda L1hha.`
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:
e Criar uma nova funo permite que voc coloque
nome em um grupo de comandos. As funes podem
simplificar um programa ao ocultar uma computao
complexa por trs de um simples comando cujo
nome pode ser uma palavra em portugus, em vez de
algum cdigo misterioso.
Captulo 3: Funes #24
Como pensar como um cientista da Computao usando Python
e 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?
3.7 Definies e uso
Reunindo os fragmentos de cdigo da Seo 3.6, o programa
completo fica assim:
de1 hovaL1hha{) .
pJ1h1
de1 1JesL1hhas{) .
hovaL1hha{)
hovaL1hha{)
hovaL1hha{)
pJ1h1 `PJ1me1Ja L1hha.`
1JesL1hhas{)
pJ1h1 `Seguhda L1hha.`
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?
3.8 Fluxo de execuo
Para assegurar que uma funo esteja definida antes do seu
primeiro uso, preciso saber em que ordem os comandos so
executados, o que chamado de fluxo de execuo.
A execuo sempre comea com o primeiro
comando do programa. Os comandos so executados um de
cada vez, pela ordem, de cima para baixo.
As definies de funo no alteram o fluxo de
execuo do programa, mas lembre-se que comandos dentro
da funo no so executados at a funo ser chamada.
Embora no seja comum, voc pode definir uma funo
dentro de outra. Neste caso, a definio mais interna no
executada at que a funo mais externa seja chamada.
Chamadas de funo so como um desvio no
fluxo de execuo. Em vez de ir para o prximo comando, o
fluxo salta para a primeira linha da funo chamada, executa
todos os comandos l e ento volta atrs para retomar de onde
havia deixado.
Parece muito simples, at a hora em que voc
lembra que uma funo pode chamar outra. Enquanto estiver
no meio de uma funo, o programa poderia ter de executar os
comandos em uma outra funo. Mas enquanto estivesse
executando esta nova funo, o programa poderia ter de
executar ainda outra funo!
Felizmente, Python adepto de monitorar a
posio onde est, assim, cada vez que uma funo se
completa, o programa retoma de onde tinha parado na funo
que a chamou. Quando chega ao fim do programa, ele
termina.
Qual a moral dessa histria srdida? Quando
voc ler um programa, no o leia de cima para baixo. Em vez
disso, siga o fluxo de execuo.
3.9 Parmetros e argumentos
Algumas das funes nativas que voc j usou requerem
argumentos, aqueles valores que controlam como a funo faz
seu trabalho. Por exemplo, se voc quer achar o seno de um
nmero, voc tem que indicar qual nmero . Deste modo, sin
recebe um valor numrico como um argumento.
Algumas funes recebem mais de um
argumento. Por exemplo, pow recebe dois argumentos, a base
e o expoente. Dentro da funo, os valores que lhe so
passados so atribudos a variveis chamadas parmetros.
Veja um exemplo de uma funo definida pelo
usurio, que recebe um parmetro:
de1 1mpJ1me0obJado{bJuho).
pJ1h1 bJuho, bJuho
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:
>>> 1mpJ1me0oobJado{`Spam`)
Spam Spam
>>> 1mpJ1me0obJado{5)
5 5
>>> 1mpJ1me0obJado{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:
>>> 1mpJ1me0obJado{`Spam`*4)
SpamSpamSpamSpam SpamSpamSpamSpam
>>> 1mpJ1me0obJado{ma1h.cos{ma1h.p1))
-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.
Captulo 3: Funes #25
Como pensar como um cientista da Computao usando Python
Tambm podemos usar uma varivel como
argumento:
>>> m1gue = `EJ1c, 1he ha1 a bee.`
>>> 1mpJ1me0obJado{m1gue)
EJ1c, 1he ha1 a bee. EJ1c, 1he ha1 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.
3.10 Variveis e parmetros so locais
Quando voc cria uma varivel local dentro de uma funo,
ela s existe dentro da funo e voc no pode us-la fora de
l. Por exemplo:
de1 cohca10upa{paJ1e1, paJ1e2)
cohca1 = paJ1e1 + paJ1e2
1mpJ1me0obJado{cohca1)
Esta funo recebe dois argumentos, concatena-
os, e ento imprime o resultado duas vezes. Podemos chamar
a funo com duas strings:
>>> cah1o1 = `P1e Jesu dom1he, `
>>> cah1o2 = `doha e1s Jequ1em. `
>>> cohca10upa{cah1o1, cah1o2)
P1e Jesu dom1he, 0oha e1s Jequ1em. P1e Jesu dom1he, \
0oha e1s Jequ1em.
Quando a funo concatDupla termina, a
varivel concat destruda. Se tentarmos imprimi-la, teremos
um erro:
>>> pJ1h1 cohca1
hameEJJoJ. cohca1
Parmetros so sempre locais. Por exemplo,
fora da funo imprimeDobrado, no existe alguma coisa
chamada bruno. Se voc tentar utiliz-la, Python vai reclamar.
3.11 Diagramas da pilha
Para entender que variveis podem ser usadas aonde, s vezes
til desenhar um diagrama da pilha. Como os diagramas de
estado, diagramas da pilha mostram o valor de cada varivel,
mas tambm a funo qual cada varivel pertence.
Cada funo representada por um frame
(quadro). Um frame uma caixa com o nome de uma funo
ao lado dela e os parmetros e variveis da funo dentro dela.
O diagrama de pilha para o exemplo anterior tem a seguinte
aparncia:
A ordem da pilha mostra o fluxo de execuo.
imprimeDobrado foi chamado por concatDupla, e
concatDupla foi chamado por __main__ (principal), que um
nome especial para a funo mais no topo. Quando voc cria
uma varivel fora de qualquer funo, ela pertence
__main__.
Cada parmetro se refere ao mesmo valor que o
seu argumento correspondente. Assim, parte1 tem o mesmo
valor de canto1, parte2 tem o mesmo valor de canto2 e bruno
tem o mesmo valor de concat.
Se um erro acontece durante uma chamada de
funo, Python imprime o nome da funo, e o nome da
funo que a chamou, e o nome da funo que chamou a que
chamou, percorrendo todo o caminho de volta a __main__.
Por exemplo, se tentssemos acessar concat de
dentro de imprimeDobrado, teramos um NameError:
TJaceback {1hheJmos1 as1).
F1e "1es1e.py", 1he 13, 1h __ma1h__
cohca10upa{cah1o1, cah1o2)
F1e "1es1e.py", 1he 5, 1h cohca10upa
1mpJ1me0obJado{cohca1)
F1e "1es1e.py", 1he 9, 1h 1mpJ1me0obJado
pJ1h1 cohca1
hameEJJoJ. cohca1
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.
3.12 Funes com resultados
A essa altura, voc deve ter percebido que algumas das
funes que estamos usando, tais como as funes
matemticas, produzem resultados. Outras funes, como
novaLinha, executam uma ao, mas no retornam um valor.
O que levanta algumas questes:
1. O que acontece se voc chama uma funo e no faz
nada com o resultado (por exemplo, no atribui o
resultado a uma varivel ou o usa como parte de uma
expresso maior)?
2. O que acontece se voc usa uma funo que no
produz resultado em uma expresso tal como
novaLinha() + 7?
3. Voc pode escrever funes que produzem
resultados, ou est preso a funes como novaLinha e
imprimeDobrado?
A resposta para a terceira questo afirmativa e
ns vamos fazer isso no Captulo 5.
Captulo 3: Funes #26
Como pensar como um cientista da Computao usando Python
A ttulo de exerccio, responda as outras duas
questes testando-as. Se tiver dvida sobre o que vlido ou
invlido em Python, tente buscar a resposta perguntando ao
interpretador.
3.13 Glossrio
chamada de
funo
(function call)
Comando que executa uma funo.
Consiste do nome da funo seguido de
uma lista de argumentos entre parnteses.
argumento
(argument)
Valor fornecido a uma funo quando ela
chamada. Este valor atribudo ao
parmetro correspondente na funo.
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.
converso de
tipo (type
conversion)
Comando explcito que pega um valor de
um tipo e devolve o valor correspondente
em outro tipo.
coercividade de
tipo (type
coercion)
Uma converso de tipo que ocorre
automaticamente, de acordo com as regras
de coercividade do Python.
mdulo
(module)
Arquivo que contm uma coleo de
funes e classes relacionadas entre si.
notao de
ponto (dot
notation)
A sintaxe para chamar uma funo que
est em outro mdulo, especificando o
nome do mdulo, seguido por um ponto
(.) e o nome da funo.
funo
(function)
Seqncia de comandos nomeada, que
realiza alguma tarefa til. As funes
podem ou no receber parmetros e
podem ou no retornar valores.
definio de
funo
(function
definition)
Comando que cria uma nova funo,
especificando seu nome, parmetros e
comandos que ela executa.
fluxo de
execuo (flow
of execution)
A ordem na qual os comandos so
executados durante a execuo do
programa.
parmetro
(parameter)
Nome usado numa funo para referir-se
ao valor passado como argumento.
varivel local
(local variable)
Varivel definida dentro da funo. Uma
varivel local s pode ser usada dentro da
funo onde foi definida.
diagrama da
pilha (stack
diagram)
Representao grfica da pilha de funes,
suas variveis e os valores aos quais elas
se referem.
frame Retngulo no diagrama da pilha que
representa uma chamada de funo.
Contm as variveis locais e os
parmetros da funo.
traceback Lista de funes que esto em execuo,
impressa quando um erro de execuo
ocorre.
Captulo 3: Funes #27
Como pensar como um cientista da Computao usando Python
Captulo 4: Condicionais e recursividade Captulo 4: Condicionais e recursividade
4.1 O operador mdulo
O operador mdulo trabalha com inteiros (e expresses que
tm inteiros como resultado) e produz o resto da diviso do
primeiro pelo segundo. Em Python, o operador mdulo um
smbolo de porcentagem (%). A sintaxe a mesma que a de
outros operadores:
>>> quoc1eh1e = 7 / 3
>>> pJ1h1 quoc1eh1e
2
>>> Jes1o = 7 3
>>> pJ1h1 Jes1o
1
Ento, 7 dividido por 3 2 e o resto 1.
O operador mdulo se revela
surpreendentemente til. Por exemplo, voc pode checar se
um nmero divisvel por outro - se x % y d zero, ento x
divisvel por y.
Voc tambm pode extrair o algarismo ou
algarismos mais direita de um nmero. Por exemplo, x % 10
resulta o algarismo mais direita de x (na base 10).
Similarmente, x % 100 resulta nos dois dgitos mais direita.
4.2 Expresses booleanas
Uma expresso booleana uma expresso que verdadeira
(true) ou falsa (false). Em Python, uma expresso que
verdadeira tem o valor 1, e uma expresso que falsa tem o
valor 0.
O operador == compara dois valores e produz
uma expresso booleana:
>>> 5 == 5
TJue
>>> 5 == 6
Fase
No primeiro comando, os dois operadores so
iguais, ento a expresso avalia como True (verdadeiro); no
segundo comando, 5 no igual a 6, ento temos False (falso).
O operador == um dos operadores de
comparao; os outros so:
x != y # x d11eJeh1e de y
x > y # x ma1oJ que y
x < y # x mehoJ que y
x >= y # x ma1oJ ou 1gua a y
x <= y # x mehoJ ou 1gua 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 =>.
4.3 Operadores lgicos
Existem trs operadores lgicos: and, or, not (e, ou, no). A
semntica (significado) destes operadores similar aos seus
significados em ingls (ou portugus). Por exemplo, x > 0 and
x < 10 verdadeiro somente se x for maior que 0 e menor que
10.
n%2 == 0 or n%3 == 0 verdadeiro se qualquer
das condies for verdadeira, quer dizer, se o nmero n for
divisvel por 2 ou por 3.
Finalmente, o operador lgico not nega uma
expresso booleana, assim, not(x > y) verdadeiro se (x > y)
for falso, quer dizer, se x for menor ou igual a y.
A rigor, os operandos de operadores lgicos
deveriam ser expresses booleanas, mas Python no muito
rigoroso. Qualquer nmero diferente de zero interpretado
como verdadeiro (True):
>>> x = 5
>>> x ahd 1
1
>>> y = 0
>>> y ahd 1
0
Em geral, esse tipo de coisa no considerado
de bom estilo. Se voc precisa comparar um valor com zero,
deve faz-lo explicitamente.
4.4 Execuo condicional
Para poder escrever programas teis, quase sempre
precisamos da habilidade de checar condies e mudar o
comportamento do programa de acordo com elas. As
instrues condicionais nos do essa habilidade. A forma
mais simples a instruo if (se):
11 x > 0
pJ1h1 "x pos111vo"
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:
CABECALh0.
PRThETR0 C0hAh00
...
bLTTh0 C0hAh00
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
Captulo 4: Condicionais e recursividade #28
Como pensar como um cientista da Computao usando Python
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
no faz nada.
4.5 Execuo alternativa
Um segundo formato da instruo if a execuo alternativa,
na qual existem duas possibilidades e a condio determina
qual delas ser executada. A sintaxe se parece com:
11 x 2 == 0.
pJ1h1 x, " paJ"
ese.
pJ1h1 x, " 1mpaJ"
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 sinal, se voc precisa checar a paridade de
nmeros com freqncia, pode colocar este cdigo dentro de
uma funo:
de1 1mpJ1mePaJ1dade{x).
11 x 2 == 0.
pJ1h1 x, " paJ"
ese.
pJ1h1 x, " 1mpaJ"
Para qualquer valor de x, imprimeParidade
exibe uma mensagem apropriada. Quando voc a chama, pode
fornecer uma expresso de resultado inteiro como um
argumento:
>>> 1mpJ1mePaJ1dade{17)
>>> 1mpJ1mePaJ1dade{y+1)
4.6 Condicionais encadeados
s vezes existem mais de duas possibilidades e precisamos de
mais que dois ramos. Uma condicional encadeada uma
maneira de expressar uma computao dessas:
11 x < y.
pJ1h1 x, " mehoJ que", y
e11 x > y.
pJ1h1 x, " ma1oJ que", y
ese.
pJ1h1 x, "e", y, "so 1gua1s"
elif uma abreviao de "else if" ("ento 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:
11 escoha == `A`.
1uhcaoA{)
e11 escoha == `B`.
1uhcaoB{)
e11 escoha == `C`.
1uhcaoC{)
ese.
pJ1h1 "Escoha 1hv1da."
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).
4.7 Condicionais aninhados
Um condicional tambm pode ser aninhado dentro de outra.
Poderamos ter escrito o exemplo tricotmico (dividido em
trs) como segue:
11 x == y.
pJ1h1 x, "e", y, "so 1gua1s"
ese.
11 x < y.
pJ1h1 x, " mehoJ que", y
ese.
pJ1h1 x, " ma1oJ que", y
O condicional mais externo tem dois ramos. O
primeiro ramo contm uma nica instruo de sada. O
segundo ramo contm outra instruo if, que por sua vez tem
dois ramos. Os dois ramos so ambos instrues de sada,
embora pudessem conter instrues condicionais tambm.
Embora a endentao das instrues torne a
estrutura aparente, condicionais aninhados tornam-se difceis
de ler rapidamente. Em geral, uma boa idia evitar o
aninhamento quando for possvel.
Operadores lgicos freqentemente fornecem
uma maneira de simplificar instrues condicionais aninhadas.
Por exemplo, podemos reescrever o cdigo a seguir usando
uma nica condicional:
11 0 < x.
11 x < 10.
pJ1h1 "x um hmeJo pos111vo de um s
agaJ1smo."
A instruo print executada somente se a
fizermos passar por ambos os condicionais, ento, podemos
usar um operador and:
11 0 < x ahd x < 10.
pJ1h1 "x um hmeJo pos111vo de um s agaJ1smo."
Esses tipos de condio so comuns, assim,
Phython prov uma sintaxe alternativa que similar notao
matemtica:
11 0 < x < 10.
pJ1h1 "x um hmeJo pos111vo de um s agaJ1smo."
4.8 A instruo return
O comando return permite terminar a execuo de uma funo
antes que ela alcance seu fim. Uma razo para us-lo se voc
detectar uma condio de erro:
1mpoJ1 ma1h
de1 1mpJ1meLogaJ11mo{x).
11 x <= 0.
pJ1h1 "Someh1e hmeJos pos111vos, poJ 1avoJ."
Je1uJh
Jesu1ado = ma1h.og{x)
pJ1h1 "0 og de x ", Jesu1ado
A funo imprimeLogaritmo recebe um
Captulo 4: Condicionais e recursividade #29
Como pensar como um cientista da Computao usando Python
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.
4.9 Recursividade
J mencionamos que vlido uma funo chamar outra
funo, e voc viu vrios exemplos disso. Mas ainda no
tnhamos dito que tambm vlido uma funo chamar a si
mesma. Talvez no seja bvio porque isso bom, mas trata-se
de uma das coisas mais mgicas e interessantes que um
programa pode fazer. Por exemplo, d uma olhada na seguinte
funo:
de1 coh1agemRegJess1va{h).
11 h == 0.
pJ1h1 "Fogo!"
ese.
pJ1h1 h
coh1agemRegJess1va{h-1)
contagemRegressiva espera que o parmetro, n,
seja um inteiro positivo. Se n for 0, ela produz como sada a
palavra "Fogo!". De outro modo, ela produz como sada n e
ento chama uma funo de nome contagemRegressiva -- ela
mesma -- passando n-1 como argumento.
O que acontece se chamarmos essa funo da
seguinte maneira:
>>> coh1agemRegJess1va{3)
A execuo de contagemRegressiva comea
com n=3, e desde que n no 0, produz como sada o valor 3,
e ento chama a si mesma...
A execuo de contagemRegressiva comea
com n=2, e desde que n no 0, produz como sada o valor 2,
e ento chama a si mesma...
A execuo de contagemRegressiva comea
com n=1, e desde que n no 0, produz como sada o valor 1,
e ento chama a si mesma...
A execuo de contagemRegressiva comea
com n=0, e desde que n 0, produz como sada a palavra
"Fogo!" e ento retorna.
A contagemRegressiva que tem n=1 retorna.
A contagemRegressiva que tem n=2 retorna.
A contagemRegressiva que tem n=1 retorna.
E ento estamos de volta em __main__ (que
viagem!). Assim, a sada completa se parece com:
3
2
1
Fogo!
Como um segundo exemplo, d uma olhada
novamente nas funes novaLinha e tresLinhas:
de1 hovaL1hha{).
pJ1h1
de1 1JesL1hhas{).
hovaL1hha{)
hovaL1hha{)
hovaL1hha{)
Muito embora isso funcione, no seria muito
til se precisssemos gerar como sada 2 novas linhas, ou 106.
Uma alternativa melhor seria esta:
de1 hL1hhas{h).
11 h > 0.
pJ1h1
hL1hhas{h-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.
4.10 Diagramas de pilha para funes recursivas
Na Seo 3.11, usamos um diagrama de pilha para representar
o estado de um programa durante uma chamada de funo. O
mesmo tipo de diagrama pode ajudar a interpretar uma funo
recursiva.
Toda vez que uma funo chamada, Python
cria um novo quadro (frame) para a funo, que contm as
variveis locais e parmetros da funo. Para uma funo
recursiva, ter que existir mais de um quadro na pilha ao
mesmo tempo.
Esta figura mostra um diagrama de pilha para
contagemRegressiva, chamada com n = 3:
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.
Captulo 4: Condicionais e recursividade #30
Como pensar como um cientista da Computao usando Python
4.11 Recursividade infinita
Se uma recursividade nunca chega ao caso base, ela prossegue
fazendo chamadas recursivas para sempre, e o programa
nunca termina. Isto conhecido como recursividade infinita, e
geralmente no considerada uma boa idia. Aqui est um
programa mnimo com uma recursividade infinita:
de1 JecuJs1va{).
JecuJs1va{)
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:
F1e "<s1d1h>", 1he 2, 1h JecuJs1va
{98 Jepe1111ohs om111ed)
F1e "<s1d1h>", 1he 2, 1h JecuJs1va
Ruh11meEJJoJ. hax1mum JecuJs1oh dep1h 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.
4.12 Entrada pelo teclado
Os programas que temos escrito at agora so um pouco crus,
no sentido de no aceitarem dados entrados pelo usurio. Eles
simplesmente fazem a mesma coisa todas as vezes.
Python fornece funes nativas que pegam
entradas pelo teclado. A mais simples chamada raw_input.
Quando esta funo chamada, o programa pra e espera que
o usurio digite alguma coisa. Quando o usurio aperta a tecla
Enter ou Return, o programa prossegue e a funo raw_input
retorna o que o usurio digitou como uma string:
>>> eh1Jada = Jaw_1hpu1{)
0 que voc es1 espeJahdo?
>>> pJ1h1 eh1Jada
0 que voc es1 espeJahdo?
Antes de chamar raw_input, uma boa idia
exibir uma mensagem dizendo ao usurio o que ele deve
entrar. Esta mensagem uma deixa (prompt). Podemos suprir
uma deixa como um argumento para raw_input:
>>> home = Jaw_1hpu1{"0ua... o seu home? ")
0ua... o seu home? AJ1huJ, Re1 dos BJe1es!
>>> pJ1h1 home
AJ1huJ, Re1 dos BJe1es!
Se esperamos que a entrada seja um inteiro,
podemos usar a funo input:
de1xa = "0ua... a veoc1dade de vo de uma \
ahdoJ1hha?\h"
veoc1dade = 1hpu1{de1xa)
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:
>>> veoc1dade = 1hpu1{de1xa)
0ua... a veoc1dade de vo de uma ahdoJ1hha?
0e qua voc 1aa, uma ahdoJ1hha A1J1caha ou uma \
EuJop1a?
Syh1axEJJoJ. 1hva1d syh1ax
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.
4.13 Glossrio
operador
mdulo
(modulus
operator)
Operador denotado por um smbolo de
porcentagem (%), que trabalha com
inteiros e retorna o resto da diviso de um
nmero por outro.
expresso
booleana
(boolean
expression)
Uma expresso que verdadeira ou falsa.
operador de
comparao
(comparison
operator)
Um dos operadores que compara dois
valores: ==, !=, >, <, >=, e <=.
operador lgico
(logical
operator)
Um dos operadores que combina
expresses booleanas: and, or, e not.
comando
condicional
(conditional
statement)
Comando que controla o fluxo de
execuo dependendo de alguma
condio.
condio
(condition)
A expresso booleana que determina qual
bloco ser executado num comando
condicional.
comando
composto
(compound
statement)
Comando que consiste de um cabealho e
um corpo. O cabealho termina com um
dois-pontos (:). O corpo endentado em
relao ao cabealho.
bloco (block) Grupo de comandos consecutivos com a
mesma endentao.
corpo (body) O bloco que se segue ao cabealho em
um comando composto.
aninhamento
(nesting)
Estrutura de programa dentro da outra,
como um comando condicional dentro de
um bloco de outro comando condicional.
recursividade
(recursion)
O processo de chamar a prpria funo
que est sendo executada.
caso base (base
case)
Bloco de comando condicional numa
funo recursiva que no resulta em uma
chamada recursiva.
recurso infinita
(infinite
recursion)
Funo que chama a si mesma
recursivamente sem nunca chegar ao caso
base. Aps algum tempo, uma recurso
infinita causa um erro de execuo.
deixa (prompt) Indicao visual que diz ao usurio que o
programa est esperando uma entrada de
dados.
Captulo 4: Condicionais e recursividade #31
Como pensar como um cientista da Computao usando Python
Captulo 5: Funes frutferas Captulo 5: Funes frutferas
5.1 Valores de retorno
Algumas das funes nativas do Python que temos usado,
como as funes matemticas, produziram resultados. Chamar
a funo gerou um novo valor, o qual geralmente atribumos
uma varivel ou usamos como parte de uma expresso:
e = ma1h.exp{1.0)
a1uJa = Ja1o * ma1h.s1h{ahguo)
Mas at agora, nenhuma das funes que ns
mesmos escrevemos retornou um valor.
Neste captulo, iremos escrever funes que
retornam valores, as quais chamaremos de funes frutferas,
ou funes que do frutos, na falta de um nome melhor. O
primeiro exemplo area, que retorna a rea de um crculo
dado o seu raio:
1mpoJ1 ma1h
de1 aJea{Ja1o).
1emp = ma1h.p1 * Ja1o**2
Je1uJh 1emp
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:
de1 aJea{Ja1o).
Je1uJh ma1h.p1 * Ja1o**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:
de1 vaoJAbsou1o{x).
11 x < 0.
Je1uJh -x
ese.
Je1uJh 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 subseqente.
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 idia
assegurar que todo caminho possvel dentro do programa
encontre uma instruo return. Por exemplo:
de1 vaoJAbsou1o{x).
11 x < 0.
Je1uJh -x
e11 x > 0.
Je1uJh 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:
>>> pJ1h1 vaoJAbsou1o{0)
hohe
Como exerccio, escreva uma funo compare
que retorne 1 se x > y, 0 se x == y e -1 se x < y.
5.2 Desenvolvimento de programas
Neste ponto, voc deve estar apto a olhar para funes
completas e dizer o que elas fazem. Tambm, se voc vem
fazendo os exerccios, voc escreveu algumas pequenas
funes. Conforme escrever funes maiores, voc pode
comear a ter mais dificuldade, especialmente com erros em
tempo de execuo (erros de runtime) ou erros semnticos.
Para lidar com programas de crescente
complexidade, vamos sugerir uma tcnica chamada
desenvolvimento incremental. A meta do desenvolvimento
incremental evitar sees de depurao (debugging) muito
longas pela adio e teste de somente uma pequena quantidade
de cdigo de cada vez.
Como exemplo, suponha que voc queira
encontrar a distncia entre dois pontos, dados pelas
coordenadas (x1,y1) e (x2,y2). Pelo teorema de Pitgoras, a
distncia :
distancia=
.
(( x2-xJ)

+( y2-yJ)

) i
O primeiro passo considerar como deveria ser
uma funo distancia em Python. Em outras palavras, quais
so as entradas (parmetros) e qual a sada (valor de
retorno)?
Neste caso, os dois pontos so as entradas, os
quais podemos representar usando quatro parmetros. O valor
de retorno a distncia, que um valor em ponto flutuante.
J podemos escrever um esboo da funo:
de1 d1s1ahc1a{x1, y1, x2, y2).
Je1uJh 0.0
Obviamente, esta verso da funo no computa
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:
>>> d1s1ahc1a{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.
Captulo 5: Funes frutferas #32
Como pensar como um cientista da Computao usando Python
Um primeiro passo lgico nesta computao
encontrar as diferenas x2 - x1 e y2 - y1. Ns iremos guardar
estes valores em variveis temporrias chamadas dx e dy e
imprimi-las:
de1 d1s1ahc1a{x1, y1, x2, y2).
dx = x2 - x1
dy = y2 - y1
pJ1h1 "dx vae", dx
pJ1h1 "dy vae", dy
Je1uJh 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 a primeira
computao corretamente. Se no, existem poucas linhas para
checar.
Em seguida, computaremos a soma dos
quadrados de dx e dy:
de1 d1s1ahc1a{x1, y1, x2, y2).
dx = x2 - x1
dy = y2 - y1
dquadJado = dx**2 + dy**2
pJ1h1 "dquadJado vae. ", dquadJado
Je1uJh 0.0
Note que removemos os comandos print que
havamos escrito no passo anterior. Cdigo como este
chamado de andaime porque ajuda a escrever o programa,
mas no parte do produto final.
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:
de1 d1s1ahc1a{x1, x2, y1, y2).
dx = x2 - x1
dy = y2 - y1
dquadJado = dx**2 + dy**2
Jesu1ado = ma1h.sqJ1{dquadJado)
Je1uJh Jesu1ado
Se isto funcionar corretamente, voc conseguiu.
Caso contrrio, talvez fosse preciso imprimir (exibir) o valor
de resultado antes da instruo return.
Enquanto for iniciante, voc deve acrescentar
apenas uma ou duas linhas de cdigo de cada vez. Conforme
ganhar mais experincia, voc se ver escrevendo e depurando
pedaos maiores. De qualquer modo, o processo de
desenvolvimento incremental pode poupar um bocado de
tempo de depurao.
Os aspectos chave do processo so:
1. Comece com um programa que funciona e faa
pequenas mudanas incrementais. Em qualquer ponto
do 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 andaime
(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.
5.3 Composio
Conforme voc poderia esperar agora, voc pode chamar uma
funo de dentro de outra. Esta habilidade chamada de
composio.
Como um exemplo, vamos escrever uma funo
que recebe dois pontos, o centro de um crculo e um ponto em
seu permetro, e calcula a rea do crculo.
Assuma que o ponto do centro est guardado
nas variveis xc e yc, e que o ponto do permetro est nas
variveis xp e yp. O primeiro passo encontrar o raio do
crculo, o qual a distncia entre os dois pontos. Felizmente,
temos uma funo, distancia, que faz isto:
Ra1o = d1s1ahc1a{xc, yc, xp, yp)
O segundo passo encontrar a rea de um
crculo com o raio dado e retorn-la:
Jesu1ado = aJea{Ja1o)
Je1uJh Jesu1ado
Juntando tudo numa funo, temos:
de1 aJea2{xc, yc, xp, yp).
Ja1o = d1s1ahc1a{xc, yc, xp, yp)
Jesu1ado = aJea{Ja1o)
Je1uJh Jesu1ado
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:
de1 aJea2{xc, yc, xp, yp).
Je1uJh aJea{d1s1ahc1a{xc, yc, xp, yp))
Como exerccio, escreva uma funo
inclinacao(x1, y1, x2, y2) que retorne a inclinao (ou
coeficienteAngular?) 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).
5.4 Funes booleanas
Funes podem retornar valores booleanos, o que muitas
vezes conveniente por ocultar testes complicados dentro de
funes. Por exemplo:
de1 eh01v1s1ve{x, y).
T1 x y == 0.
Je1uJh TJue # veJdade1Jo {1Jue), d1v1s1ve
ese.
Je1uJh Fase # 1aso {1ase), ho d1v1s1ve
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:
Captulo 5: Funes frutferas #33
Como pensar como um cientista da Computao usando Python
de1 eh01v1s1ve{x, y).
Je1uJh x y == 0
Esta sesso mostra a nova funo em ao:
>>> eh01v1s1ve{6, 4)
Fase
>>> eh01v1s1ve{6, 3)
TJue
Funes booleanas so freqentemente usadas
em comandos condicionais:
11 eh01v1s1ve{x, y).
pJ1h1 "x d1v1s1ve poJ y"
ese.
pJ1h1 "x ho d1v1s1ve poJ y"
Mas a comparao extra desnecessria.
Como exerccio, escreva uma funo
estaEntre(x, y, z) que retorne True se y < x < z ou False se
no.
5.5 Mais recursividade
At aqui, voc aprendeu apenas um pequeno subconjunto da
linguagem Python, mas pode ser que te interesse saber que
este pequeno subconjunto uma linguagem de programao
completa, o que significa que qualquer coisa que possa ser
computada pode ser expressa nesta linguagem. Qualquer
programa j escrito pode ser reescrito usando somente os
aspectos da linguagem que voc aprendeu at agora
(usualmente, voc precisaria de uns poucos comandos para
controlar dispositivos como o teclado, mouse, discos, etc., mas
isto tudo).
Provar esta afirmao um exerccio nada
trivial, que foi alcanado pela primeira vez por Alan Turing,
um dos primeiros cientistas da computao (algum poderia
dizer que ele foi um matemtico, mas muitos dos primeiros
cientistas da computao comearam como matemticos). Por
isso, ficou conhecido como Tese de Turing. Se voc fizer um
curso em Teoria da Computao, voc ter chance de ver a
prova.
Para te dar uma idia do que voc pode fazer
com as ferramentas que aprendeu a usar at agora, vamos
avaliar algumas funes matemticas recursivamente
definidas. Uma definio recursiva similar uma definio
circular, no sentido de que a definio faz referncia coisa
que est sendo definida. Uma verdadeira definio circular
no muito til:
vorpal: adjetivo usado para descrever algo que
vorpal.
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
h! = h.{h-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:
de1 1a1oJ1a{h).
Se acontece de o argumento ser 0, tudo o que
temos de fazer retornar 1:
de1 1a1oJ1a{h).
11 h == 0.
Je1uJh 1
Por outro lado, e esta a parte interessante,
temos que fazer uma chamada recursiva para encontrar o
fatorial de n-1 e ento multiplic-lo por n:
de1 1a1oJ1a{h).
11 h == 0.
Je1uJh 1
ese.
JecuJs1vo = 1a1oJ1a{h-1)
Jesu1ado = h * JecuJs1vo
Je1uJh Jesu1ado
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
1, e o resultado, 6, se torna o valor de retorno da chamada de
funo que iniciou todo o processo.
Eis o diagrama de pilha para esta seqncia de
chamadas de funo:
Os valores de retorno so mostrados sendo
passados de volta para cima da pilha. Em cada quadro, o valor
de retorno o valor de resultado, o qual o produto de n por
recursivo.
5.6 Voto de confiana (Leap of faith)
Seguir o fluxo de execuo uma maneira de ler programas,
mas que pode rapidamente se transformar em um labirinto.
Uma alternativa o que chamamos de "voto de confiana".
Quando voc tem uma chamada de funo, em vez de seguir o
fluxo de execuo, voc assume que a funo funciona
corretamente e retorna o valor apropriado.
Captulo 5: Funes frutferas #34
Como pensar como um cientista da Computao usando Python
De fato, voc est agora mesmo praticando este
voto de confiana ao usar as funes nativas. Quando voc
chama math.cos ou math.exp, voc no examina a
implementao destas funes. Voc apenas assume que elas
funcionam porque as pessoas que escreveram as bibliotecas
nativas eram bons programadores.
O mesmo tambm verdade quando voc
chama uma de suas prprias funes. Por exemplo, na Seo
5.4, escrevemos a funo chamada ehDivisivel que determina
se um nmero divisvel por outro. Uma vez que nos
convencemos que esta funo est correta -- ao testar e
examinar o cdigo -- podemos usar a funo sem examinar o
cdigo novamente.
O mesmo tambm verdadeiro para programas
recursivos. Quando voc tem uma chamada recursiva, em vez
de seguir o fluxo de execuo, voc poderia assumir que a
chamada recursiva funciona (produz o resultado correto) e
ento perguntar-se, "Assumindo que eu possa encontrar o
fatorial de n-1, posso calcular o fatorial de n?" Neste caso,
claro que voc pode, multiplicando por n.
Naturalmente, um pouco estranho que uma
funo funcione corretamente se voc ainda nem terminou de
escrev-la, mas por isso que se chama voto de confiana!
5.7 Mais um exemplo
No exemplo anterior, usamos variveis temporrias para
explicitar (spell out XXX) os passos e tornar o cdigo mais
fcil de depurar, mas poderamos ter economizado algumas
linhas:
de1 1a1oJ1a{h).
11 h == 0.
Je1uJh 1
ese.
Je1uJh h * 1a1oJ1a{h-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:
11bohacc1{0) = 1
11bohacc1{1) = 1
11bohacc1{h) = 11bohacc1{h-1) + 11bohacc1{h-2),
Traduzido em Python, parecer assim:
de1 11bohacc1{h).
11 h == 0 oJ h == 1.
Je1uJh 1
ese.
Je1uJh 11bohacc1{h-1) + 11bohacc1{h-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.
5.8 Checagem de tipos
O que acontece se chamamos fatorial e damos a ela 1.5 como
argumento?:
>>> 1a1oJ1a {1.5)
Ruh11meEJJoJ. hax1mum JecuJs1oh dep1h exceeded
Parece um caso de recursividade infinita. Mas o
que ser que de fato? Existe um caso base -- quando n == 0.
O problema que o valor de n nunca encontra o caso base.
Na primeira chamada recursiva, o valor de n
0.5. Na prxima, ele igual a -0.5. Da em diante, ele se torna
cada vez menor, mas jamais ser 0.
Temos ento duas alternativas. Podemos tentar
generalizar a funo fatorial para que funcione com nmeros
em ponto flutuante, ou fazemos fatorial realizar a checagem
de tipo de seus parmetros. A primeira chamada funo
gamma e est um pouco alm do escopo deste livro. Sendo
assim, ficaremos com a segunda.
Podemos usar type para comparar o tipo do
parmetro com o tipo de um valor inteiro conhecido (como 1).
Ao mesmo tempo em que fazemos isto, podemos nos
certificar tambm de que o parmetro seja positivo:
de1 1a1oJ1a {h).
11 1ype{h) != 1ype{1).
pJ1h1 "Fa1oJ1a someh1e de11h1do paJa
1h1e1Jos."
Je1uJh -1
e11 h < 0.
pJ1h1 "Fa1oJ1a someh1e de11h1do paJa 1h1e1Jos\
pos111vos."
Je1uJh -1
e11 h ==0.
Je1uJh 1
ese.
Je1uJh h * 1a1oJ1a{h-1)
Agora temos trs casos base. O primeiro pega os
no-inteiros. O segundo pega os inteiros negativos. Em ambos
os casos, o programa exibe uma mensagem de erro e retorna
um valor especial, -1, para indicar que alguma coisa saiu
errada:
>>> 1a1oJ1a {"FJed")
Fa1oJ1a someh1e de11h1do paJa 1h1e1Jos.
-1
>>> 1a1oJ1a {-2)
Fa1oJ1a someh1e de11h1do paJa 1h1e1Jos pos111vos.
-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.
5.9 Glossrio
funo frutfera
(fruitful function)
Uma funo que produz um valor de
retorno.
valor de retorno
(return value)
O valor entregue como resultado de uma
chamada de funo.
varivel
temporria
(temporary
variable)
Uma varivel usada para guardar um
valor intermedirio em um clculo
complexo.
cdigo morto
(dead code)
Parte de um programa que nunca pode
ser executada, muitas vezes por que ela
aparece depois de uma instruo return.
Captulo 5: Funes frutferas #35
Como pensar como um cientista da Computao usando Python
None Um valor especial em Python, retornado
por funes que no possuem uma
instruo return ou tm uma instruo
return sem argumento.
desenvolvimento
incremental
(incremental
development)
Uma estratgia de desenvolvimento de
programas que evita a depurao ao
adicionar e testar somente uma pequena
quantidade de cdigo de cada vez.
andaime
(scaffolding)
Cdigo usado durante o
desenvolvimento do programa, mas que
no faz parte do produto final.
guardio
(guardian)
Uma condio que checa e manipula
circunstncias que poderiam causar um
erro.
Captulo 5: Funes frutferas #36
Como pensar como um cientista da Computao usando Python
Captulo 6: Iterao Captulo 6: Iterao
6.1 Reatribuies
Como voc talvez j tenha descoberto, permitido fazer mais
de uma atribuio mesma varivel. Uma nova atribuio faz
uma varivel existente referir-se a um novo valor (sem se
referir mais ao antigo).:
bJuho = 5
pJ1h1 bJuho,
bJuho = 7
pJ1h1 bJuho
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:
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 agoJa so 1gua1s
b = 3 # a e b ho so ma1s 1gua1s
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.
6.2 O comando while
Os computadores so muito utilizados para automatizar tarefas
repetitivas. Repetir tarefas idnticas ou similares sem cometer
erros uma coisa que os computadores fazem bem e que as
pessoas fazem poorly.
Vimos dois programas, nLinhas e
contagemRegressiva, que usam recursividade (recurso) para
fazer a repetio, que tambm chamada iterao. Porque a
iterao muito comum, Python tem vrias caractersticas
para torn-la mais fcil. A primeira delas em que vamos dar
uma olhada o comando while.
Aqui est como fica contagemRegressiva com
um comando while:
de1 coh1agemRegJess1va{h).
wh1e h > 0.
pJ1h1 h
h = h-1
pJ1h1 "Fogo!"
Desde que removemos a chamada recursiva,
esta funo no recursiva.
Voc quase pode ler o comando while como se
fosse Ingls. Ele significa, "Enquanto (while) n for maior do
que 0, siga exibindo o valor de n e diminuindo 1 do valor de
n. Quando chegar a 0, exiba a palavra Fogo!".
Mais formalmente, aqui est o fluxo de
execuo para um comando while:
1. Teste a condio, resultando 0 ou 1.
2. Se a condio for falsa (0), saia do comando while e
continue a execuo a partir do prximo comando.
3. Se a condio for verdadeira (1), execute cada um
dos comandos dentro do corpo e volte ao passo 1.
O corpo consiste de todos os comandos abaixo
do cabealho, com a mesma endentao.
Este tipo de fluxo chamado de um loop (ou
lao) porque o terceiro passo cria um "loop" ou um lao de
volta ao topo. Note que se a condio for falsa na primeira vez
que entrarmos no loop, os comandos dentro do loop jamais
sero executados.
O corpo do loop poderia alterar o valor de uma
ou mais variveis de modo que eventualmente a condio se
torne falsa e o loop termine. Se no for assim, o loop se
repetir para sempre, o que chamado de um loop infinito.
Uma fonte de diverso sem fim para os cientistas da
computao a observao de que as instrues da
embalagem de shampoo, "Lave, enxge, repita" um loop
infinito.
No caso de contagemRegressiva, podemos
provar que o loop terminar porque sabemos que o valor de n
finito, e podemos ver que o valor de n diminui dentro de
cada repetio (iterao) do loop, ento, eventualmente
chegaremos ao 0. Em outros casos, isto no to simples de
afirmar:
de1 sequehc1a{h).
wh1e h != 1.
pJ1h1 h,
11 h2 == 0. # h paJ
h = h/2
ese. # h 1mpaJ
h = h*3+1
Captulo 6: Iterao #37
Como pensar como um cientista da Computao usando Python
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.
6.3 Tabelas
Uma das coisas para qual os loops so bons para gerar dados
tabulares. Antes que os computadores estivessem readily
disponveis, as pessoas tinham que calcular logaritmos, senos,
cossenos e outras funes matemticas mo. Para tornar isto
mais fcil, os livros de matemtica continham longas tabelas
listando os valores destas funes. Criar as tabelas era
demorado e entediante, e elas tendiam a ser cheias de erros.
Quando os computadores entraram em cena,
uma das reaes iniciais foi "Isto timo! Podemos usar
computadores para geras as tabelas, assim no haver erros."
Isto veio a se tornar verdade (na maioria das vezes) mas
shortsighted. Rapidamente, porm, computadores e
calculadoras tornaram-se to pervasivos que as tabelas ficaram
obsoletas.
Bem, quase. Para algumas operaes, os
computadores usam tabelas de valores para conseguir uma
resposta aproximada e ento realizar clculos para melhorar a
aproximao. Em alguns casos, tm havido erros nas tabelas
underlying, o caso mais famoso sendo o da tabela usada pelo
processador Pentium da Intel para executar a diviso em
ponto-flutuante.
Embora uma tabela de logaritmos no seja mais
to til quanto j foi um dia, ela ainda d um bom exemplo de
iterao. O seguinte programa gera uma seqncia de valores
na coluna da esquerda e seus respectivos logaritmos na coluna
da direita:
x = 1.0
wh1e x < 10.0.
pJ1h1 x, `\1`, ma1h.og{x)
x = x + 1.0
A string '\t' representa um caracter de
tabulao.
Conforme caracteres e strings vo sendo
mostrados na tela, um ponteiro invisvel chamado cursor
marca aonde aparecer o prximo caractere. Depois de um
comando print, o cursor normalmente vai para o incio de uma
nova linha.
O caractere de tabulao desloca o cursor para a
direita at que ele encontre uma das marcas de tabulao.
Tabulao til para fazer colunas de texto line up, como na
sada do programa anterior:
1.0 0.0
2.0 0.69314718056
3.0 1.09861228867
4.0 1.38629436112
5.0 1.60943791243
6.0 1.79175946923
7.0 1.94591014906
8.0 2.07944154168
9.0 2.19722457734
Se estes valores parecem odd, lembre-se que a
funo log usa a base e. J que potncias de dois so to
importantes em cincia da computao, ns freqentemente
temos que achar logaritmos referentes base 2. Para fazermos
isso, podemos usar a seguinte frmula:
Alterando o comando de sada para:
pJ1h1 x, `\1`, ma1h.og{x)/ma1h.og{2.0)
o que resultar em:
1.0 0.0
2.0 1.0
3.0 1.58496250072
4.0 2.0
5.0 2.32192809489
6.0 2.58496250072
7.0 2.80735492206
8.0 3.0
9.0 3.16992500144
Podemos ver que 1, 2, 4 e 8 so potncias de
dois porque seus logaritmos na base 2 so nmeros redondos.
Se precisssemos encontrar os logaritmos de outras potncias
de dois, poderamos modificar o programa deste modo:
x = 1.0
wh1e x < 100.0.
pJ1h1 x, `\1`, ma1h.og{x)/ma1h.og{2.0)
x = x * 2.0
Agora, em vez de somar algo a x a cada iterao
do loop, o que resulta numa seqncia aritmtica, ns
multiplicamos x por algo, resultando numa seqncia
geomtrica. O resultado :
1.0 0.0
2.0 1.0
4.0 2.0
8.0 3.0
16.0 4.0
32.0 5.0
64.0 6.0
Por causa do caractere de tabulao entre as
colunas, a posio da segunda coluna no depende do nmero
de dgitos na primeira coluna.
Tabelas de logaritmos podem no ser mais teis,
mas para cientistas da computao, conhecer as potncias de
dois !
Como um exerccio, modifique este programa
de modo que ele produza as potncias de dois acima de 65.535
(ou seja, 216). Imprima e memorize-as.
O caractere de barra invertida em '\t' indica o
incio de uma seqncia de escape. Seqncias de escape so
usadas para representar caracteres invisveis como de
tabulao e de nova linha. A seqncia \n representa uma nova
linha.
Captulo 6: Iterao #38
Como pensar como um cientista da Computao usando Python
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
pJoduza
es1a
sa1da.
6.4 Tabelas de duas dimenses (ou bi-dimensionais)
Uma tabela de duas dimenses uma tabela em que voc l o
valor na interseo entre uma linha e uma coluna. Uma tabela
de multiplicao um bom exemplo. Digamos que voc
queira imprimir uma tabela de multiplicao de 1 a 6.
Uma boa maneira de comear escrever um
loop que imprima os mltiplos de 2, todos em uma linha:
1 = 1
wh1e 1 <= 6.
pJ1h1 2*1, ` `,
1 = 1 + 1
pJ1h1
A primeira linha inicializa a varivel chamada i,
a qual age como um contador ou varivel de controle do
loop. Conforme o loop executado, o valor de i
incrementado de 1 a 6. Quando i for 7, o loop termina. A cada
repetio (iterao) do loop, mostrado o valor de 2*i,
seguido de trs espaos.
De novo, a vrgula no comando print suprime a
nova linha. Depois que o loop se completa, o segundo
comando print inicia uma nova linha.
A sada do programa :
2 4 6 8 10 12
At aqui, tudo bem. O prximo passo
encapsular e generalizar.
6.5 Encapsulamento e generalizao
Encapsulamento o processo de wrapping um pedao de
cdigo em uma funo, permitindo que voc tire vantagem de
todas as coisas para as quais as funes so boas. Voc j viu
dois exemplos de encapsulamento: imprimeParidade na seo
4.5; e eDivisivel na seo 5.4
Generalizao significa tomar algo que
especfico, tal como imprimir os mltiplos de 2, e torn-lo
mais geral, tal como imprimir os mltiplos de qualquer inteiro.
Esta funo encapsula o loop anterior e
generaliza-o para imprimir mltiplos de n:
de1 1mpJ1mehu11pos{h).
1 = 1
wh1e 1 <= 6.
pJ1h1 h*1, `\1 `,
1 = 1 + 1
pJ1h1
Para encapsular, tudo o que tivemos que fazer
foi adicionar a primeira linha, que declara o nome de uma
funo e sua lista de parmetros. Para generalizar, tudo o que
tivemos que fazer foi substituir o valor 2 pelo parmetro n.
Se chamarmos esta funo com o argumento 2,
teremos a mesma sada que antes. Com o argumento 3, a sada
:
3 6 9 12 15 18
Com o argumento 4, a sada :
4 8 12 16 20 24
Agora voc provavelmente pode adivinhar
como imprimir uma tabela de multiplicao - chamando
imprimeMultiplos repetidamente com argumentos diferentes.
De fato, podemos usar um outro loop:
1 = 1
wh1e 1 <= 6.
1mpJ1mehu11pos{1)
1 = 1 + 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
6.6 Mais encapsulamento
Para demonstrar de novo o encapsulamento, vamos pegar o
cdigo do final da seo 6.5 e acondicion-lo, envolv-lo em
uma funo:
de1 1mpJ1meTabhu1{).
1 = 1
wh1e 1 <= 6.
1mpJ1mehu11pos{1)
1 = 1 + 1
Este processo um plano de desenvolvimento
comum. Ns desenvolvemos cdigo escrevendo linhas de
cdigo fora de qualquer funo, ou digitando-as no
interpretador. Quando temos o cdigo funcionando, extramos
ele e o embalamos em uma funo.
Este plano de desenvolvimento
particularmente til se voc no sabe, quando voc comea a
escrever, como dividir o programa em funes. Esta tcnica
permite a voc projetar enquanto desenvolve.
6.7 Variveis locais
Voc pode estar pensando como podemos utilizar a mesma
varivel, i, em ambos, imprimeMultiplos e imprimeTabMult.
Isto no causaria problemas quando uma das funes mudasse
o valor da varivel?
A resposta no, porque o i em
imprimeMultiplos e o i em imprimeTabMult no so a mesma
varivel.
Variveis criadas dentro de uma definio de
funo so locais; voc no pode acessar uma varivel local
de fora da funo em que ela "mora". Isto significa que voc
livre para ter mltiplas variveis com o mesmo nome, desde
que elas no estejam dentro da mesma funo.
O diagrama de pilha para este programa mostra
Captulo 6: Iterao #39
Como pensar como um cientista da Computao usando Python
que duas variveis chamadas i no so a mesma varivel. Elas
podem se referir a valores diferentes e alterar o valor de uma
no afeta outra.
O valor de i em imprimeTabMult vai de 1 a 6.
No diagrama, i agora 3. Na prxima iterao do loop i ser
4. A cada iterao do loop, imprimeTabMult chama
imprimeMultiplos com o valor corrente de i como argumento.
O valor atribudo ao parmetro n.
Dentro de imprimeMultiplos, o valor de i vai de
1 a 6. No diagrama, i agora 2. Mudar esta varivel no tem
efeito sobre o valor de i em imprimeTabMult.
comum e perfeitamente legal ter variveis
locais diferentes com o mesmo nome. Em particular, nomes
como i e j so muito usados para variveis de controle de
loop. Se voc evitar utiliz-los em uma funo s porque voc
j os usou em outro lugar, voc provavelmente tornar seu
programa mais difcil de ler.
6.8 Mais generalizao
Como um outro exemplo de generalizao, imagine que voc
precise de um programa que possa imprimir uma tabela de
multiplicao de qualquer tamanho, no apenas uma tabela de
seis por seis. Voc poderia adicionar um parmetro a
imprimeTabMult:
de1 1mpJ1meTabhu1{a1uJa).
1 = 1
wh1e 1 <= a1uJa.
1mpJ1mehu11pos{1)
1 = 1 + 1
Ns substitumos o valor 6 pelo parmetro
altura. Se chamarmos imprimeTabMult com o argumento 7,
ela mostra:
1 2 3 4 5 6
2 4 6 8 10 12
3 6 9 12 15 18
4 8 12 16 20 24
5 10 15 20 25 30
6 12 18 24 30 36
7 14 21 28 35 42
Isto bom, exceto que ns provavelmente
quereramos que a tabela fosse quadrada - com o mesmo
nmero de linhas e colunas. Para fazer isso, adicionamos
outro parmetro a imprimeMultiplos para especificar quantas
colunas a tabela deveria ter.
S para confundir, chamamos este novo
parmetro de altura, demonstrando que diferentes funes
podem ter parmetros com o mesmo nome (como acontece
com as variveis locais). Aqui est o programa completo:
de1 1mpJ1mehu11pos{h, a1uJa).
1 = 1
wh1e 1 <= a1uJa.
pJ1h1 h*1, `1`,
1 = 1 + 1
pJ1h1
de1 1mpJ1meTabhu1{a1uJa).
1 = 1
wh1e 1 <= a1uJa.
1mpJ1mehu11pos{1, a1uJa)
1 = 1 + 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:
1mpJ1meTabhu1{1, a1uJa)
para:
1mpJ1meTabhu1{1, 1)
e voc ter:
1
2 4
3 6 9
4 8 12 16
5 10 15 20 25
6 12 18 24 30 36
7 14 21 28 35 42 49
Como um exerccio, trace a execuo desta
verso de imprimeTabMult e explique como ela funciona.
6.9 Funes
e H pouco tempo mencionamos "todas as coisas para
as quais as funes so boas." Agora, voc pode estar
pensando que coisas exatamente so estas. Aqui esto
algumas delas:
e Dar um nome para uma seqncia de comandos torna
seu programa mais fcil de ler e de depurar.
e Dividir um programa longo em funes permite que
voc separe partes do programa, depure-as
isoladamente, e ento as componha em um todo.
e Funes facilitam tanto recurso quanto iterao.
e Funes bem projetadas so freqentemente teis
para muitos programas. Uma vez que voc escreva e
depure uma, voc pode reutiliz-la.
Captulo 6: Iterao #40
Como pensar como um cientista da Computao usando Python
6.10 Glossrio
reatribuio
(multiple
assignment
1
)
quando mais de um valor atribudo a
mesma varivel durante a execuo do
programa.
iterao
(iteration)
execuo repetida de um conjunto de
comandos/instrues (statements) usando
uma chamada recursiva de funo ou um
lao (loop).
lao (loop) um comando/instruo ou conjunto de
comandos/instrues que executam
repetidamente at que uma condio de
interrupo seja atingida.
lao infinito
(infinite loop)
um lao em que a condio de interrupo
nunca ser atingida.
corpo (body) o conjunto de comandos/instrues que
pertencem a um lao.
varivel de lao
(loop variable)
uma varivel usada como parte da
condio de interrupo do lao.
tabulao (tab) um carcter especial que faz com que o
cursor mova-se para a prxima parada
estabelecida de tabulao na linha atual.
nova-linha
(newline)
um carcter especial que faz com que o
cursor mova-se para o incio da prxima
linha.
cursor (cursor) um marcador invisvel que determina
onde o prximo carcter var ser impresso.
sequncia de
escape (escape
sequence)
um carcter de escape () seguido por um
ou mais caracteres imprimveis, usados
para definir um carcter no imprimvel.
encapsular
(encapsulate)
quando um programa grande e complexo
dividido em componentes (como
funes) e estes so isolados um do outro
(pelo uso de variveis locais, por
exemplo).
generalizar
(generalize)
quando algo que desnecessariamente
especfico (como um valor constante)
substitudo por algo apropriadamente
geral (como uma varivel ou um
parmetro). Generalizaes do maior
versatilidade ao cdigo, maior
possibilidade de reuso, e em algumas
situaes at mesmo maior facilidade para
escrev-lo.
plano de
desenvolviment
o (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.
1 N.T.: O termo multiple assignment (ou atribuio mltipla)
usado com mais frequncia para descrever a sintaxe a = b
= c. Por este motivo optamos pelo termo reatribuio no
contexto da seo 6.1 desse captulo.
Captulo 6: Iterao #41
Como pensar como um cientista da Computao usando Python
Captulo 7: Strings Captulo 7: Strings
7.1 Um tipo de dado composto
At aqui, vimos trs diferentes tipos de dado: int, float e
string. Strings so qualitativamente diferentes dos outros dois
tipos porque so feitas de pedaos menores - caracteres.
Tipos que consistem de pedaos menores so
chamados tipos de dados compostos. Dependendo do que
estejamos fazendo, pode ser que precisemos tratar um tipo de
dado composto como uma coisa nica, ou pode ser que
queiramos acessar suas partes. Esta ambigidade til.
O operador colchete seleciona um nico
caractere de uma string.:
>>> 1Ju1a = "bahaha"
>>> e1Ja = 1Ju1a|1]
>>> pJ1h1 e1Ja
A expresso fruta[1] seleciona o caractere
nmero 1 de fruta. A varivel letra referencia ou refere-se ao
resultado da expresso. Quando exibimos letra, temos uma
surpresa:
a
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:
>>> e1Ja = 1Ju1a|0]
>>> pJ1h1 e1Ja
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.
7.2 Comprimento
A funo len retorna o nmero de caracteres de uma string:
>>> 1Ju1a = "bahaha"
>>> eh{1Ju1a)
6
Para pegar a ltima letra de uma string, voc
pode ficar tentado a fazer alguma coisa assim:
compJ1meh1o = eh{1Ju1a)
u11ma = 1Ju1a|compJ1meh1o] # ERR0!
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:
compJ1meh1o = eh{1Ju1a)
u11ma = 1Ju1a|compJ1meh1o-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.
7.3 Travessia e o loop for
Vrias computaes envolvem o processamento de uma string
um caractere de cada vez. Muitas vezes elas comeam com o
primeiro, selecionam um de cada vez, fazem alguma coisa
com ele, e continuam at o fim. Este padro de processamento
chamado uma travessia (traversal, com a idia de
"percorrimento"). Uma maneira de codificar uma travessia
com um comando while:
1hd1ce = 0
wh1e 1hd1ce < eh{1Ju1a).
e1Ja = 1Ju1a|1hd1ce]
pJ1h1 e1Ja
1hd1ce = 1hd1ce + 1
Este loop percorre a string e exibe cada letra em
sua prpria linha. A condio do loop indice < len(fruta),
assim, quando ndice igual ao comprimento da string, a
condio se torna falsa, e o corpo do loop no executado. O
ltimo caractere acessado aquele com o ndice len(fruta)-1,
que vem a ser o ltimo caractere da string.
Como um exerccio, escreva uma funo que
tome uma string como argumento e devolva suas letras de
trs para frente, uma por linha.
Usar um ndice para percorrer um conjunto de
valores to comum que Python oferece uma sintaxe
alternativa simplificada - o loop for:
1oJ chaJ 1h 1Ju1a.
pJ1h1 chaJ
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 McCloskey's 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:
pJe11xos = "JKLhh0P0"
su11xo = "ack"
1oJ e1Ja 1h pJe11xos.
pJ1h1 e1Ja + su11xo
A sada deste programa :
Jack
Kack
Captulo 7: Strings #42
Como pensar como um cientista da Computao usando Python
Lack
hack
hack
0ack
Pack
0ack
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.
7.4 Fatias de strings
Um segmento de uma string chamado de uma fatia.
Selecionar uma fatia similar a selecionar um caractere:
>>> s = "PedJo, Pauo e haJ1a"
>>> pJ1h1 s|0.5]
PedJo
>>> pJ1h1 s|7.12]
Pauo
>>> pJ1h1 s|16.21]
haJ1a
O operador [n:m] retorna a parte da string do
"n-simo" caractere ao "m-simo" caractere, incluindo o
primeiro mas excluindo o ltimo. Este comportamento no
intuitivo; ele faz mais sentido se voc imaginar os ndices
apontando para os intervalos entre os caracteres, como no
seguinte diagrama:
Se voc omitir o primeiro ndice (antes dos dois
pontos ":"), a fatia comea do incio da string. Se voc omitir
o segundo ndice, a fatia vai at o final da string. Assim:
>>> 1Ju1a = "bahaha"
>>> 1Ju1a|.3]
`bah`
>>> 1Ju1a|3.]
`aha`
O que voc acha de s[:] significa?
7.5 Comparao de strings
O operador de comparao funciona com strings. Para ver se
duas strings so iguais:
11 paavJa == "bahaha".
pJ1h1 "S1m, hs ho 1emos bahahas!"
Outras operaes de comparao so teis para
colocar palavras em ordem alfabtica:
11 paavJa < "bahaha".
pJ1h1 "Sua paavJa," + paavJa + ", vem ah1es de\
bahaha."
e11 paavJa > "bahaha".
pJ1h1 "Sua paavJa," + paavJa + ", vem depo1s \
de bahaha."
ese.
pJ1h1 "S1m, hs ho 1emos bahahas!"
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 paavJa, ZebJa, vem ah1es de bahaha.
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.
7.6 Strings so imutveis
tentador usar o operador [] no lado esquerdo de uma
expresso de atribuio, com a inteno de alterar um
caractere em uma string. Por exemplo:
saudacao = "A, muhdo!"
saudacao|0] = `E` # ERR0!
pJ1h1 saudacao
Em vez de produzir a sada El, Mundo!, este
cdigo produz o erro em tempo de execuo (runtime error):
TypeError: object doesn't 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 = "A, muhdo!"
hovaSaudacao = `E` + saudao|1.]
pJ1h1 hovaSaudacao
A soluo aqui concatenar uma nova primeira
letra com uma fatia de saudao. Esta operao no tem
nenhum efeito sobre a string original.
7.7 Uma funo find (encontrar)
O que faz a seguinte funo?:
de1 11hd{s1J, ch).
1hd1ce = 0
wh1e 1hd1ce < eh{s1J).
11 s1J|1hd1ce] == ch.
Je1uJh 1hd1ce
1hd1ce = 1hd1ce + 1
Je1uJh -1
Num certo sentido, find (encontrar) o oposto
do operador []. Em vez de pegar um ndice e extrair o
caractere correspondente, ela pega um caractere e encontra
(finds) em qual ndice aquele caractere aparece. Se o caractere
no encontrado, a funo retorna -1.
Este o primeiro exemplo que vemos de uma
instruo return dentro de um loop. Se str[indice] == ch, a
funo retorna imediatamente, abandonando o loop
prematuramente.
Se o caractere no aparece na string, ento o
programa sai do loop normalmente e retorna -1.
Este padro de computao s vezes chamado
de travessia "eureka", porque to logo ele encontra (find) o
que est procurando, ele pode gritar "Eureka!" e parar de
procurar.
Como um exerccio, modifique a funo find
Captulo 7: Strings #43
Como pensar como um cientista da Computao usando Python
(encontrar) de modo que ela receba um terceiro parmetro, o
ndice da string por onde ela deve comear sua procura.
7.8 Iterando e contando
O programa seguinte conta o nmero e vezes que a letra a
aparece em uma string:
1Ju1a = "bahaha"
coh1adoJ = 0
1oJ e1Ja 1h 1Ju1a.
11 e1Ja == `a`
coh1adoJ = coh1adoJ + 1
pJ1h1 coh1adoJ
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 a's.
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.
7.9 O mdulo string
O mdulo string contm funes teis que manipulam strings.
Conforme usual, ns temos que importar o mdulo antes que
possamos utiliz-lo:
>>> 1mpoJ1 s1J1hg
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.:
>>> 1Ju1a = "bahaha"
>>> 1hd1ce = s1J1hg.11hd{1Ju1a, "a")
>>> pJ1h1 1hd1ce
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:
>>> s1J1hg.11hd{"bahaha", "ha")
2
Alm disso, ela recebe um argumento adicional
que especifica o ndice pelo qual ela deve comear sua
procura:
>>> s1J1hg.11hd{"bahaha", "ha", 3)
4
Ou ela pode receber dois argumentos adicionais
que especificam o intervalo de ndices:
>>> s1J1hg.11hd{"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.
7.10 Classificao de caracteres
Muitas vezes til examinar um caractere e testar se ele
maisculo ou minsculo, ou se ele um caractere ou um
dgito. O mdulo string oferece vrias constantes que so teis
para esses propsitos.
A string string.lowercase contm todas as letras
que o sistema considera como sendo minsculas.
Similarmente, string.uppercase contm todas as letras
maisculas. Tente o seguinte e veja o que voc obtm:
>>> pJ1h1 s1J1hg.oweJcase
>>> pJ1h1 s1J1hg.uppeJcase
>>> pJ1h1 s1J1hg.d1g11s
Ns podemos usar essas constantes e find
(encontrar) para classificar caracteres. Por exemplo, se
find(lowercase, ch) retorna um valor outro que no -1, ento
ch deve ser minsculo:
de1 eh1huscuo{ch).
Je1uJh s1J1hg.11hd{s1J1hg.oweJcase, ch) != -1
Como uma alternativa, podemos tirar vantagem
do operador in, que determina se um caractere aparece em
uma string:
de1 eh1huscuo{ch).
Je1uJh ch 1h s1J1hg.oweJcase
Ainda, como uma outra alternativa, podemos
usar o operador de comparao:
de1 eh1huscuo{ch).
Je1uJh `a` <= ch <= `z`
Se ch estiver entre a e z, ele deve ser uma letra
minscula.
Como um exerccio, discuta que verso de
eMinusculo voc acha que ser a mais rpida. Voc pode
pensar em outras razes alm da velocidade para preferir
uma em vez de outra?
Outra constante definida no mdulo string pode
te surpreender quando voc executar um print sobre ela:
>>> pJ1h1 s1J1hg.wh11espace
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.
7.11 Glossrio
tipo de dado
composto
(compound
data type)
Um tipo de dado no qual o valor consiste de
componentes, ou elementos, que so eles
mesmos valores.
travessia
(traverse)
Iterar atravs dos elementos de um conjunto,
realizando uma operao similar em cada um
Captulo 7: Strings #44
Como pensar como um cientista da Computao usando Python
deles.
ndice (index) Uma varivel ou valor usados para
selecionar um membro de um conjunto
ordenado, como um caractere em uma string.
fatia (slice) Uma parte de uma string especificada por
um intervalo de ndices.
mutvel
(mutable)
Um tipo de dado composto a cujos
elementos podem ser atribudos novos
valores.
contador
(counter)
Uma varivel utilizada para contar alguma
coisa, usualmente inicializada em zero e
ento incrementada.
incrementar
(increment)
aumentar o valor de uma varivel em 1.
decrementar
(decrement)
diminuir o valor de uma varivel em 1.
espaamento
(whitespace)
Qualquer um dos caracteres que move o
cursor sem imprimir caracteres visveis. A
constante string.whitespace contm todos os
caracteres de espaamento.
7.11 Glossrio2
tipo de dado
composto
(compound
data type)
Um tipo de dado em que os valores so
compostos de componentes, ou elementos,
que podem ser tratados como valores
separados.
atravessar
(traverse)
Iterar atravs dos elementos definidos,
executando uma operao similar em cada.
ndice (index) Uma varivel ou valor usado para selecionar
um membro de uma definio ordenada,
como um caractere de uma string.
fatia (slice) Uma parte da string especificada por um
intervalo de ndice.
mutvel
(mutable)
Um tipo de dado composto do qual
elementos podem atribuir novos valores.
contador
(counter)
Uma varivel usada para contar alguma
coisa, geralmente iniciada em zero e
incrementada.
incremento
(increment)
Para aumentar o valor da varivel.
decremento
(decrement)
Para dimiuir o valor da varivel.
espao em
branco
(whitespace)
Qualquer caractere que move o cursor sem
imprimir caracteres visveis. A constante
string.whitespace contm todos os
caracteres de espao em branco.
Captulo 7: Strings #45
Como pensar como um cientista da Computao usando Python
Captulo 8: Listas Captulo 8: Listas
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.
8.1 Valores da lista
Existem vrias maneiras de criar uma nova lista; a mais
simples envolver os elementos em colchetes ([ e ]):
>>> |10, 20, 30, 40]
>>> |`spam`, `buhgee`, `swaow`]
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:
>>> |`ao`, 2.0, 5, |10,20]]
Uma lista dentro de outra lista dita estar
aninhada.
Listas que contm inteiros consecutivos so
comuns, ento Python fornece uma maneira simples de cri-
los:
>>> Jahge{1,5)
|1, 2, 3, 4]
A funo range pega dois argumentos e devolve
uma lista que contm todos os inteiros do primeiro at o
segundo, incluindo o primeiro mas no incluindo o segundo!
Existem outras formas de range. Com um
argumento simples, ela cria uma lista que inicia em 0:
>>> Jahge{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:
>>> Jahge{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.
>>> vocabuaJ1o = |`mehoJaJ`, `cas11gaJ`, \
`de1ehes1JaJ`]
>>> humeJos = |17, 123]
>>> vaz1o = |]
>>> pJ1h1 vocabuaJ1o, humeJos, vaz1o
|`mehoJaJ`, `cas11gaJ`, `de1ehes1JaJ`] |17, 123] |]
8.2 Acessado elementos
A sintaxe para acessar os elementos de uma lista a mesma
que a sintaxe para acessar os caracteres de uma string XXX o
operator colchete ([]). A expresso dentro dos colchetes
especifica o ndice. Lembre-se que os ndices iniciam em 0:
>>> pJ1h1 humeJos|0]
>>> humeJos|1]= 5
O operador colchete pode aparecer em qualquer
lugar em uma expresso. Quando ele aparece no lado
esquerdo de uma atribuio, ele modifica um dos elementos
em uma lista, de forma que o um-simo elemento de numeros,
que era 123, agora 5.
Qualquer expresso inteira pode ser utilizada
como um ndice:
>>> humeJos|3-2]
5
>>> humeJos|1.0]
TypeEJJoJ. sequehce 1hdex mus1 be 1h1egeJ
Se voc tentar ler ou escrever um elemento que
no existe, voc recebe um erro de tempo de execuo
(runtime error):
>>> humeJos|2]=5
ThdexEJJoJ. 1s1 ass1ghmeh1 1hdex ou1 o1 Jahge
Se um ndice possui um valor negativo, ele
conta ao contrrio a partir do final da lista:
>>> humeJos|-1]
5
>>> humeJos|-2]
17
>>> humeJos|-3]
ThdexEJJoJ. 1s1 1hdex ou1 o1 Jahge
numeros[-1] o ltimo elemento da lista,
numeros[-2] o penltimo e numeros[-3] no existe.
comum utilizar uma varivel de lao como um
ndice da lista:
>>> cavae1Jos = |`gueJJa`, `1ome`, `pes1e`, `moJ1e`]
1 = 0
wh1e 1 < 4.
pJ1h1 cavae1Jos|1]
1 = 1 + 1
Este lao while conta de 0 at 4. Quando a
varivel do lao i 4, a condio falha e o lao se encerra.
Desta forma o corpo do lao executado somente quando i
0, 1, 2 e 3.
Em cada vez dentro do lao, a varivel i
utilizada como um ndice para a lista, exibindo o i-simo
elemento. Este padro de computao chamado de percurso
na lista.
8.3 Comprimento da lista
A funo len devolve o comprimento de uma lista. uma boa
idia utilizar este valor como o limite superior de um lao ao
invs de uma constante. Desta forma, se o tamanho da lista
Captulo 8: Listas #46
Como pensar como um cientista da Computao usando Python
mudar, voc no precisar ir atravs de todo o programa
modificando todos os laos; eles funcionaro corretamente
para qualquer tamanho de lista:
>>> cavae1Jos = |`gueJJa`, `1ome`, `pes1e`, `moJ1e`]
1 = 0
wh1e 1 < eh{cavae1Jos).
pJ1h1 cavae1Jos|1]
1 = 1 + 1
A ltima vez que o corpo do lao executado, i
len(cavaleiros) - 1, que o ndice do ltimo elemento.
Quando i igual a len(cavaleiros), a condio falha e o corpo
no executado, o que uma boa coisa, porque
len(cavaleiros) no um ndice legal.
Embora uma lista possa conter uma outra lista, a
lista aninhada ainda conta como um elemento simples. O
comprimento desta lista quatro:
>>> |`spam!`, 1, |`BJ1e`, `Roque1oJ1`, \
`Po 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?
8.4 Membros de uma lista
in um operador lgico que testa se um elemento membro
de uma seqncia. Ns o utilizamos na Seo 7.10 com
strings, mas ele tambm funciona com listas e outras
seqncias:
>>> cavae1Jos = |`gueJJa`, `1ome`, `pes1e`, `moJ1e`]
>>> `pes1e` 1h cavae1Jos
TJue
>>> `depJavao` 1h cavae1Jos
Fase
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:
>>> ``depJavao`` ho1 1h cavae1Jos
TJue
8.5 Listas e laos for
O lao for que vimos na Seo 7.3 tambm funciona com
listas. A sintaxe generalizada de um lao for :
1oJ vARTAvEL 1h LTSTA.
C0RP0
Esta declarao equivalente a:
>>> 1 = 0
wh1e 1 < eh{LTST).
vARTABLE = LTST|1]
XXX B00Y
1 = 1 + 1
O lao for mais conciso porque podemos
eliminar a varivel do lao, i. Aqui est o lao anterior escrito
com um`lao for:
>>> 1oJ cavae1Jo 1h cavae1Jos.
pJ1h1 cavae1Jo
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:
>>> 1oJ humeJo 1h Jahge{20).
11 humeJo 2 == 0.
pJ1h1 humeJo
>>> 1oJ 1Ju1a 1h |"bahaha", "abacax1", "aJaha"].
pJ1h1 "Eu gos1o de comeJ " + 1Ju1a + "s!"
O primeiro exemplo exibe todos os nmeros
pares entre zero e dezenove. O segundo exemplo expressa o
entusiasmo por vrias frutas.
8.6 Operaes em listas
O operador + concatena listas:
>>> a = |1, 2, 3]
>>> b = |4, 5, 6]
>>> c = a + b
>>> pJ1h1 c
|1, 2, 3, 4, 5, 6]
Similarmente, o operador * repete uma lista um
nmero dado de vezes:
>>> |0] * 4
|0, 0, 0, 0]
>>> |1, 2, 3] * 3
|1, 2, 3, 1, 2, 3, 1, 2, 3]
O primeiro exemplo repete [0] quatro vezes. O
segundo exemplo repete a lista [1, 2, 3] trs vezes.
8.7 Fatiamento de listas
A operao de fatiamento que vimos na Seo 7.4 tambm
funciona sobre listas:
>>> 1s1a = |`a`, `b`, `c`, `d`, `e`, `1`]
>>> 1s1a|1.3]
|`b`, `c`]
>>> 1s1a|.4]
|`a`, `b`, `c`, `d`]
>>> 1s1a|3.]
|`d`, `e`, `1`]
>>> 1s1a|.]
|`a`, `b`, `c`, `d`, `e`, `1`]
8.8 Listas so mutveis
Diferente das strings, as listas so mutveis, o que significa
que podemos modificar seus elementos. Utilizando o operador
colchete no lado esquerdo de uma atribuio, podemos
atualizar um de seus elementos:
>>> 1Ju1a = |"bahaha", "abacax1", "aJaha"]
>>> 1Ju1a|0] = "abaca1e"
>>> 1Ju1a|-1] = "1ahgeJ1ha"
>>> pJ1h1 1Ju1a
|`abaca1e`, `abacax1`, `1ahgeJ1ha`]
Com o operador de fatiamento podemos
atualizar vrios elementos de uma vez:
Captulo 8: Listas #47
Como pensar como um cientista da Computao usando Python
>>> 1s1a = |`a`, `b`, `c`, `d`, `e`, `1`]
>>> 1s1a|1.3] = |`x`, `y`]
>>> pJ1h1 1s1a
|`a`, `x`, `y`, `d`, `e`, `1`]
Tambm podemos remover elementos de uma
lista atribuindo a lista vazia a eles:
>>> 1s1a = |`a`, `b`, `c`, `d`, `e`, `1`]
>>> 1s1a|1.3] = |]
>>> pJ1h1 1s1a
|`a`, `d`, `e`, `1`]
E podemos adicionar elementos a uma lista
enfiando-os numa fatia vazia na posio desejada:
>>> 1s1a = |`a`, `d`, `1`]
>>> 1s1a|1.1] = |`b`, `c`]
>>> pJ1h1 1s1a
|`a`, `b`, `c`, `d`, `1`]
>>> 1s1a|4.4] = |`e`]
>>> pJ1h1 1s1a
|`a`, `b`, `c`, `d`, `e`, `1`]
8.9 Remoo em lista
Utilizando fatias para remover elementos pode ser
complicado, e desta forma propenso a erro. Python fornece
uma alternativa que mais legvel.
del remove um elemento de uma lista:
>>> a = |`um`, `do1s`, `1Jes`]
>>> de a|1]
>>> a
|`um`, `1Jes`]
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:
>>> 1s1a = |`a`, `b`, `c`, `d`, `e`, `1`]
>>> de 1s1a|1.5]
>>> pJ1h1 1s1a
|`a`, `1`]
Como de costume, fatias selecionam todos os
elementos at, mas no incluindo, o segundo ndice.
8.10 Ojetos e valores
Se executamos estas declaraes de atribuio:
>>> a = "bahaha"
>>> b = "bahaha"
sabemos que a e b se referem a uma string com
as letras banana. Mas no podemos dizer se elas apontam para
a mesma string.
Existem dois possveis estados:
Em um caso, a e b se referem a duas coisas
diferentes que possuem o mesmo valor. No segundo caso, elas
se referem mesma coisa. Estas "coisas" possume nomes -
elas so chamadas objetos. Um objeto algo ao qual uma
varivel pode se referenciar.
Todo objeto possui um 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.
>>> 1d{a)
135044008
>>> 1d{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]
>>> 1d{a)
135045528
>>> 1d{b)
135041704
Ento o diagrama de estado fica assim:
a e b possuem o mesmo valor mas no se
referem ao mesmo objeto.
8.11 Apelidos
Uma vez que variveis se referem a objetos, se atribuimos
uma varivel a uma outra, ambas as variveis se referem ao
mesmo objeto:
>>> a = |1, 2, 3]
>>> b = a
Neste caso, o diagrama de estado se parece com
isto:
Uma vez que a lista possui dois nomes
diferentes, a e b, dizemos que ela est "apelidada" (aliased).
Mudanas feitas em um apelido afetam o outro nome:
>>> b|0] = 5
>>> pJ1h1 a
|5, 2, 3]
Embora este comportamento possa ser til, ele
s vezes inesperado e indesejado. Em geral, mais seguro
evitar os apelidos quando voc est trabalhando com objetos
mutveis. claro, para objetos imutveis, no h problema.
por isto que Python livre para apelidar cadeias de caracteres
quando v uma oportunidade de economizar.
Captulo 8: Listas #48
Como pensar como um cientista da Computao usando Python
8.12 Clonando listas
Se queremos modificar uma lista e tambm manter uma cpia
da original, preciamos ter condies de fazer uma cpia da
prpria lista, no apenas uma referncia. Este processo
algumas vezes chamado clonagem, para evitar a ambigidade
da palavra "cpia".
A maneira mas fcil de clonar uma lista
utilizar o operador de fatia:
>>> a = |1, 2, 3]
>>> b = a|.]
>>> pJ1h1 b
|1, 2, 3]
Pegar qualquer fatia de a cria uma nova lista.
Neste caso acontece da fatia consistir da lista inteira.
Agora estamos livres para fazer alteraes a b
sem nos preocuparmos com``a``:
>>> b|0] = 5
>>> pJ1h1 a
|1, 2, 3]
Como exerccio, desenhe um diagrama de
estado para``a`` e b antes e depois desta mudana.
8.13 Lista como parmetro
Passar uma lista como um argumento passa realmente uma
referncia lista, no uma cpia da lista. Por exemplo, a
funo cabeca pega uma lista como parmetro e devolve a
cabea da lista, ou seja, seu primeiro elemento:
>>> de1 cabeca{1s1a).
Je1uJh 1s1a|0]
Eis como ela utilizada:
>>> humeJos = |1, 2, 3]
>>> cabeca{humeJos)
1
O parmetro lista e a varivel numeros so
apelidos para o mesmo objeto. O diagrama de estado se parece
com isto:
Uma vez que o objeto compartilhado pelos
dois quadros, o desenhamos entre eles.
Se a funo modifica um parmetro da lista, a
funo chamadora v a mudana. Por exemplo,
removeCabeca remove o primeiro elemento da lista:
>>> de1 Jemovecabeca{1s1a).
de 1s1a|0]
Aqui est a maneira como ela utilizada:
>>> humeJos = |1, 2, 3]
>>> JemoveCabeca{humeJos)
>>> pJ1h1 humeJos
|2, 3]
Se uma funo devolve uma lista, ela devolve
uma referncia lista. Por exemplo, cauda devolve uma lista
que contm todos menos o primeiro elemento de uma
determinada lista:
>>> de1 cauda{1s1a).
Je1uJh 1s1a|1.]
Aqui est a maneira como ela utilizada:
>>> humeJos = |1, 2, 3]
>>> Jes1o = cauda{humeJos)
>>> pJ1h1 Jes1o
|2, 3]
Uma vez que o valor de retorno foi criado com
o operador de fatia, ele uma nova lista. A criao de resto, e
qualquer alterao subseqente a resto, no tem efeito sobre
numeros.
8.14 Lista aninhadas
Uma lista aninhada uma lista que aparece como um
elemento de uma outra lista. Nesta lista, o terceiro elemento
uma lista aninhada:
>>> 1s1a = |"ao", 2.0, 5, |10, 20]]
Se exibimos lista[3], obtemos [10, 20]. Para
extrairmos um elemento de uma lista aninhada, podemos agir
em duas etapas:
>>> eem = 1s1a|3]
>>> eem|0]
10
Ou podemos combin-las:
>>> 1s1a|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.
8.15 Matrizes
Listas aninhadas so freqentemente utilizadas para
representar matrizes. Por exemplo, a matriz:
poderia ser representada como:
>>> ma1J1z = ||1, 2, 3], |4, 5, 6], |7, 8, 9]]
matriz uma lista com trs elementos, onde
cada elemento uma linha da matriz. Podemos selecionar uma
linha inteira da matriz da maneira habitual:
>>> ma1J1z|1]
|4, 5, 6]
Ou podemos extrair um nico elemento da
matriz utilinado a forma de duplo ndice:
>>> ma1J1z|1]|1]
5
O primeiro ndice seleciona a linha, e o segundo
ndice seleciona a coluna. Embora esta maneira de representar
matrizes seja comum, ela no a nica possibilidade. Uma
pequena variao utilizar uma lista de colunas ao invs de
uma lista de linhas.
Captulo 8: Listas #49
Como pensar como um cientista da Computao usando Python
Mais adiante veremos uma alternativa mais
radical utilizando um dicionrio.
8.16 Strings e listas
Duas das mais teis funes no mdulo string envolvem listas
de strings. A funo split (separar) quebra uma string em uma
lista de palavras. Por padro, qualquer nmero de caracteres
espao em branco considerado um limite de uma palavra:
>>> 1mpoJ1 s1J1hg
>>> poes1a = "0 oJvaho ho caJvaho..."
>>> s1J1hg.sp11{poes1a)
|`0`, `oJvaho`, `ho`, `caJvaho...`]
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:
>>> s1J1hg.sp11{poes1a, `va`)
|`0 oJ`, `ho ho caJ`, `ho...`]
Perceba que o delimitador no aparece na lista.
A funo join (juntar) o inverso de split. Ela
pega uma lista de strings e concatena os elementos com um
espao entre cada par:
>>> 1s1a = |`0`, `oJvaho`, `ho`, `caJvaho...`]
>>> s1J1hg.o1h{1s1a)
`0 oJvaho ho caJvaho...`
Como split, join recebe um delimitador que
inserido entre os elementos:
>>> s1J1hg.o1h{1s1a, `_`)
`0_oJvaho_ho_caJvaho...`
Como um execcio, descreva o relacionamento
entre string.join(string.split(poesia)) e poesia. Eles so o
mesmo para qualquer string? Quando eles seriam diferentes?
8.17 Glossrio
lista (list) Uma coleo denominada de objetos, onde
cada objeto identificado por um ndice.
ndice (index) Uma varivel inteira ou valor que indica um
elemento de uma lista.
elemento
(element)
Um dos valores em uma lista(ou outra
seqncia). O operador colchete seleciona
elementos de uma lista.
seqncia
(sequence)
Qualquer um dos tipos de dados que
consiste de um conjunto ordenado de
elementos, com cada elemento identificado
por um ndice.
lista aninhada
(nested list)
Uma lista que um elemento de uma outra
lista.
percurso na
lista (list
traversal)
O acesso seqencial de cada elemento em
uma lista.
objeto
(object)
Um coisa a qual uma varivel pode se
referir.
apelidos
(aliases)
Mltiplas variveis que contm referncias
ao mesmo objeto.
clonar (clone) Criar um novo objeto que possui o mesmo
valor de um objeto existente. Copiar a
referncia a um objeto cria um apelido
(alias) mas no clona o objeto.
delimitador
(delimiter)
Um caracter uma string utilizados para
indicar onde uma string deveria ser
dividida(split).
Captulo 8: Listas #50
Como pensar como um cientista da Computao usando Python
Captulo 9: Tuplas Captulo 9: Tuplas
9.1 Mutabilidade e tuplas
At agora, voc tem visto dois tipos compostos: strings, que
so compostos de caracteres; e listas, que so compostas de
elementos de qualquer tipo. Uma das diferenas que notamos
que os elementos de uma lista podem ser modificados, mas
os caracteres em uma string no. Em outras palavras, strings
so imutveis e listas so mutveis.
H um outro tipo em Python chamado tupla
(tuple) que similar a uma lista exceto por ele ser imutvel.
Sintaticamente, uma tupla uma lista de valores separados por
vrgulas:
>>> 1upa = `a`, `b`, `c`, `d`, `e`
Embora no seja necessrio, convencional
colocar tuplas entre parnteses:
>>> 1upa = {`a`, `b`, `c`, `d`, `e`)
Para criar uma tupla com um nico elemento,
temos que incluir uma vrgula final:
>>> 11 = {`a`,)
>>> 1ype{11)
<1ype `1upe`>
Sem a vrgula, Python entende ('a') como uma
string entre parnteses:
>>> 12 = {`a`)
>>> 1ype{12)
<1ype `s1J1hg`>
Questes de sintaxe de lado, as operaes em
tuplas so as mesmas operaes das listas. O operador ndice
seleciona um elemento da tupla.
>>> 1upa = {`a`, `b`, `c`, `d`, `e`)
>>> 1upa|0]
`a`
E o operador slice (fatia) seleciona uma "faixa"
(range) de elementos.
>>> 1upa|1.3]
{`b`, `c`)
Mas se tentarmos modificar um dos elementos
de uma tupla, teremos um erro:
>>> 1upa|0] = `A`
TypeEJJoJ. obec1 doesh`1 suppoJ1 11em ass1ghmeh1
Naturalmente, mesmo que no possamos
modificar os elementos de uma tupla, podemos substitu-la por
uma tupla diferente:
>>> 1upa = {`A`,) + 1upa|1.]
>>> 1upa
{`A`, `b`, `c`, `d`, `e`)
9.2 Atribuies de tupla
De vez em quando, necessrio trocar entre si os valores de
duas variveis. Com operaes de atribuio convencionais,
temos que utilizar uma varivel temporria. Por exemplo, para
fazer a troca entre a e b:
>>> 1emp = a
>>> a = b
>>> b = 1emp
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
vaueEJJoJ. uhpack 1upe o1 wJohg s1ze
9.3 Tuplas como valores de retorno
Funes podem retornar tuplas como valor de retorno. Por
Exemplo, ns poderamos escrever uma funo que troca dois
parmetros entre si:
de1 1Joca{x, y).
Je1uJh y, x
Ento ns poderamos atribuir o valor de retorno
para uma tupla com duas variveis:
a, b = 1Joca{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:
de1 1Joca{x, y). # veJsao 1hcoJJe1a
x, y = y, x
Se ns chamarmos esta funo desta forma:
1Joca{a, b)
ento a e x so apelidos para um mesmo valor.
Mudar x dentro da funo troca, faz com que x se referencie a
um valor diferente, mas sem efeito sobre a dentro de
__main__. Do mesmo modo, a mudana em y no tem efeito
sobre b.
Esta funo roda sem produzir uma mensagem
de erro, mas ela no faz o que pretendemos. Este um
exemplo de um erro semntico.
Como exerccio, desenhe um diagrama de
estado pra esta funo de modo que voc possa ver porque
ela no funciona.
9.4 Nmeros aleatrios
A maioria dos programas de computador fazem a mesma coisa
sempre que so executados, ento, podemos dizer que eles so
determinsticos. Determinismo em geral uma coisa boa, se
Captulo 9: Tuplas #51
Como pensar como um cientista da Computao usando Python
ns esperamos que um clculo d sempre o mesmo resultado.
Entretanto, para algumas aplicaes queremos que o
computador se torne imprevisvel. Jogos so um exemplo
bvio, mas existem outros.
Fazer um programa realmente no-
determinstico se mostra no ser to fcil, mas existem
maneiras de faz-lo ao menos parecer no-determinstico.
Uma dessas maneiras gerar nmeros aleatrios e us-los
para determinar o resultado de um programa. Python tem uma
funo nativa que gera nmeros pseudo aleatrios, os quais
no so verdadeiramente aleatrios no sentido matemtico,
mas para os nossos propsitos eles so.
O mdulo random contm uma funo chamada
random que retorna um nmero em ponto flutuante (floating-
point number) entre 0.0 e 1.0. Cada vez que voc chama
random, voc recebe o prximo nmero de uma longa srie.
Para ver uma amostra, execute este loop:
1mpoJ1 Jahdom
1oJ 1 1h Jahge{10).
x = Jahdom.Jahdom{)
pJ1h1 x
Para gerar um nmero aleatrio ente 0.0 e um
limite superior, digamos superior, multiplique x por superior.
Como exerccio, gere um nmero aleatrio entre
'inferior' e 'superior'.
Como exerccio adicional, gere um nmero
inteiro aleatrio entre 'inferior' e 'superior', inclusive os dois
extremos.
9.5 Lista de nmeros aleatrios
O primeiro passo gerar uma lista aleatria de valores.
listaAleatoria pega um parmetro inteiro e retorna uma lista de
nmeros aleatrios com o comprimento dado. Inicia-se com
uma lista de n zeros. A cada iterao do loop, ele substitui um
dos elementos por um nmero aleatrio. O valor retornado
uma referncia para a lista completa:
de1 1s1aAea1oJ1a{h).
s = |0] * h
1oJ 1 1h Jahge{h).
s|1] = Jahdom.Jahdom{)
Je1uJh s
Vamos realizar um teste desta funo com uma
lista de oito elementos. Para efeitos de depurao, uma boa
idia comear com uma lista pequena.
>>> 1s1aAea1oJ1a{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.
9.6 Contando
Uma boa maneira de abordar problemas como esse dividir o
problema em subproblemas, e encontrar um subproblema que
se enquadre em um padro de soluo computacional que
voc j tenha visto antes.
Neste caso, queremos percorrer uma lista de
nmeros e contar o nmero de vezes que valor se encaixa em
um determinado intervalo. Isso soa familiar. Na Seo 7.8,
ns escrevemos um programa que percorria uma string e
contava o nmero de vezes que uma determinada letra
aparecia.
Assim, podemos prosseguir copiando o
programa original e adaptando-o para o problema atual. O
programa original era:
coh1adoJ = 0
1oJ e1Ja 1h 1Ju1a.
11 e1Ja == `a`.
coh1adoJ = coh1adoJ + 1
pJ1h1 coh1adoJ
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.:
coh1adoJ = 0
1oJ humeJo 1h 1s1a
11 1h1eJ1oJ < humeJo < supeJ1oJ.
coh1adoJ = coh1adoJ + 1
pJ1h1 coh1adoJ
O ltimo passo encapsular este cdigo em
uma funo chamada noIntervalo. Os parmetros so a lista e
os valores inferior e superior:
de1 hoTh1eJvao{1s1a, 1h1eJ1oJ, supeJ1oJ).
coh1adoJ = 0
1oJ humeJo 1h 1s1a.
11 1h1eJ1oJ < humeJo < supeJ1oJ.
coh1adoJ = coh1adoJ + 1
Je1uJh coh1adoJ
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.
9.7 Vrios intervalos
Conforme o nmero de intervalos aumenta, noIntervalo torna-
se intragvel. Com dois intervalos, no to ruim:
1h1eJ1oJ = hoTh1eJvao{a, 0.0, 0.5)
supeJ1oJ = hoTh1eJvao{a, 0.5, 1)
Mas com quatro intervalos, comea a ficar
desconfortvel.:
1h1eJvao1 = hoTh1eJvao{a, 0.0, 0.25)
1h1eJvao2 = hoTh1eJvao{a, 0.25, 0.5)
1h1eJvao3 = hoTh1eJvao{a, 0.5, 0.75)
Captulo 9: Tuplas #52
Como pensar como um cientista da Computao usando Python
1h1eJvao4 = hoTh1eJvao{a, 0.75, 1.0)
Existem aqui dois problemas. Um que temos
que criar novos nomes de varivel para cada resultado. O
outro que temos que calcular os limites de cada intervalo.
Vamos resolver o segundo problema primeiro.
Se o nmero de intervalos numeroDeIntervalos, ento a
largura de cada intervalo 1.0 / numeroDeIntervalos.
Vamos usar um lao (loop) para calcular a faixa,
ou largura, de cada intervalo. A varivel do loop, i, conta de 0
at numeroDeIntervalos-1:
aJguJa0oTh1eJvao = 1.0 / humeJo0eTh1eJvaos
1oJ 1 1h Jahge{humeJo0eTh1eJvaos).
1h1eJ1oJ = 1 * aJguJa0oTh1eJvao
supeJ1oJ = 1h1eJ1oJ + aJguJa0oTh1eJvao
pJ1h1 "do" 1h1eJ1oJ, "ao", supeJ1oJ
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 1o 0.125
0.125 1o 0.25
0.25 1o 0.375
0.375 1o 0.5
0.5 1o 0.625
0.625 1o 0.75
0.75 1o 0.875
0.875 1o 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:
humeJo0eTh1eJvaos = 8
1h1eJvaos = |0] * humeJo0eTh1eJvaos
aJguJa0oTh1eJvao = 1.0 / humeJo0eTh1eJvaos
1oJ 1 1h Jahge{humeJo0eTh1eJvaos).
1h1eJ1oJ = 1 * aJguJa0oTh1eJvao
supeJ1oJ = 1h1eJ1oJ + aJguJa0oTh1eJvao
1h1eJvaos|1] = hoTh1eJvao{1s1a, 1h1eJ1oJ,
supeJ1oJ)
pJ1h1 1h1eJvaos
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.
9.8 Uma soluo em um s passo
Embora este programa funcione, ele no to eficiente quanto
poderia ser. Toda vez que ele chama noIntervalo, ele percorre
a lista inteira. Conforme o nmero de intervalos aumenta, a
lista ser percorrida um bocado de vezes.
Seria melhor fazer uma nica passagem pela
lista e calcular para cada valor o ndice do intervalo ao qual o
valor pertena. Ento podemos incrementar o contador
apropriado.
Na seo anterior, pegamos um ndice, i, e o
multiplicamos pela larguraDoIntervalo para encontrar o limite
inferior daquele intervalo. Agora queremos pegar um valor
entre 0.0 e 1.0 e encontrar o ndice do intervalo ao qual ele se
encaixa.
J que este problema o inverso do problema
anterior, podemos imaginar que deveramos dividir por
larguraDoIntervalo em vez de multiplicar. Esta suposio est
correta.
J que larguraDoIntervalo = 1.0 /
numeroDeIntervalos, dividir por larguraDoIntervalo o
mesmo que multiplicar por numeroDeIntervalos. Se
multiplicarmos um nmero na faixa entre 0.0 e 1.0 por
numeroDeIntervalos, obtemos um nmero na faixa entre 0.0 e
numeroDeIntervalos. Se arredondarmos este nmero para
baixo, ou seja, para o menor inteiro mais prximo, obtemos
exatamente o que estamos procurando - o ndice do intervalo:
humeJo0eTh1eJvaos = 8
1h1eJvaos = |0] * humeJo0eTh1eJvaos
1oJ 1 1h 1s1a.
1hd1ce = 1h1{1 * humeJo0eTh1eJvaos)
1h1eJvaos|1hd1ce] = 1h1eJvaos|1hd1ce] + 1
Usamos a funo int para converter um nmero
em ponto flutuante (float) para um inteiro.
Existe a possibilidade deste clculo produzir um
ndice que esteja fora dos limites (seja negativo ou maior que
len(intervalos)-1)?
Uma lista como intervalos que contm uma
contagem do nmero de valores em cada intervalo chamada
de histograma.
Como exerccio, escreva uma funo chamada
``histograma`` que receba uma lista e um nmero de
intervalos como argumentos e retorne um histograma com o
nmero de intervalos solicitado.
9.9 Glossrio
tipo imutvel
(immutable
type)
Um tipo de elemento que no pode ser
modificado. Atribuies a um elemento ou
"fatiamento (slices)" XXX aos tipos
imutveis causaro erro.
tipo mutvel
(mutable type)
Tipo de dados onde os elementos podem
ser modificados. Todos os tipos mutveis,
so tipos compostos. Listas e dicionrios
so exemplos de tipos de dados mutveis.
String e tuplas no so.
tupla (tuple) Tipo sequencial similar as listas com
exceo de que ele imutvel. Podem ser
usadas Tuplas sempre que um tipo imutvel
for necessrio, por exemplo uma "chave
(key)" em um dicionrio
Atribuio a
tupla (tuple
Atribuio a todos os elementos de uma
tupla feita num nico comando de
Captulo 9: Tuplas #53
Como pensar como um cientista da Computao usando Python
assignment) atribuo. A atribuio aos elementos
ocorre em paralelo, e no em sequncia,
tornando esta operao til para swap, ou
troca recproca de valores entre variveis
(ex: a,b=b,a).
determinstico
(deterministic)
Um programa que realiza a mesma coisa
sempre que executado.
pseudo
aleatrio
(pseudorando
m)
Uma sequncia de nmeros que parecem
ser aleatrios mas so na verdade o
resultado de uma computao
"determinstica"
histograma
(histogram)
Uma lista de inteiros na qual cada elemento
conta o nmero de vezes que algo acontece.
Captulo 9: Tuplas #54
Como pensar como um cientista da Computao usando Python
Captulo 10: Dicionrios Captulo 10: Dicionrios
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 {:
>>> 1hg2esp = {}
>>> 1hg2esp|`ohe`] = `uho`
>>> 1hg2esp|`1wo`] = `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:
>>> pJ1h1 1hg2esp
{`ohe`. `uho`, `1wo`. `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.
>>> 1hg2esp = {`ohe`. `uho`, `1wo`. `dos`, \
`1hJee`. `1Jes`}
Se nos imprimirmos o valor de ing2esp
novamente, nos teremos uma surpresa:
>>> pJ1h1 1hg2esp
{`ohe`. `uho`, `1hJee`. `1Jes`, `1wo`. `dos`}
Os pares chave-valor no esto em ordem!
Felizmente, no a motivos para se preocupar com a ordem,
desde que os elementos do dicionrio nunca sejam indexados
com indices inteiros. Podemos usar as chaves para buscar os
valores correspondentes:
>>> pJ1h1 1hg2esp|`1wo`]
`dos`
A chave 'two' retornou o valor 'dos' mesmo
pensando que retornaria o terceiro par chave-valor.
10.1 Operaes dos Dicionrios
O comando del remove um par chave-valor de um dicionrio.
Por exemplo, o dicionrio abaixo contem os nomes de varias
frutas e o numero de cada fruta em no estoque:
>>> 1hveh1aJ1o = {`abacax1s`. 430, `bahahas`. 312, \
`aJahas`. 525, `peJas`. 217}
>>> pJ1h1 1hveh1aJ1o
{`aJahas`. 525, `abacax1s`. 430, `peJas`. 217, \
`bahahas`. 312}
Se alguem comprar todas as peras, podemos
remover a entrada do dicionrio:
>>> de 1hveh1aJ1o|`peJas`]
>>> pJ1h1 1hveh1aJ1o
{`aJahas`. 525, `abacax1s`. 430, `bahahas`. 312}
Ou se ns esperamos por mais peras em breve,
nos podemos simplesmente trocar o valor associoado as peras:
>>> 1hveh1aJ1o|`peJas`] = 0
>>> pJ1h1 1hveh1aJ1o
{`aJahas`. 525, `abacax1s`. 430, `peJas`. 0, \
`bahahas`. 312}
A funo len tambm funciona com dicionrios;
retornando o nmero de pares chave-valor:
>>> eh{1hveh1aJ1o)
4
10.2 Mtodos dos Dicionrios
Um mtodo parecido com uma funo - possui parametros e
retorna valores - mas a sintaxe diferente. Por exemplo, o
metodo keys recebe um dicionrio e retorna uma lista com as
chaves, mas em vez de usarmos a sintaxe de funo
keys(ing2esp), nos usamos a sintaxe de mtodo
ing2esp.keys():
>>> 1hg2esp.keys{)
|`ohe`, `1hJee`, `1wo`]
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.
O mtodo values parecido; retorna a lista de
valores de um dicionrio:
>>> 1hg2esp.vaues{)
|`uho`, `1Jes`, `dos`]
O mtodo items retorna os dois, na forma de
uma lista de tuplas - cada tupla com um par chave-valor:
>>> 1hg2esp.11ems{)
|{`ohe`,`uho`), {`1hJee`,`1Jes`), {`1wo`,`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:
>>> 1hg2esp.has_key{`ohe`)
TJue
>>> 1hg2esp.has_key{`deux`)
Fase
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{`ohe`)
Captulo 10: Dicionrios #55
Como pensar como um cientista da Computao usando Python
hameEJJoJ. has_key
10.3 Aliasing (XXX) e Copiar
Uma vez que os dicionrios so mutveis, voce precisa saber
sobre Aliasing. Sempre que duas variveis referenciarem o
mesmo objeto, quando uma alterada, afeta a outra.
Se voc quer modificar um dicionrio e
continuar com uma copia original, utilize o mtodo copy. Por
exemplo, opposites um dicionrio que contm pares de
antnimos:
>>> oppos11es = {`up`. `dowh`, `J1gh1`. `wJohg`, \
`1Jue`. `1ase`}
>>> a1as = oppos111es
>>> copy = oppos111es.copy{)
alias e opposites se referem ao mesmo objeto;
copy se refere a um novo objeto igual ao dicionrio opposites.
Se voc modificar o alias, opposites tambm ser alterado.
>>> a1as|`J1gh1`] = `e11`
>>> oposs11es|`J1gh1`]
`e11`
Se modificarmos copy, opposites no ser
modificado:
>>> copy|`J1gh1`] = `pJ1v1ege`
>>> oppos11es|`J1gh1`]
`e11`
10.4 Matrizes Esparsas
Na seo 8.14, ns usamos uma lista de listas para representar
uma matriz. Essa uma boa escolha se a matriz for
principalmente de valores diferentes de zero, mas
considerando uma matriz esparsa como essa:
Uma representao usando uma lista contem
muitos zeros:
>>> ma1J1z = | |0,0,0,1,0],
|0,0,0,0,0],
|0,2,0,0,0],
|0,0,0,0,0],
|0,0,0,3,0] ]
Uma alternativa usarmos um dicionrio. Para
as chaves, ns podemos usar tuplas que contm os nmeros da
linha e a coluna. Abaixo uma representao em um dicinario
da mesma matriz:
>>> ma1J1z = {{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 []:
>>> ma1J1z|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:
>>> ma1J1z|1,3]
KeyEJJoJ. {1,3)
O mtodo get resolve esse problema:
>>> ma1J1z.ge1{{0,3), 0)
1
O primeiro parmetro a chave; o segundo o
valor que get retornar caso no existe a chave no dicionrio:
>>> ma1J1z.ge1{{1,3), 0)
0
get definitivamente melhora a semntica e a
sintaxe do acesso a matrizes esparsas.
10.5 Hint
Se voc brincou com a funo fibonacci da seo 5.7,
provvel que voc notou que quanto maior o nmero passado
para a funo, mais tempo a funo demora para executar.
Alm disso, o tempo da execuo aumenta rapidamente. 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.
Captulo 10: Dicionrios #56
Como pensar como um cientista da Computao usando Python
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:
>>> pJev1ous = {0.1, 1.1}
>>> de1 11bohacc1{h).
11 pJev1ous.has_key{h).
Je1uJh pJev1ous|h]
ese.
hewvaue = 11bohacc1{h-1) + \
11bohacc1{h-2)
pJev1ous|h] = hewvaue
Je1uJh hewvaue
O dicionrio chamado previous guarda os
nmeros de Fibonacci que ns ja conhecemos. Ele comea
com apenas dois pares: 0 possui 1; e 1 possui 1.
Sempre que 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:
>>> 11bohacc1{50)
0veJ1owEJJoJ. 1h1egeJ add111oh
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.
10.6 Inteiros Longos
Python possui um tipo chamado long int que permite
trabalharmos com qualquer tamanho de inteiros. Existem duas
maneiras de criarmos um valor long int. A primeira escrever
um inteiro seguido de um L no final:
>>> 1ype{1L)
<1ype `ohg 1h1`>
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:
>>> ohg{1)
1L
>>> ohg{3.9)
3L
>>> ohg{`57`)
57L
Todas as operaes matemticas funcionam
com long int s, ento no precisamos modificar muito para
adaptar fibonacci:
>>> pJev1ous = {0. 1L, 1.1L}
>>> 11bohacc1{50)
20365011074L
Somente trocando os valores iniciais de
previous, conseguimos mudar o comportamento da fibonacci.
1 N.T. A partir do Python 2. XXX este erro no ocorre mais,
pois em caso de sobrecarga o valor inteiro
automaticamente promovido para o tipo long.
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.
10.7 Contando Letras
No captulo 7, escrevemos uma funo que contava o nmero
de ocorrncias de uma letra em uma string. A verso mais
comum desse problema fazer um histograma das letras da
string, ou seja, quantas vezes cada letra aparece na string.
Um histograma pode ser util para comprimir um
arquivo de texto. Pois diferentes letras aparecem com
diferentes frequncias, podemos comprimir um arquivo
usando pequenos cdigos para letras comuns e longos cdigos
para letras que aparecem em menor frequncia.
Dicionrios fornecem uma maneira elegante de
gerar um histograma:
>>> e11eJCouh1s = {}
>>> 1oJ e11eJ 1h "h1ss1ss1pp1".
... e11eJCouh1s|e11eJ] =
e11eJCouh1s.ge1{e11eJ,0) + 1
...
>>> e11eJCouh1s
{`h`. 1, `s`. 4, `p`. 2, `1`. 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:
>>> e11eJT1ems = e11eJCouh1s.11ems{)
>>> e11eJT1ems.soJ1{)
>>> pJ1h1 e11eJT1ems
|{`h`, 1), {`1`, 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.
10.8 Glossrio
dicionrio
(dictionary)
Uma coleo de pares de chaves-valores
que so mapeados pelas chaves, para se
obter os valores. As chaves podem ser
qualquer tipo de dados imutavel, e os
valores podem ser de qualquer tipo.
chave (key) Um valor que usado para buscar uma
entrada em um dicionrio.
par chave-valor
(key-value pair)
Um dos itens de um dicionrio.
mtodo
(method)
Um tipo de funo que chamada com
uma sintaxe diferente e invocada no
contexto de um objeto.
invocar (invoke) Chamar um mtodo.
hint O armazenamento temporrio de um valor
pr-computado para evitar a computao
redundante.
overflow Um resultado numrico que muito
Captulo 10: Dicionrios #57
Como pensar como um cientista da Computao usando Python
grande para ser representado no formato
numrico.
Captulo 10: Dicionrios #58
Como pensar como um cientista da Computao usando Python
Captulo 11: Arquivos e excees Captulo 11: Arquivos e excees
Arquivos e excees
Durante a execuo de um programa, seus dados ficam na
memria. Quando o programa termina, ou o computador
desligado, os dados na memria desaparecem. Para armazenar
os dados permanentemente, voc tem que coloc-los em um
arquivo. Arquivos usualmente so guardados em um disco
rgido (HD), num disquete ou em um CD-ROM.
Quando existe um nmero muito grande de
arquivos, eles muitas vezes so organizados dentro de
diretrios (tambm chamados de ?pastas? ou ainda ?
*folders*?). Cada arquivo identificado por um nome nico,
ou uma combinao de um nome de arquivo com um nome de
diretrio.
Lendo e escrevendo em arquivos, os programas
podem trocar informaes uns com os outros e gerar formatos
imprimveis como PDF.
Trabalhar com arquivos muito parecido com
trabalhar com livros. Para utilizar um livro, voc tem que abr-
lo. Quando voc termina, voc tem que fech-lo. Enquanto o
livro estiver aberto, voc pode tanto l-lo quanto escrever
nele. Em qualquer caso, voc sabe onde voc est situado no
livro. Na maioria das vezes, voc l o livro inteiro em sua
ordem natural, mas voc tambm pode saltar atravs de alguns
trechos (skip around).
Tudo isso se aplica do mesmo modo a arquivos.
Para abrir um arquivo, voc especifica o nome dele e indica o
que voc quer, seja ler ou escrever (gravar).
Abrir um arquivo cria um objeto arquivo. Neste
exemplo, a varivel f se referencia ao novo objeto arquivo.
>>> 1 = opeh{"1es1e.da1", "w")
>>> pJ1h1 1
<opeh 11e "1es1e.da1", mode "w" a1 1e820>
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:
>>> 1.wJ11e{"AgoJa hoJa")
>>> 1.wJ11e{"de 1echaJ o aJqu1vo")
Fechar o arquivo diz ao sistema que terminamos
de escrever (gravar) e que o arquivo est livre para ser lido:
>>> 1.cose{)
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?):
>>> 1 = opeh{"1es1e.da1", "J")
Se tentarmos abrir um arquivo que no existe,
temos um erro:
>>> 1 = opeh{"1es1e.ca1", "J")
T0EJJoJ. |EJJho 2] ho such 11e oJ d1Jec1oJy. \
`1es1e.ca1`
Sem nenhuma surpresa, o mtodo read l dados
do arquivo. Sem argumentos, ele l todo o contedo do
arquivo:
>>> 1ex1o = 1.Jead{)
>>> pJ1h1 1ex1o
AgoJa hoJade 1echaJ o aJqu1vo
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:
>>> 1 = opeh{"1es1e.da1", "J")
>>> pJ1h1 1.Jead{9)
AgoJa h
Se no houver caracteres suficientes no arquivo,
read retorna os caracteres restantes. Quando chegamos ao final
do arquivo, read retorna a string vazia:
>>> pJ1h1 1.Jead{1000006)
oJade 1echaJ o aJqu1vo
>>> pJ1h1 1.Jead{)
>>>
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:
de1 cop1aAJqu1vo{vehoAJqu1vo, hovoAJqu1vo).
11 = opeh{vehoAJqu1vo, "J")
12 = opeh{hovoAJqu1vo, "w")
wh1e 1.
1ex1o = 11.Jead{50)
11 1ex1o == "".
bJeak
12.wJ11e{1ex1o)
11.cose{)
12.cose{)
Je1uJh
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.
11.1 Arquivos texto
Um arquivo texto um arquivo que contm caracteres
imprimveis e espaos, organizados dentro de linhas separadas
por caracteres de nova linha. J que Pyhton especialmente
projetado para processar arquivos texto, ele oferece mtodos
que tornam esta tarefa mais fcil.
Captulo 11: Arquivos e excees #59
Como pensar como um cientista da Computao usando Python
Para demonstrar, vamos criar um arquivo texto
com trs linhas de texto separadas por caracteres de nova
linha:
>>> 1 = opeh{"1es1e.da1", "w")
>>> 1.wJ11e{"1hha um\h1hha do1s\h1hha 1Js\h")
>>> 1.cose{)
O mtodo readline l todos os caracteres at, e
incluindo, o prximo caractere de nova linha:
>>> 1 = opeh{"1es1e.da1", "J")
>>> pJ1h1 1.Jead1he{)
1hha um
>>>
readlines retorna todas as linhas restantes como
uma lista de strings:
>>> pJ1h1 1.Jead1hes{)
|`1hha do1s\012`, `1hha 1Js\012`]
Neste caso, a sada est em formado de lista, o
que significa que as strings aparecem entre aspas e o caractere
de nova linha aparece como a seqncia de escape 012.
No fim do arquivo, readline retorna a string
vazia e readlines retorna a lista vazia:
>>> pJ1h1 1.Jead1he{)
>>> pJ1h1 1.Jead1hes{)
|]
A seguir temos um exemplo de um programa de
processamento de linhas. filtraArquivo faz uma cpia de
velhoArquivo, omitindo quaisquer linhas que comecem por #:
de1 111JaAJqu1vo{vehoAJqu1vo, hovoAJqu1vo).
11 = opeh{vehoAJqu1vo, "J")
12 = opeh{hovoAJqu1vo, "w")
wh1e 1.
1ex1o = 11.Jead1he{)
11 1ex1o == "".
bJeak
11 1ex1o|0] == `#`.
coh11hue
12.wJ11e{1ex1o)
11.cose{)
12.cose{)
Je1uJh
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.
11.2 Gravando variveis
O argumento de write tem que ser uma string, assim se
quisermos colocar outros valores em um arquivo, temos de
convert-los para strings primeiro. A maneira mais fcil de
fazer isso com a funo str:
>>> x = 52
>>> 1.wJ11e{s1J{x))
Uma alternativa usar o operador de
formatao %. Quando aplicado a inteiros, % o operador
mdulo. Mas quando o primeiro operador uma string, % o
operador de formatao.
O primeiro operando a string de formatao,
e o segundo operando uma tupla de expresses. O resultado
uma string que contm os valores das expresses,
formatadas de acordo com a string de formatao.
Num exemplo simples, a seqncia de
formatao "??%d??" significa que a primeira expresso na
tupla deve ser formatada como um inteiro. Aqui a letra d
representa ?decimal?.
>>> caJJos = 52
>>> "d" caJJos
`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:
>>> caJJos = 52
>>> "Em uho vehdemos d caJJos." caJJos
`Em uho vehdemos 52 caJJos.`
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 d1as 11zemos 1 m1hes s." \
{34,6.1,`Jea1s`)
`Em 34 d1as 11zemos 6.100000 m1hes de Jea1s.`
Por padro, o formato de ponto flutuante exibe
seis casas decimais.
O nmero de expresses na tupla tem que ser
igual ao nmero de seqncias de formatao na string. Alm
disso, os tipos das expresses tm que iguais aos da seqncia
de formatao:
>>> "d d d" {1,2)
TypeEJJoJ. ho1 ehough aJgumeh1s 1oJ 1oJma1 s1J1hg
>>> "d" `Jea1s`
TypeEJJoJ. 1ega aJgumeh1 1ype 1oJ bu11-1h \
opeJa11oh
No primeiro exemplo, no existem expresses
suficientes; no segundo, a expresso do tipo errado.
Para um controle maior na formatao de
nmeros, podemos especificar o nmero de dgitos como parte
da seqncia de formatao:
>>> "6d" 62
` 62`
>>> "121" 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.21" 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.
Captulo 11: Arquivos e excees #60
Como pensar como um cientista da Computao usando Python
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:
de1 Jea1oJ1o{saaJ1os).
es1udah1es = saaJ1os.keys{)
es1udah1es.soJ1{)
1oJ es1udah1e 1h es1udah1es.
pJ1h1 "-20s 12.021" {es1udah1e, \
saaJ1os|es1udah1e])
Para testar esta funo, criaremos um pequeno
dicionrio e imprimiremos o contedo:
>>> saaJ1os = {`maJ1a`. 6.23, `oo`. 5.45, \
`osu`. 4.25}
>>> Jea1oJ1o{saaJ1os)
oo 5.45
osu 4.25
maJ1a 6.23
Controlando a largura de cada valor, podemos
garantir que as colunas ficaro alinhadas, desde que os nomes
contenham menos que vinte e um caracteres e os salrios
sejam menores do que um bilho de reais por hora.
11.3 Diretrios
Quando voc cria um novo arquivo abrindo-o e escrevendo
nele, o novo arquivo fica no diretrio corrente (seja l onde
for que voc esteja quando rodar o programa). Do mesmo
modo, quando voc abre um arquivo para leitura, Python
procura por ele no diretrio corrente.
Se voc quiser abrir um arquivo que esteja em
algum outro lugar, voc tem que especificar o caminho (path)
para o arquivo, o qual o nome do diretrio (ou folder) onde
o arquivo est localizado:
>>> 1 = opeh{"/usJ/shaJe/d1c1/woJds", "J")
>>> pJ1h1 1.Jead1he{)
AaJhus
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.
11.4 Pickling
Para colocar valores em um arquivo, voc tem que convert-
los para strings. Voc j viu como fazer isto com str:
>>> 1.wJ11e {s1J{12.3))
>>> 1.wJ11e {s1J{|1,2,3]))
O problema que quando voc l de volta o
valor, voc tem uma string. O Tipo original da informao foi
perdido. De fato, voc no pode sequer dizer onde comea um
valor e termina outro:
>>> 1.Jead1he{)
?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:
>>> 1mpoJ1 p1cke
>>> 1 = opeh{?1es1.pck?, ?w?)
Para armazenar uma estrutura de dados, use o
mtodo dump e ento feche o arquivo do modo usual:
>>> p1cke.dump{12.3, 1)
>>> p1cke.dump{|1,2,3], 1)
>>> 1.cose{)
Ento, podemos abrir o arquivo para leitura e
carregar as estruturas de dados que foram descarregadas
(dumped):
>>> 1 = opeh{?1es1.pck?, ?J?)
>>> x = p1cke.oad{1)
>>> x
12,3
>>> 1ype{x)
<1ype ?1oa1?>
>>> y = p1cke.oad{1)
>>> y
|1, 2, 3]
>>> 1ype{y)
<1ype ?1s1?>
Cada vez que invocamos load, obtemos um
nico valor do arquivo, completo com seu tipo original.
11.5 Excees
Whenever que um erro em tempo de execuo acontece, ele
gera uma exceo. Usualmente, o programa pra e Python
exibe uma mensagem de erro.
Por exemplo, dividir por zero gera uma
exceo:
>>> pJ1h1 55/0
ZeJo01v1s1ohEJJoJ. 1h1egeJ d1v1s1oh oJ moduo
Do mesmo modo, acessar um item de lista
inexistente:
>>> a = |]
>>> pJ1h1 a|5]
ThdexEJJoJ. 1s1 1hdex ou1 o1 Jahge
Ou acessar uma chave que no est em um
dicionrio:
>>> b = {}
>>> pJ1h1 b|?wha1?]
KeyEJJoJ. wha1
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:
homedoaJqu1vo = Jaw_1hpu1{?Eh1Je com o home do \
aJqu1vo. ?)
1Jy.
Captulo 11: Arquivos e excees #61
Como pensar como um cientista da Computao usando Python
1 = opeh {homedoaJqu1vo, ?J?)
excep1.
pJ1h1 ?ho ex1s1e aJqu1vo chamado?, homedoaJqu1vo
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:
de1 ex1s1e{homedoaJqu1vo)
1Jy.
1 = opeh{homedoaJqu1vo)
1.cose{)
Je1uJh 1
excep1.
Je1uJh 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.
de1 eh1JahumeJo{).
x = 1hpu1 {?Escoha um hmeJo. ?)
11 x == 17.
Ja1se ?EJJohumeJoRu1m?, ?17 um hmeJo Ju1m?
Je1uJh 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:
>>> eh1JahumeJo{)
Escoha um hmeJo. 17
EJJohumeJoRu1m. 17 um hmeJo Ju1m
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.
11.6 Glossrio
arquivo (file) Uma entidade nomeada, usualmente
armazenada em um disco rgido (HD),
disquete ou CD-ROM, que contm uma
seqncia de caracteres.
diretrio
(directory)
Uma coleo nomeada de arquivos,
tambm chamado de pasta ou folder.
caminho (path) Uma seqncia de nomes de diretrios que
especifica a exata localizao de um
arquivo.
arquivo texto
(text file)
Um arquivo que contm caracteres
organizados em linhas separadas por
caracteres de nova linha.
comando
break (break
statement)
Um comando que fora a atual iterao de
um loop a terminar. O fluxo de execuo
vai para o topo do loop, testa a condio e
prossegue conforme o caso.
Captulo 11: Arquivos e excees #62
Como pensar como um cientista da Computao usando Python
Captulo 12: Classes e objetos Captulo 12: Classes e objetos
12.1 Tipos compostos definidos pelo usurio
Depois de usarmos alguns tipos nativos do Python, estamos
prontos para criar um tipo de dados: o Ponto.
Considere o conceito matemtico de um ponto.
Em duas dimenses, um ponto um par de nmeros
(coordenadas) que so tratadas coletivamente como um objeto
simples. Na notao matemtica, pontos so freqentemente
escritos entre parnteses com vrgula separando as
coordenadas. Por exemplo, (0, 0) representa a origem, e (x, y)
representa o ponto x unidades direita, e y unidades acima da
origem.
Uma maneira natural para representar um ponto
em Python, com dois valores numricos em ponto flutuante.
A questo, ento, como agrupar estes dois valores em um
objeto composto. A maneira rpida e rasteira usar uma lista
ou uma tupla, e para algumas aplicaes, esso pode ser a
melhor escolha
1
.
Uma alternativa definir um novo tipo
composto, tambm chamado uma classe. Esta abordagem
envolve um pouco mais de esforo, mas ela tem vantagens
que logo ficaro evidentes.
Eis a definio de uma classe:
cass Poh1o.
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:
11ha = Poh1o{)
A varivel final agora contm uma referncia a
um novo objeto da classe Ponto. Uma funo como Ponto, que
cria novos objetos, chamada construtor.
12.2 Atributos
Podemos adicionar novos dados em uma instncia usando a
notao de ponto (dot notation):
>>> 11ha.x = 3.0
1 N.T.: A linguagem Python tambm incorpora um tipo nativo
complex que representa nmeros complexos. Uma
instncia de complex, como a=3+5j possui dois valores de
ponto flutuante em seus atributos a.real e a.imag, e pode
ser utilizada para armazenar pontos em um espao bi-
dimensional.
>>> 11ha.y = 4.0
Esta sintaxe similar sintaxe para acessar uma
varivel de um mdulo, como math.pi ou string.uppercase.
Neste caso, porm, estamos acessando um item de dado de
uma instncia. Estes itens so chamados atributos.
O seguinte diagrama de estado mostra o
resultado destas atribuies:
A varivel final refere a um objeto Ponto, que
contm dois atributos. Cada atributo faz referncia a um
nmero em ponto flutuante.
Podemos ler o valor de um atributo usando a
mesma sintaxe:
>>> pJ1h1 11ha.y
4.0
>>> x = 11ha.x
>>> pJ1h1 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:
pJ1h1 `{` + s1J{11ha.x) + `, ` + s1J{11ha.y) + `)`
d1s1Ao0uadJado = 11ha.x * 11ha.x + 11ha.y * \
11ha.y
A primeira linha imprime (3.0, 4.0); a segunda
linha calcula o valor 25.0.
tentador imprimir o valor do prprio objeto
final:
>>> pJ1h1 11ha
<__ma1h__.Poh1o 1hs1ahce a1 8018e70>
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.
Captulo 12: Classes e objetos #63
Como pensar como um cientista da Computao usando Python
12.3 Instncias como parmetros
Voc pode passar uma instncia como um parmetro da forma
usual. Por exemplo:
de1 mos1JaJPoh1o{p).
pJ1h1 `{` + s1J{p.x) + `, ` + s1J{p.y) + `)`
A funo mostrarPonto pega o ponto (p) como
um argumento e mostra-o no formato padro. Se voc chamar
mostrarPonto(final), a sada ser (3.0, 4.0).
Como um exerccio, re-escreva a funo
distncia da Seo 5.2 para receber dois pontos como
parmetros, ao invs de quatro nmeros.
12.4 O significado de "mesmo"
O significado da palavra "mesmo" parece perfeitamente claro
at que voc pense a respeito, e ento voc percebe que h
mais nesta palavra do que voc esperava.
Por exemplo, se voc diz "Cris e eu temos o
mesmo carro", voc est dizendo que o carro de Cris e o seu
so do mesmo fabricante e modelo, mas so dois carros
diferentes. Se voc disser "Cris e eu temos a mesma me",
voc est dizendo que a me de Cris e a sua, so a mesma
pessoa
1
. Portanto a idia de 'semelhana' diferente
dependendo do contexto.
Quando falamos de objetos, h uma
ambigidade similar. Por exemplo, se dois Pontos forem os
mesmos, isto quer dizer que eles contm os mesmos dados
(coordenadas) ou que so realmente o "mesmo" objeto?
Para verificar se duas referncias se referem ao
'mesmo' objeto, use o operador '=='
2
. Por exemplo:
>>> p1 = Poh1o{)
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = Poh1o{)
>>> p2.x = 3
>>> p2.y = 4
>>> p1 == p2
Fase
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
TJue
Este tipo de igualdade chamado de igualdade
rasa porque ela compara somente as referncias e no o
contedo dos objetos.
1 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".
2 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).
Para comparar o contedo dos objetos --
igualdade profunda -- podemos escrever uma funo chamada
mesmoPonto:
de1 mesmoPoh1o{p1, p2) .
Je1uJh {p1.x == p2.x) ahd {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 = Poh1o{)
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = Poh1o{)
>>> p2.x = 3
>>> p2.y = 4
>>> mesmoPoh1o{p1, p2)
TJue
claro, se as duas variveis referirem ao
mesmo objeto, elas tm igualdade rasa e igualdade profunda.
12.5 Retngulos
Digamos que desejemos uma classe para representar um
retngulo. A questo , qual informao temos de prover para
especificar um retngulo? Para manter as coisas simples,
assuma que o retngulo orientado verticalmente ou
horizontalmente, nunca em um ngulo.
H algumas possibilidades: poderamos
especificar o centro do retngulo (duas coordenadas) e seu
tamanho (largura e altura); ou poderamos especificar um dos
lados e o tamanho; ou poderamos especificar dois lados
opostos. A escolha convencional especificar o canto superior
esquerdo do retngulo e o tamanho.
Novamente, vamos definir uma nova classe:
cass Rec1ahge.
pass
E instanci-la:
box = Rec1ahge{)
box.w1d1h = 100.0
box.he1gh1 = 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!
box.coJheJ = Poh1o{)
box.coJheJ.x = 0.0,
box.coJheJ.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:
Captulo 12: Classes e objetos #64
Como pensar como um cientista da Computao usando Python
12.6 Instancias como valores retornados
Funes podem retornar instncias. Por exemplo, findCenter
pega um Retngulo como um argumento e retorna um Ponto
que contem as coordenadas do centro do retngulo:
de1 11hdCeh1eJ{box).
p = Poh1o{)
p.x = box.coJheJ.x + box.w1d1h/2.0
p.y = box.coJheJ.y + box.he1gh1/2.0
Para chamar esta funo, passe 'box' como um
argumento e coloque o resultado em uma varivel.
>>> ceh1eJ = 11hdCeh1eJ{box)
>>> pJ1h1 mos1JaJPoh1o{ceh1eJ)
{50.0, 100.0)
12.7 Objetos so mutveis
Podemos mudar o estado de um objeto fazendo uma
atribuio a um dos seus atributos. Por exemplo, para mudar o
tamanho de um retngulo sem mudar sua posio, podemos
modificar os valores de sua largura e altura. Veja:
box.w1d1h = box.w1d1h + 50
box.he1gh1 = box.he1gh1 + 100
Poderamos encapsular este cdigo em um
mtodo e generaliza-lo para aumentar o tamanho deste
retngulo em qualquer medida:
de1 gJowRec1{box, dw1d1h, dhe1gh1) .
box.w1d1h = box.w1d1h + dw1d1h
box.he1gh1 = box.he1gh1 + dhe1gh1
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 = Rec1ahge{)
>>> bob.w1d1h = 100.00
>>> bob.he1gh1 = 200.00
>>> bob.coJheJ.x = 0.0,
>>> bob.coJheJ.y = 0.0,
>>> gJowRec1{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'.
12.8 Copiando
Ao usar 'alias' - como fizemos na seo anterior - podemos
tornar o programa um pouco difcil de ler ou entender, pois as
mudanas feitas em um local, podem afetar inesperadamente
um outro objeto. E pode se tornar difcil de encontrar todas as
variveis que podem afetar um dado objeto.
Copiar um objeto freqentemente uma
alternativa ao 'alias'. O modulo 'copy' contm uma funo
chamada 'copy' que duplica um qualquer objeto. Veja:
>>> 1mpoJ1 copy
>>> p1 = Poh1o{)
>>> p1.x = 3
>>> p1.y = 4
>>> p2 = copy.copy{p1)
>>> p1 == p2
0
>>> mesmoPoh1o{p1, p2)
1
Uma vez que importamos o modulo 'copy',
podemos usar o mtodo 'copy' para criar um outro 'Ponto'. p1
e p2 no representam o mesmo ponto, mas eles contem os
mesmo dados.
Para copiar um simples objeto como um 'Ponto',
que no contem nenhum objeto embutido, 'copy' suficiente.
Isto eh chamado 'shallow' copia.
Mas para um objeto como um 'Rectangle', que
contem uma referencia para um 'Ponto', o mtodo 'copy' no
ir executar corretamente a copia. Ele ir copiar a referencia
para o objeto 'Ponto', portanto o que acontece aqui que os
dois Rectangle (o novo e o antigo) iro fazer referencia a um
simples 'Ponto'.
Em outras palavras, se criarmos um 'box', c1,
utilizando a forma usual, e depois fazer uma copia, c2, usando
o mtodo 'copy', o diagrama de estado resultante ficar assim:
o resultado no ser o que esperamos. Neste
caso, invocando 'growRect' em um dos retngulos (c1), isto
no ir afetar o outro retngulo (c2, neste exemplo). Mas se
usarmos o mtodo 'moveRect' em qualquer um deles, isto ir
inevitavelmente afetar o outro. Este comportamento confuso
e propenso a erros!
Mas felizmente o modulo 'copy' contem um
mtodo chamado 'deepcopy' que copia no somente o objeto,
mas tambm copia todo e qualquer objeto 'embutido' neste
objeto. Por isto, voc no ficar surpreso porque este mtodo
chama-se 'deepcopy' (copia profunda) no ? Veja como
funciona:
>>> c2 = copy.deepcopy{c1)
Agora, c1 e c2 so objetos completamente
separados.
Podemos usar 'deepcopy' para re-escrever
'growRect' sendo que ao invs de modificar um Rectangle
existente, ele cria um novo que tem a mesma localizao do
outro, mas com novas dimenses:
de1 gJowRec1{box, dw1d1h, dhe1gh1).
1mpoJ1 copy
hewBox = copy.deepcopy{box)
hewBox.w1d1h = hewBox.w1d1h + dw1d1h
hewBox.he1gh1 = hewBox.he1gh1 + dhe1gh1
Je1uJh hewBox
Como exerccio, re-escreva o mtodo
'moveRect' para ele criar e retornar um novo Rectangle ao
invs de apenas modificar o antigo.
Captulo 12: Classes e objetos #65
Como pensar como um cientista da Computao usando Python
12.9 Glossrio
classe (class) Um tipo composto (XXX compound type)
definido pelo usurio. Uma classe tambm
pode ser visualizada como um molde que
define a forma dos objetos que sero suas
instncias.
instanciar
(instantiate)
Criar uma instncia de uma classe.
instncia
(instance)
Um objeto que pertence a uma classe.
objeto (object) Um tipo de dado composto comumente
utilizado para representar uma coisa ou
um conceito do mundo real.
construtor
(constructor)
Um mtodo utilizado para criar novos
objetos.
atributo
(attribute)
Um dos itens de dados nomeados que
compem uma instncia.
igualdade rasa
(shallow
equality)
Igualdade de referncias; ocorre quando
duas referncias apontam para o mesmo
objeto.
igualdade
profunda (deep
equality)
Igualdade de valores; ocorre quando duas
referncias apontam para objetos que tm
o mesmo valor.
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.
Captulo 12: Classes e objetos #66
Como pensar como um cientista da Computao usando Python
Captulo 13: Classes e funes Captulo 13: Classes e funes
13.1 Horario
Como exemplo de outro tipo definido pelo usurio, vamos
definir uma classe chamada Horario que grava os registros de
horrio do dia. Eis a definio da classe:
cass hoJaJ1o.
pass
Podemos criar uma nova instncia de Horario e
determinar atributos para horas, minutos e segundos:
hoJaJ1o = hoJaJ1o{)
hoJaJ1o.hoJas = 11
hoJaJ1o.m1hu1os = 59
hoJaJ1o.seguhdos = 30
O diagrama de estado para o objeto Horario
parece com isso:
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).
13.2 Funes Puras
Nas prximas sesses, vamos escrever duas verses de uma
funo chamada adicionaHorario, que calcula a soma de dois
horrios. Elas vo demonstrar 2 tipos de funes: funes
puras e funes modificadoras.
Segue uma verso rudimentar de somaHorario:
de1 somahoJaJ1o{h1, h2).
soma = hoJaJ1o{)
soma.hoJas = h1.hoJas + h2.hoJas
soma.m1hu1os = h1.m1hu1os + h2.m1hu1os
soma.seguhdos = h1.seguhdos + h2.seguhdos
Je1uJh soma
A funo cria um novo objeto Horario,
inicializa os seus atributos, e retorna uma referncia para o
novo objeto. Isso chamado de funo pura pois ela no
modifica nenhum dos objetos que so passados como
parmetros e no tem nenhum efeito colateral, como imprimir
um valor ou pegar entrada do usurio.
Aqui est um exemplo de como usar esta
funo. Ns vamos criar dois objetos Horario: horarioAtual,
que contm o horrio atual; e horarioDoPao, que contm a
quantidade de tempo que a mquina de fazer po gasta para
fazer po. Ento vamos usar somaHorario para tentar saber
quando o po estar pronto. Se voc no tiver terminado de
escrever imprimirHorario ainda, de uma olhada na seo 14.2
antes de voc continuar isso:
>>> hoJaJ1oA1ua = hoJaJ1o{)
>>> hoJaJ1oA1ua.hoJas = 9
>>> hoJaJ1oA1ua.m1hu1os = 14
>>> hoJaJ1oA1ua.seguhdos = 30
>>> hoJaJ1o0oPao = hoJaJ1o{)
>>> hoJaJ1o0oPao.hoJas = 3
>>> hoJaJ1o0oPao.m1hu1os = 35
>>> hoJaJ1o0oPao.seguhdos = 0
>>> hoJaJ1oTeJm1ho = somahoJaJ1o{hoJaJ1oA1ua, \
hoJaJ1o0oPao)
>>> 1mpJ1m1JhoJaJ1o{hoJaJ1oTeJm1ho)
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 ?
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:
de1 somahoJaJ1o{11, 12).
soma = hoJaJ1o{)
soma.hoJas = 11.hoJas + 12.hoJas
soma.m1hu1os = 11.m1hu1os + 12.m1hu1os
soma.seguhdos = 11.seguhdos + 12.seguhdos
11 soma.seguhdos >= 60.
soma.seguhdos = soma.seguhdos - 60
soma.m1hu1os = soma.m1hu1os + 1
11 soma.m1hu1os >= 60.
soma.m1hu1os = soma.m1hu1os - 60
soma.hoJas = soma.hoJas + 1
Je1uJh 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
13.3 Modificadores
Existem momentos quando til para uma funo modificar
um ou mais dos objetos que ela recebe como parmetro.
Usualmente, quem est chamando a funo mantm uma
referncia para os objetos que ele passa, de forma que
quaisquer mudanas que a funo faz so visveis para quem
est chamando. Funes que trabalham desta forma so
chamadas modificadores.
Captulo 13: Classes e funes #67
Como pensar como um cientista da Computao usando Python
incrementar, que adiciona um nmero dado de
segundos para um objeto Horario, poderia ser escrito quase
naturalmente como um modificador. Um rascunho rudimentar
da funo seria algo parecido com isso:
de1 1hcJemeh1aJ{hoJaJ1o, seguhdos).
hoJaJ1o.seguhdos = \
hoJaJ1o.seguhdos + seguhdos
11 hoJaJ1o.seguhdos >= 60.
hoJaJ1o.seguhdos = \
hoJaJ1o.seguhdos - 60
hoJaJ1o.m1hu1os = hoJaJ1o.m1hu1os + 1
11 hoJaJ1o.m1hu1os >= 60.
hoJaJ1o.m1hu1os = \
hoJaJ1o.m1hu1os - 60
hoJaJ1o.hoJas = hoJaJ1o.hoJas + 1
A primeira linha executa a operao bsica; o
resto lida com os caso especiais que vimos antes.
Esta funo est correta ? O que aconteceria se
o parmetro 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:
de1 1hcJemeh1aJ{hoJaJ1o, seguhdos).
hoJaJ1o.seguhdos = \
hoJaJ1o.seguhdos + seguhdos
wh1e hoJaJ1o.seguhdos >= 60.
hoJaJ1o.seguhdos = hoJaJ1o.seguhdos -
60
hoJaJ1o.m1hu1os = hoJaJ1o.m1hu1os + 1
wh1e hoJaJ1o.m1hu1os >= 60.
hoJaJ1o.m1hu1os = \
hoJaJ1o.m1hu1os - 60
hoJaJ1o.hoJas = hoJaJ1o.hoJas + 1
Esta funo agora esta correta, mas no a
soluo mais eficiente.
Como um exerccio, reescreva esta funo de
maneira que ela no contenha nenhum loop. Como um
segundo exerccio, reescreva incrementar como uma funo
pura, e escreva chamadas de funes para as duas funes.
Clique aqui para feedback
13.4 O que melhor ?
Qualquer coisa que pode ser feita com modificadores tambm
podem ser feitas com funes puras. De fato, algumas
linguagens de programao permitem apenas funes puras.
Existe alguma evidncia que programas que usam funes
puras so desenvolvidos mais rapidamente e so menos
propensos a erros que programas que usam modificadores. No
entanto, modificadores as vezes so convenientes, e em alguns
casos, programao funcional menos eficiente.
Em geral, recomendamos que voc escreva
funes puras sempre que for necessrio e recorrer para
modificadores somente se existir uma grande vantagem. Esta
aproximao poderia ser chamada de um estilo de
programao funcional. Clique aqui para feedback
13.5 Desenvolvimento Prototipado versus
Desenvolvimento Planejado
Neste captulo, demonstramos uma aproximao para o
desenvolvimento de programas que chamamos de
desenvolvimento prototipado. Em cada caso, escrevemos um
rascunho rudimentar (ou prottipo) que executou os clculos
bsicos e ento, o testamos em uns poucos casos, corrigindo
as falhas que fomos encontrando.
Embora esta aproximao possa ser eficaz, ela
pode conduzir a cdigo que desnecessariamente complicado
pois trata de muitos casos especiais e no confivel, pois
difcil saber se voc encontrou todos os erros.
Uma alternativa o desenvolvimento planejado,
onde uma viso de alto nvel do problema pode tornar a
codificao muito mais fcil. Nesse caso, a abstrao que
um objeto Horario realmente um nmero de trs digitos na
base 60! O componente segundo a "coluna dos uns", o
componente minuto a "coluna do 60", e o componente hora
a "coluna do 360".
Quando ns escrevemos somaHorario e
incrementar, ns estvamos efetivamente fazendo adies em
base 60, que o motivo pelo qual tinhamos de transportar de
uma coluna para a prxima.
Essa observao sugere uma outra aproximao
para todo o problema - ns podemos converter um objeto
Horario em um nmero simples e levar vantagem do fato de
que um computador sabe como fazer aritmtica com nmeros.
A seguinte funo converte o objeto Horario em um inteiro:
de1 cohveJ1eJPaJaSeguhdos{1).
m1hu1os = 1.hoJas * 60 + 1.m1hu1os
seguhdos = m1hu1os * 60 + 1.seguhdos
Je1uJh seguhdos
Agora, tudo que precisamos uma maneira de
converter de um inteiro para um objeto Horario:
de1 cJ1aJhoJaJ1o{seguhdos).
hoJaJ1o = T1me{)
hoJaJ1o.hoJas = seguhdos/3600
seguhdos = seguhdos - hoJaJ1o.hoJas * 3600
hoJaJ1o.m1hu1os = seguhdos/60
seguhdos = seguhdos - hoJaJ1o.m1hu1os * 60
hoJaJ1o.seguhdos = seguhdos
Je1uJh hoJaJ1o
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:
de1 somahoJaJ1o{11, 12).
seguhdos = \
cohveJ1eJPaJaSeguhdos{11) + cohveJ1eJPaJaSeguhdos{12)
Je1uJh cJ1aJhoJaJ1o{seguhdos)
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
13.6 Generalizao
Algumas vezes, converter de base 60 para base 10 e voltar
mais difcil do que simplesmente lidar com horrios.
Captulo 13: Classes e funes #68
Como pensar como um cientista da Computao usando Python
Converso de base mais abstrata; nossa intuio para lidar
com horrios melhor.
Mas se conseguirmos abstrair horrios como
nmeros de base 60 e investirmos em criar as funes de
converso (converterParaSeguntos e criarHorario), ns
conseguimos um programa que menor, fcil de ler e depurar,
e mais confivel.
tambm fcil para adicionar funcionalidades
depois. Por exemplo, imagine subtrair dois Horarios para
encontrar a durao entre eles. Uma aproximao ingnua
seria implementar subtrao com emprstimo. Usando as
funes de converso ser mais fcil e provavelmente estar
correto.
Ironicamente, algumas vezes fazer um problema
mais difcil (ou mais genrico) o torna mais simples (porque
existem alguns poucos casos especiais e poucas oportunidades
para errar). Clique aqui para feedback
13.7 Algoritmos
Quando voc escreve uma soluo genrica para uma classe
de problemas, ao contrrio de uma soluo especfica para um
nico problema, voc escreveu um algoritmo. Ns
mencionamos isso antes mas no definimos cuidadosamente.
Isso no fcil para definir, ento vamos tentar definir
demonstrando algumas situaes.
Primeiramente, considere alguma coisa que no
seja um algoritmo. Quando voc aprendeu a multiplicar
nmeros de um dgito, voc provavelmente memorizou a
tabela de multiplicao. Como resultado, voc memorizou 100
solues especficas. Esse tipo de conhecimento no
algoritmo.
Mas se voc "preguioso", voc
provavelmente trapaceou por ter aprendido alguns truques.
Por exemplo, para encontrar o produto de n e 9, voc pode
escrever n-1 como o primeiro dgito e 10-n como o segundo
dgito. Este truque um soluo genrica para multiplicar
qualquer nmero de um dgito por 9. Isso um algoritmo!
De modo parecido, as tcnicas que voc
aprendeu para somar com transporte, subtrao com
emprstimo, e diviso longa so todas algoritmos. Uma das
caractersticas dos algoritmos que eles no requerem
nenhuma inteligncia para serem executados. Eles so
processos mecnicos no qual cada passo segue o ltimo de
acordo com um conjunto simples de regras.
Na nossa opinio, preocupante que humanos
gastem tanto tempo na escola aprendendo a executar
algoritmos que, literalmente, no requerem inteligncia.
Por outro lado, o processo de projetar
algoritmos interessante, intelectualmente 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.
13.8 Glossrio
funo pura (pure
function)
Uma funo que no modifica
nenhum dos objetos que ela recebe
como parmetro. A maioria das
funes puras frutfera.
modificador
(modifier)
Uma funo que muda um ou mais
dos objetos que ela recebe como
parmetros. A maioria dos
modificadores nula.
estilo de
programao
funcional (functional
programming style)
Um estilo de programao onde a
maioria das funes so puras.
desenvolvimento
prototipado
(prototype
development)
Uma maneira de desenvolver
programas comeando com um
prottipo e gradualmente
melhorando-o.
desenvolvimento
planejado (planned
development)
Uma maneira de desenvolver
programas que envolvem uma
percepo de alto nvel do problema
e mais planejamento do que
desenvolvimento incremental ou
desenvolvimento prototipado.
algoritmo (algorithm) Um conjunto de instrues para
resolver uma classe de problemas
usando um processo mecnico, no
inteligente.
Captulo 13: Classes e funes #69
Como pensar como um cientista da Computao usando Python
Captulo 14: Classes e mtodos Captulo 14: Classes e mtodos
ATENO As referncias cruzadas a nomes em cdigos de
outros captulos (especialmente 13) ainda no foram
unificadas...
14.1 Caractersticas da orientao a objetos
Python uma linguagem de programao orientada a
objetos, o que significa que ela tem caractersticas que
suportam a programao orientada a objetos.
No fcil definir programao orientada a
objetos, mas temos visto already algumas de suas
caractersticas:
e Programas so construdos sobre definies de
objetos e definies de funes, e a maioria das
computaes expressa em termos de operaes
sobre objetos.
e Cada definio de objeto corresponde a algum objeto
ou conceito do mundo real, e as funes que operam
com aqueles objetos correspondem maneira como
os objetos do mundo real interagem.
Por exemplo, a classe Tempo, definida no
captulo 13 corresponde maneira como as pessoas registram
as horas do dia, e as funes que definimos correspondem aos
tipos de coisas que as pessoas fazem com times. Do mesmo
modo, as classes Ponto e Retngulo correspondem aos
conceitos matemticos de um ponto e de um retngulo.
At aqui, no tiramos vantagem das
caractersticas fornecidas por Python que suportam a
programao orientada a objetos. Estritamente falando, estas
caractersticas no so necessrias. Na maior parte das vezes,
elas fornecem uma sintaxe alternativa para as coisas que j
fizemos, mas em muitos casos, a alternativa mais concisa e
convm mais acuradamente estrutura do programa.
Por exemplo, no programa Time, no existe
uma conexo bvia entre a definio da classe e a definio da
funo que segue. Com alguma investigao, fica aparente
que toda funo toma pelo menos um objeto Time como um
parmetro.
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:
e Mtodos so definidos dentro da definio de uma
classe para tornar explcita a relao entre a classe e o
mtodo.
e 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.
14.2 exibeHora (printTime)
No captulo 13, definimos uma classe chamada Horrio
(Time) e voc escreveu uma funo chamada exibeHora
(printTime), que deve ter ficado mais ou menos assim:
cass hoJaJ1o.
pass
de1 ex1behoJa{11me)
pJ1h1 s1J{11me.hoJas) + ?.? + \
s1J{11me.m1hu1os) + ?.? + \
s1J{11me.seguhdos)
Para chamar esta funo, passamos um objeto
Time como um parmetro:
>>> hoJaCoJJeh1e = hoJa{)
>>> hoJaCoJJeh1e.hoJas = 9
>>> hoJaCoJJeh1e.m1hu1os = 14
>>> hoJaCoJJeh1e.seguhdos = 30
>>> ex1behoJa{hoJaCoJJeh1e)
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:
cass hoJaJ1o.
de1 ex1behoJa{11me).
pJ1h1 s1J{11me.hoJas) + ?.? + \
s1J{11me.m1hu1os) + ?.? + \
s1J{11me.seguhdos)
Agora podemos chamar exibeHora usando a
natao de ponto:
>>> hoJaCoJJeh1e.ex1behoJa{)
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.?
Na programao orientada a objetos, os objetos
so agentes ativos. Uma chamado do tipo
horaCorrente.exibeHora() diz ?Ei, horaCorrente! Por favor
exiba-se a si mesmo!?
Esta mudana de perspectiva pode ser mais
polida, mas no fica bvio que seja til. Nos exemplos que
temos visto at aqui, pode ser que no seja. Mas s vezes,
deslocar a responsabilidade das funes para cima dos objetos
torna possvel escrever funes mais versteis, e torna mais
fcil manter e reutilizar o cdigo.
Captulo 14: Classes e mtodos #70
Como pensar como um cientista da Computao usando Python
14.3 Um outro exemplo
Vamos converter incremento (da Seo 13.3) em um mtodo.
Para poupar espao, deixaremos de fora mtodos definidos
previamente(anteriormente?), mas voc deve mant-los em
sua verso:
cass T1me.
#pJev1ous me1hod de11h111ohs heJe...
de1 1hcJemeh1{se1, seguhdos).
se1.secohds = secohds + se1.secohds
wh1e se1.seguhdos >= 60.
se1.secohds = se1.seguhdos - 60
se1.m1hu1es = se1.m1hu1os + 1
wh1e se1.m1hu1es >= 60.
se1.m1hu1es = se1.m1hu1os - 60
se1.houJs = se1.hoJas + 1
A transformao puramente mecnica ?
movemos a definio do mtodo para dentro da definio da
classe e mudamos o nome do primeiro parmetro.
Agora podemos chamar incremento como um
mtodo:
hoJaCoJJeh1e.1hcJemeh1o{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?.
14.10 Glossrio
linguagem Uma linguagem que prov caractersticas
orientada a
objetos
tais como classes definidas pelo usurio e
herana, que facilitam a programao
orientada a objetos.
programao
orientada a
objetos
Um estilo de programao na qual os
dados e as operaes que os manipulam
esto organizados em classes e mtodos.
mtodo Uma funo que definida dentro de uma
definio de classe e chamada em
instncias desta classe.
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.
Captulo 14: Classes e mtodos #71
Como pensar como um cientista da Computao usando Python
Captulo 15: Conjuntos de objetos Captulo 15: Conjuntos de objetos
15.1 Composio
At agora, voc vio diversos exemplos de composio. Um
dos primeiros exemplos foi o uso de uma invocao de
mtodo como parte de uma expresso. Outro exemplo a
estrutura aninhada dos comandos: voc pode pr um comando
if dentro de um lao while, dentro de outro comando if, e
assim por diante.
Tendo visto este padro, e tendo aprendido a
respeito de listas e objetos, voc no deveria ficar surpreso em
aprender que voc pode criar listas de objetos. Voc tambm
pode criar obejtos que contm listas (como atritos); voc pode
criar listas que contm listas; voc pode criar objetos que
contm objetos; e assim por diante.
Neste captulo e no prximo, voc ir ver alguns
exemplos destas combinaes, usando objetos Carta como
exemplo.
15.2 Objetos Carta
Se voc no estiver familiarizado com jogos de cartas, agora
um bom momento para conseguir um baralho, ou ento esse
captulo pode no fazer muito sentido. H 52 cartas em um
baralho, cada uma das quais pertence a um dos quatro naipes e
a uma das treze posies. Os naipes so Espadas, Copas,
Ouros e Paus (em ordem descendente no bridge). As posies
so s, 2, 3, 4, 5, 6, 7, 8, 9, 10, Valete, Rainha e Rei.
Dependendo do jogo, a posio do s pode ser maior do que a
do Rei ou menor do que a do 2.
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:
e Espadas -> 3
e Copas -> 2
e Ouros -> 1
e 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:
e Valete -> 11
e Rainha -> 12
e 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:
cass CaJ1a.
de1 __1h11__{se1, ha1pe=0, pos1cao=0).
se1.ha1pe = ha1pe
se1.pos1cao = pos1cao
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:
1Jes0ePaus = CaJ1a{0, 3)
O primeiro argumento, 0, representa o naipe de
Paus.
15.3 Atributos de classe e o mtodo __str__
Para imprimir objetos Carta de uma maneira que as pessoas
possam facilmente ler, ns gostaramos de mapear os cdigos
inteiros para palavras. Uma forma natural de fazer isso usar
listas de strings. Ns atribumos estas listas para atributos de
classe no topo da definio de classe:
cass CaJ1a.
1s1a0eha1pes = |"Paus", "0uJos", "Copas",
"Espadas"]
1s1a0ePos1coes = |"haJ1", "As", "2", "3", "4",
"5", "6", "7",
"8", "9", "10", "vae1e",
"Ra1hha", "Re1"]
# m1odo 1h11 om111do
de1 __s1J__{se1).
Je1uJh {se1.1s1a0ePos1coes|se1.pos1cao] +
" de " + se1.L1s1a0eha1pes|se1.ha1pe])
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
Captulo 15: Conjuntos de objetos #72
Como pensar como um cientista da Computao usando Python
3, e assim por diante.
Com os mtodos que ns temos at agora, ns
podemos criar e imprimir cartas:
>>> caJ1a1 = CaJ1a{1, 11)
>>> pJ1h1 caJ1a1
vae1e de 0uJos
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:
>>> caJ1a2 = CaJ1a{1, 3)
>>> pJ1h1 caJ1a2
3 de 0uJos
>>> pJ1h1 caJ1a2.1s1a0eha1pes|1]
0uJos
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:
>>> caJ1a1.1s1a0eha1pes = "Bae1as Rodop1ah1es"
>>> pJ1h1 caJ1a1
3 de Bae1as Rodop1ah1es
O problema que todos os Ouros se tornam
Baleias Rodopiantes:
>>> pJ1h1 caJ1a2
3 de Bae1as Rodop1ah1es
Normalmente, no uma boa idia modificar
atributos de classe.
15.4 Comparando cartas
Para tipos primitivos, existem operadores condicionais (<, >,
==, etc.) que comparam valores e determinam quando um
maior que, menor que ou igual a outro. Para tipos definidos
pelo usurio, ns podemos sobrescrever o comportamento dos
operadores pr-definidos fornecendo um mtodo __cmp__.
Por conveno, __cmp__ recebe dois parmetros, self e other,
e retorna 1 se o primeiro objeto for maior, -1 se o segundo
objeto for maior, e 0 se eles forem iguais.
Alguns tipos so totalmente ordenados, o que
significa que ns podemos comparar quaisquer dois elementos
e dizer qual o maior. Por exemplo, os inteiros e os nmeros
de ponto flutuante so totalmente ordenados. Alguns
conjuntos so no-ordenados, o que significa que no existe
maneira significativa de dizer que um elemento maior que o
outro. Por exemplo, as frutas so no-ordenadas, e por isso
que no podemos comparar mas e laranjas.
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__:
de1 __cmp__{se1, o1heJ).
# veJ111caJ os ha1pes
11 se1.ha1pe > o1heJ.ha1pe. Je1uJh 1
11 se1.ha1pe < o1heJ.ha1pe. Je1uJh -1
# as caJ1as 1m o mesmo ha1pe... veJ111caJ as
pos1es
11 se1.pos1cao > o1heJ.pos1cao. Je1uJh 1
11 se1.pos1cao < o1heJ.pos1cao> Je1uJh -1
# as pos1es so 1gua1s... um empa1e
Je1uJh 0
Nesta ordenao, Ases so menores do que 2.
Como um exerccio, modifique ``__cmp__``, de
modo que os Ases sejam maiores do que os Reis.
15.5 Baralhos
Agora que ns temos objetos para representar Cartas, o
prximo passo lgico definir uma classe para representar um
Baralho. claro que um baralho formado por cartas;
portanto, cada objeto Baralho ir conter uma lista de cartas
como um atributo.
A seguir, damos uma definio para a classe
Baralho. O mtodo de inicializao cria o atributo cartas e
gera o conjunto padro de 52 cartas:
casse BaJaho
de1 __1h11__{se1).
se1.caJ1as = |]
1oJ ha1pe 1h Jahge{4).
1oJ pos1cao 1h Jahge{1, 14).
se1.caJ1as.appehd{CaJ1a{ha1pe, pos1cao))
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.
15.6 Imprimindo o baralho
Como sempre, quando ns definimos um novo tipo de objeto,
ns gostaramos de ter um mtodo para imprimir o contedo
de um objeto. Para imprimir um Baralho, ns percorremos a
lista e imprimimos cada Carta:
cass BaJaho.
...
de1 1mpJ1m1JBaJaho{se1).
1oJ caJ1a 1h se1.caJ1as.
pJ1h1 caJ1a
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:
Captulo 15: Conjuntos de objetos #73
Como pensar como um cientista da Computao usando Python
cass BaJaho.
...
de1 __s1J__{se1).
s = ""
1oJ 1 1h Jahge{eh{se1.caJ1as)).
s = s + " "*1 + s1J{se1.caJ1as|1]) + "\h"
Je1uJh 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:
>>> baJaho = BaJaho{)
>>> pJ1h1 BaJaho
As 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
vae1e de Paus
Ra1hha de Paus
Re1 de Paus
As de 0uJos
E assim por diante. Mesmo que o resultado
aparea em 52 linhas, uma string longa que contm
newlines.
15.7 Embaralhando
Se um baralho estiver perfeitamente embaralhado, ento cada
carta tem a mesma probabilidade de aparecer em qualquer
lugar no baralho, e qualquer localizao no baralho tem a
mesma probabilidade de conter qualquer carta.
Para embaralhar as cartas, ns usaremos a
funo randrange do mdulo random. Com dois argumentos
inteiros, a e b, randrange escolhe um inteiro aleatrio no
intervalo a <= x < b. Como o limite superior estritamente
menor que b, ns podemos usar o comprimento de uma lista
como o segundo parmetro, e ns garantimos que o ndice
sempre ser vlido. Por exemplo, esta expresso escolhe o
ndice de uma carta aleatria em um baralho:
Jahdom.JahdJahge{0, eh{se1.caJ1as))
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:
cass BaJaho.
...
de1 embaJahaJ{se1).
1mpoJ1 Jahdom
hCaJ1as = eh{se1.caJ1as)
1oJ 1 1h Jahge{hCaJ1as).
= Jahdom.JahdJahge{1, hCaJ1as)
se1.caJ1as|1], se1.caJ1as|] =
se1.caJ1as|], se1.caJ1as|1]
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:
se1.caJ1as|1], se1.caJ1as|] = se1.caJ1as|],
se1.caJ1as|1]
Como exerccio, reescreva esta linha de cdigo
sem usar uma atribuio de seqncia.
15.8 Removendo e distribuindo cartas
Outro mtodo que pode ser til para a classe Baralho
removerCarta. Ele recebe uma carta como parmetro, remove-
a do baralho e retorna verdadeiro (1), se a carta estava no
baralho e falso (0), caso contrrio:
cass BaJaho.
...
de1 JemoveJCaJ1a{se1, caJ1a).
11 caJ1a 1h se1.caJ1as.
se1.caJ1as.Jemove{caJ1a)
Je1uJh 1
ese
Je1uJh 0
O operador in retorna verdadeiro se o primeiro
operando estiver contido no segundo, que deve ser uma lista
ou uma tupla. Se o primeiro operando for um objeto, Python
usa o mtodo __cmp__ do objeto para determinar 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:
cass BaJaho.
...
de1 d1s1J1bu1JCaJ1a{se1).
Je1uJh se1.caJds.pop{)
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:
cass BaJaho.
...
de1 es1ahvaz1o{se1).
Je1uJh {eh{se1.caJ1as) == 0)
Captulo 15: Conjuntos de objetos #74
Como pensar como um cientista da Computao usando Python
15.9 Glossrio
codificar
(encode)
Representar um conjunto de valores
usando outro conjunto de valores,
construindo um mapeamento entre eles.
atributo de
classe (class
atribute)
Uma varivel que definida dentro de uma
definio de classe, mas fora de qualquer
mtodo. Atributos de classe podem ser
acessados a partir de qualquer mtodo da
classe e so compartilhados por todas as
instncias da classe.
acumulador
(accumulator)
Uma varivel usada em um lao para
acumular uma srie de valores, para, por
exemplo, concaten-los em uma string ou
som-los a uma soma em andamento.
Captulo 15: Conjuntos de objetos #75
Como pensar como um cientista da Computao usando Python
Capitulo 16: Herana Capitulo 16: Herana
16.1 Herana
Uma das caractersticas mais marcantes das linguagens
orientadas a objetos a herana. Herana a habilidade de
definir uma nova classe que uma verso modificada de uma
classe existente.
A principal vantagem dessa caracterstica que
voc pode adicionar novos mtodos a uma classe sem ter que
modificar a classe existente. Chama-se "herana" porque a
nova classe herda todos os mtodos da classe existente.
Ampliando a metfora, podemos dizer que a classe existente
s vezes chamada de classe me (parent). A nova classe pode
ser chamada de classe filha ou, simplesmente, "subclasse".
A herana uma caracterstica poderosa.
Alguns programas que seriam complicados sem herana
podem ser escritos de forma simples e concisa graas a ela. E
a herana tambm pode facilitar o reuso do cdigo, uma vez
que voc pode adaptar o comportamento de classes existentes
sem ter que modific-las. Em alguns casos, a estrutura da
herana reflete a natureza real do problema, tornando o
programa mais fcil de entender.
Por outro lado, a herana pode tornar um
programa seja difcil de ler. Quando um mtodo invocado,
s vezes no est claro onde procurar sua definio. A parte
relevante do cdigo pode ser espalhada em vrios mdulos. E,
tambm, muitas das coisas que podem ser feitas utilizando
herana tambm podem ser feitas de forma igualmente
elegante (ou at mais) sem ela. Se a estrutura natural do
problema no se presta a utilizar herana, esse estilo de
programao pode trazer mais problemas que vantagens.
Nesse captulo, vamos demonstrar o uso de
herana como parte de um programa que joga uma variante de
Mico. Um dos nossos objetivos escrever um cdigo que
possa ser reutilizado para implementar outros jogos de cartas.
16.2 Uma mo de cartas
Para quase todos os jogos de baralho, preciso representar
uma mo de cartas. Uma mo de cartas similar a um mao
de baralho. Porque ambos so formados por uma srie de
cartas e ambos requerem operaes, como, adicionar e
remover cartas. Fora isso, a habilidade de embaralhar a mo e
o baralho tambm so teis.
Mas, ao mesmo tempo, a mo tambm
diferente do baralho. Dependendo do jogo que est sendo
jogado, precisamos realizar algumas operaes nas mos de
cartas que no fazem sentido para o baralho inteiro. Por
exemplo, no pquer, podemos classificar uma mo (trinca,
flush, etc.) ou compar-la com outra mo. No jogo de bridge,
podemos querer computar a quantidade de pontos que h
numa mo, a fim de fazer um lance.
Essa situao sugere o uso de herana. Se Mao
uma subclasse de Baralho, ter todos os mtodos de Baralho, e
novos mtodos podem ser adicionados.
Na definio de classe, o nome da classe pai
aparece entre parnteses:
cass hao{BaJaho).
pass
Esse comando indica que a nova classe Mao
herda da classe existente Baralho.
O construtor de Mao inicializa os atributos da
mo, que so nome e cartas. A string nome identifica essa
mo, provavelmente pelo nome do jogador que est segurando
as cartas. O nome um parmetro opcional com a string vazia
como valor default. cartas a lista de cartas da mo,
inicializada com uma lista vazia
cass hao{BaJaho).
de1 __1h11__{se1, home="").
se1.caJ1as = |]
se1.home = home
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:
cass hao{BaJaho).
#...
de1 ad1c1ohaJCaJ1a{se1,caJ1a).
se1.caJ1as.appehd{caJ1a)
De novo, a elipse indica que omitimos outros
mtodos. O mtodo de listas append adiciona a nova carta no
final da lista de cartas.
16.3 Dando as cartas
Agora que temos uma classe Mao, queremos distribuir cartas
de Baralho para mos de cartas. No imediatamente bvio se
esse mtodo deve ir na classe Mao ou na classe Baralho, mas
como ele opera num nico baralho e (possivelmente) em
vrias mos de cartas, mais natural coloc-lo em Baralho.
O mtodo distribuir deve ser bem geral, j que
diferentes jogos tero diferentes requerimentos. Podemos
querer distribuir o baralho inteiro de uma vez s ou adicionar
uma carta a cada mo.
distribuir recebe dois argumentos, uma lista (ou
tupla) de mos e o numero total de cartas a serem dadas. Se
no houver cartas suficientes no baralho, o mtodo d todas as
cartas e pra:
cass BaJaho.
#...
de1 d1s1J1bu1J{se1, maos, hCaJ1as=999).
hhaos = eh{maos)
1oJ 1 1h Jahge{hCaJ1as).
11 se1.es1ahvaz1a{). bJeak
# 1h1eJJompeJ se acabaJam as caJ1as
caJ1a = se1.pegaJCaJ1a{)
# pegaJ a caJ1a do 1opo
mao = maos|1 hhaos]
# quem deve JecebeJ agoJa?
mao.ad1c1ohaJCaJ1a{caJ1a)
# ad1c1ohaJ a caJ1a 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.
Capitulo 16: Herana #76
Como pensar como um cientista da Computao usando Python
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).
16.4 Exibindo a mao
Para exibir o contedo de uma mo, podemos tirar vantagem
dos mtodos exibirBaralho e __str__ herdados de Baralho. Por
exemplo:
>>> baJaho = BaJaho{)
>>> baJaho.embaJahaJ{)
>>> mao = hao{"1ab1o")
>>> baJaho.d1s1J1bu1J{|mao], 5)
>>> pJ1h1 mao
ho 1ab1o coh1m
2 de espadas
3 de espadas
4 de espadas
As de copas
9 de paus
Nao l uma grande mo, mas tem potencial
para um straight flush.
Embora seja conveniente herdar os mtodos
existentes, h outras informacoes num objeto Mao que
podemos querer incluir quando ao exib-lo. Para fazer isso,
podemos fornecer um mtodo __str__ para a classe Mao que
sobrescreva o da classe Baralho:
cass hao{BaJaho)
#...
de1 __s1J__{se1).
s = "hao " + se1.home
11 se1.es1ahvaz1a{).
Je1uJh s + " es1 vaz1a\h"
ese.
Je1uJh s + " coh1m\h" + BaJaho.__s1J__{se1)
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.
16.5 A classe JogoDeCartas
A classe JogoDeCartas toma conta de algumas tarefas bsicas
comuns a todos os jogos, como, criar o baralho e embaralh-
lo:
cass Jogo0eCaJ1as.
de1 __1h11__{se1).
se1.baJaho = BaJaho{)
se1.baJaho.embaJahaJ{)
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...
16.6 Classe MaoDeMico
Uma mo para jogar Mico requer algumas habilidades para
alem das habilidades gerais de uma Mao. Vamos definir uma
nova classe, MaoDeMico, que herda de Mao e prov um
mtodo adicional chamado descartarCasais:
cass hao0eh1co{hao).
de1 descaJ1aJCasa1s{se1).
coh1a = 0
caJ1asTh1c1a1s = se1.caJ1as|.]
1oJ caJ1a 1h caJ1asTh1c1a1s.
casa = CaJ1a{3 - caJ1a.ha1pe, caJ1a.vaoJ)
11 casa 1h se1.caJ1as.
se1.caJ1as.Jemove{caJ1a)
se1.caJ1as.Jemove{casa)
pJ1h1 "hao s. s casa1s s"
{se1.home,caJ1a,casa)
coh1a = coh1a + 1
Je1uJh coh1a
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!
Capitulo 16: Herana #77
Como pensar como um cientista da Computao usando Python
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:
>>> ogo = Jogo0eCaJ1as{)
>>> mao = hao0eh1co{"1ab1o")
>>> ogo.baJaho.d1s1J1bu1J{|mao], 13)
>>> pJ1h1 mao
mo 1ab1o coh1m
As de espadas
2 de ouJos
7 de espadas
8 de paus
6 de copas
8 de espadas
7 de paus
Ra1hha de paus
7 de ouJos
5 de paus
vae1e de ouJos
10 de ouJos
10 de copas
>>> mao.descaJ1aJCasa1s{)
ho 1ab1o. 7 de espadas 1az paJ com 7 de paus
ho 1ab1o. 8 de espadas 1az paJ com 8 de paus
ho 1ab1o. 10 de ouJos 1az paJ com 10 de copas
>>> pJ1h1 mao
ho 1ab1o coh1m
As de espadas
2 de ouJos
6 de copas
Ra1hha de paus
7 de ouJos
5 de paus
vae1e de ouJos
Observe que no existe um mtodo __init__
para a classe MaoDeMico. Ele herdado de Mao.
16.7 Classe Mico
Agora podemos focar nossa ateno no jogo em si. Mico
uma subclasse de JogoDeCartas com um novo mtodo
chamado jogar que recebe uma lista de jogadores como
argumento.
J que __init__ herdado de JogoDeCartas, um
novo objeto Mico contm um novo baralho embaralhado:
cass h1co{Jogo0eCaJ1as).
de1 ogaJ{se1, homes).
# JemoveJ a 0ama de paus
se1.baJaho.JemoveJCaJ1a{CaJ1a{0,12))
# 1azeJ uma mo paJa cada ogadoJ
se1.maos = |]
1oJ home 1h homes .
se1.maos.appehd{hao0eh1co{home))
# d1s1J1bu1J as caJ1as
se1.baJaho.d1s1J1bu1J{se1.maos)
pJ1h1 "---------- As caJ1as 1oJam dadas"
se1.ex1b1Jhaos{)
# JemoveJ casa1s 1h1c1a1s
casa1s = se1.JemoveJTodos0sCasa1s{)
pJ1h1 "---------- 0s paJes 1oJam descaJ1ados, o
ogo comea"
se1.ex1b1Jhaos{)
# ogaJ a1 que 25 casa1s se 1oJmem
vez = 0
humhaos = eh{se1.maos)
wh1e casa1s < 25.
casa1s = casa1s + se1.ogaJvez{vez)
vez = {vez + 1) humhaos
pJ1h1 "---------- F1m do ogo"
se1.ex1b1Jhaos{)
Algumas etapas do jogo foram separadas em
mtodos. removerTodosOsCasais percorre a lista de mos e
invoca descartarCasais em cada uma:
cass h1co{Jogo0eCaJ1as).
#...
de1 JemoveJTodos0sCasa1s{se1).
coh1a = 0
1oJ mao 1h se1.maos.
coh1a = coh1a + mao.descaJ1aJCasa1s{)
Je1uJh coh1a
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:
cass h1co{Jogo0eCaJ1as).
#...
de1 ogaJvez{se1, 1).
11 se1.maos|1].es1ahvaz1a{).
Je1uJh 0
v1z1hho = se1.buscaJv1z1hho{1)
hovaCaJ1a = se1.maos|v1z1hho].pegaJCaJ1a{)
se1.maos|1].ad1c1ohaJCaJ1a{hovaCaJ1a)
pJ1h1 "hao", se1.maos|1].home, "pegou",
hovaCaJ1a
coh1a = se1.maos|1].descaJ1aJCasa1s{)
se1.maos|1].embaJahaJ{)
Je1uJh coh1a
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.
Capitulo 16: Herana #78
Como pensar como um cientista da Computao usando Python
O mtodo buscarVizinho comea com o jogador
imediatamente esquerda e continua ao redor da mesa at
encontrar um jogador que ainda tenha cartas:
cass h1co{Jogo0eCaJ1as).
#...
de1 buscaJv1z1hho{se1, 1).
humhaos = eh{se1.maos)
1oJ hex1 1h Jahge{1,humhaos).
v1z1hho = {1 + hex1) humhaos
11 ho1 se1.maos|v1z1hho].es1ahvaz1a{).
Je1uJh v1z1hho
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:
>>> 1mpoJ1 caJ1as
>>> ogo = caJ1as.h1co{)
>>> ogo.ogaJ{|"A1ce","Ja1J","CaJa"])
---------- As caJ1as 1oJam dadas
ho A1ce coh1m
Re1 de copas
vae1e de paus
Ra1hha de espadas
Re1 de espadas
10 de ouJos
ho Ja1J coh1m
Ra1hha de copas
vae1e de espadas
vae1e de copas
Re1 de ouJos
Ra1hha de ouJos
ho CaJa coh1m
vae1e o1 ouJos
Re1 de paus
10 de espadas
10 de copas
10 de paus
ho Ja1J. 0ama de copas 1az paJ com 0ama de ouJos
ho CaJa. 10 de espadas 1az paJ com 10 de paus
---------- 0s paJes 1oJam descaJ1ados, o ogo comea
ho A1ce coh1m
Re1 de copas
vae1e de paus
Ra1hha de espadas
Re1 de espadas
10 de ouJos
ho Ja1J coh1m
vae1e de espadas
vae1e de copas
Re1 de ouJos
ho CaJa coh1m
vae1e de ouJos
Re1 de paus
10 de copas
ho A1ce pegou o Re1 de ouJos
ho A1ce. Re1 de copas 1az paJ com Re1 de ouJos
ho Ja1J pegou 10 de copas
ho CaJa pegou vae1e de paus
ho A1ce pegou vae1e de copas
ho Ja1J pegou vae1e de ouJos
ho CaJa pegou 0ama de espadas
ho A1ce pegou vae1e de ouJos
ho A1ce. vae1e de copas 1az paJ com vae1e de
ouJos
ho Ja1J pegou Re1 de paus
ho CaJa pegou Re1 de espadas
ho A1ce pegou 10 de copas
ho A1ce. 10 de ouJos 1az paJ com 10 de copas
ho Ja1J pegou 0ama de espadas
ho CaJa pegou vae1e de espadas
ho CaJa. vae1e de paus 1az paJ com vae1e de
espadas
ho Ja1J pegou Re1 de espadas
ho Je11. Re1 de paus 1az paJ com Re1 de espadas
---------- F1m do ogo
ho A1ce es1 vaz1a
ho Ja1J coh1m
Ra1hha de espadas
ho CaJa es1 vaz1a
Eh1o, o Ja1J peJdeu.
16.8 Glossrio
herana (inheritance) Habilidade de definir uma nova
classe que a verso modificada de
uma classe definida anteriormente.
classe me (parent
class)
A classe de quem a classe filha
herda.
classe filho (child
class)
Um nova classe criada herdando de
uma classe existente; tambm
chamada de "subclasse".
Capitulo 16: Herana #79
Como pensar como um cientista da Computao usando Python
Captulo 17: Listas encadeadas Captulo 17: Listas encadeadas
17.1 Referncias Embutidas
Ns temos visto exemplos de atributos que referenciam outros
objetos, que so chamados referncias embutidas (veja a
Seo 12.8). Uma estrutura de dados comum, a lista ligada,
tira vantagem desta caracterstica.
Listas ligadas so constitudas de ns (nodos),
onde cada n contm uma referncia para o prximo n na
lista. Alm disto, cada n contm uma unidade de dados
chamada a carga.
Uma lista ligada considerada uma estrutura
de dados recorrente porque ela tem uma definio
recorrente.
Uma lista ligada :
e Uma lista vazia, representada por None, ou
e Um n que contm um objeto carga e uma referncia
para uma lista ligada.
Estruturas de dados recorrentes so adequadas
para mtodos recorrentes.
17.2 A classe No (Node)
Como usual quando se escreve uma nova classe, ns
comearemos com os mtodos de inicializao e __str__ de
modo que podemos testar o mecanismo bsico de se criar e
mostrar o novo tipo:
cass ho.
de1 __1h11__{se1, caJga=hohe, pJox1mo=hohe).
se1.caJga = caJga
se1.pJox1mo = pJox1mo
de1 __s1J__{se1).
Je1uJh s1J{se1.caJga)
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:
>>> ho = ho{"1es1e")
>>> pJ1h1 ho
1es1e
Para ficar interessante, ns precisamos uma lista
com mais do que um n:
>>> ho1 = ho{1)
>>> ho2 = ho{2)
>>> ho3 = ho{3)
Este cdigo cria trs ns, mas ns ainda no
temos uma lista ainda porque os ns no esto ligados. O
diagrama de estado parecido com este:
Para ligar os ns, temos que fazer o primeiro n
da lista referir ao segundo e o segundo n referir ao terceiro:
>>> ho1.pJox1mo = ho2
>>> ho2.pJox1mo = ho3
A referncia do terceiro n None, que indica
que ele o final da lista. Agora o diagrama de estado se
parece com:
Agora voc sabe como criar ns e lig-los em
uma lista. O que pode estar menos claro neste ponto por qu.
17.3 Listas como Colees
Listas so teis porque elas provm um modo de montar
mltiplos objetos em uma nica entidade, algumas vezes
chamada uma coleo. No exemplo, o primeiro n da lista
serve como uma referncia para toda a lista.
Para passar uma lista como um parmetro, voc
apenas tem que passar uma referncia ao primeiro n. Por
exemplo, a funo imprimeLista toma um nico n como um
argumento. Iniciando com o cabea da lista, ela imprime cada
n at que chegue ao fim:
de1 1mpJ1meL1s1a{ho).
wh1e ho.
pJ1h1 ho,
ho = ho.pJox1mo
pJ1h1
Para chamar este mtodo, ns passamos uma
referncia ao primeiro no:
>>> 1mpJ1meL1s1a{ho1)
1 2 3
Dentro de imprimeLista ns temos uma
referncia para o primeiro n da lista, mas no h variveis
que refiram aos outros ns. Ns temos que usar o valor
proximo de cada n para alcanar o prximo n.
Para percorrer uma lista ligada, comum usar
uma varivel lao como no para referir a cada um dos ns
sucessivamente.
Este diagrama mostra o valor de lista e os
valores que no assume:
Captulo 17: Listas encadeadas #80
Como pensar como um cientista da Computao usando Python
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.
17.4 Listas e Recorrncia
natural expressar muitas operaes de listas utilizando
mtodos recorrentes. Por exemplo, o seguinte um algoritmo
recorrente para imprimir uma lista de trs para frente.
1. Separe a lista em dois pedaos: o primeiro n
(chamado a cabea); e o resto (chamado o rabo).
2. Imprima o rabo de trs para frente.
3. Imprima a cabea.
Logicamente, o Passo 2, a chamada recorrente,
assume que ns temos um modo de imprimir a lista de trs
para frente. Mas se ns assumimos que a chamada recorrente
funciona -- o passo de f -- ento podemos nos convencer de
que o algoritmo funciona.
Tudo o que precisamos so um caso base e um
modo de provar que para qualquer lista, ns iremos, ao final,
chegar no caso base. Dada a definio recorrente de uma lista,
um caso base natural a lista vazia, representada por None:
de1 1mpJ1me0eTJasPaJaFJeh1e{1s1a).
11 1s1a == hohe . Je1uJh
cabeca = 1s1a
Jabo = 1s1a.pJox1mo
1mpJ1me0eTJasPaJaFJeh1e{Jabo)
pJ1h1 cabeca,
A primeira linha trata o caso base fazendo nada.
As prximas duas linhas dividem a lista em cabeca e rabo. As
duas ltimas linhas imprimem a lista. A vrgula no final da
ltima linha impede o Python de imprimir uma nova linha
aps cada n.
Ns invocamos este mtodo como invocamos o
imprimeLista:
>>> 1mpJ1me0eTJasPaJaFJeh1e{ho1)
3 2 1
O resultado a lista de trs para frente.
Voc pode se perguntar por qu imprimeLista e
imprimeDeTrasParaFrente so funes e no mtodos da
classe No. A razo que ns queremos usar None para
representa a lista vazia e no legal invocar um mtodo sobre
None. Esta limitao torna complicado escrever cdigo de
manipulao de lista em estilo orientado a objeto limpo.
Podemos provar que imprimeDeTrasParaFrente
sempre termina? Em outras palavras, ir ela sempre atingir o
caso base? De fato, a resposta no. Algumas listas faro este
mtodo falhar.
17.5 Listas Infinitas
No h nada que impea um n de referenciar de volta um n
anterior na lista, incluindo ele mesmo. Por exemplo, esta
figura mostra uma lista com dois ns, um dos quais refere-se a
si mesmo:
Se ns invocarmos imprimeLista nesta lista, ele
ficar em lao para sempre. Se ns invocarmos
imprimeDeTrasParaFrente, ele recorrer infinitamente. Este
tipo de comportamento torna as listas infinitas difceis de se
lidar.
A despeito disto, elas ocasionalmente so teis.
Por exemplo, podemos representar um nmero como uma lista
de dgitos e usar uma lista infinita para representar uma frao
repetente.
Mesmo assim, problemtico que no
possamos provar que imprimeLista e
imprimeDeTrasParaFrente terminem. O melhor que podemos
fazer a afirmao hipottica, "Se a lista no contm laos,
ento este mtodo terminar." Este tipo de hiptese chamado
uma pr-condio. Ele impe uma limitao sobre um dos
parmetros e descreve o comportamento do mtodo se a
limitao satisfeita. Voc ver mais exemplos em breve.
17.6 O Teorema da Ambigidade Fundamental
Uma parte de imprimeDeTrasParaFrente pode ter gerado
surpresa:
cabeca = 1s1a
Jabo = 1s1a.pJox1mo
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:
de1 1mpJ1me0eTJasPaJaFJeh1e{1s1a).
11 1s1a == hohe . Je1uJh
1mpJ1me0eTJasPaJaFJeh1e{1s1a.pJox1mo)
pJ1h1 1s1a,
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.
Captulo 17: Listas encadeadas #81
Como pensar como um cientista da Computao usando Python
O teorema da ambigidade fundamental
descreve a ambigidade que inerente referncia a um n:
Uma varivel que refere a um n pode tratar o
n como um objeto nico ou como o primeiro em uma lista
de ns.
17.7 Modificando Listas
Existem duas maneiras de se modificar uma lista ligada.
Obviamente, podemos modificar a carga dos ns, mas as
operaes mais interessantes so aquelas que adicionam,
removem ou reordenam os ns.
Como um exemplo, vamos escrever um mtodo
que remove o segundo n na lista e retorna uma referncia ao
n removido:
de1 JemoveSeguhdo{1s1a).
11 1s1a == hohe . Je1uJh
pJ1me1Jo = 1s1a
seguhdo = 1s1a.pJox1mo
# 1az o pJ1me1Jo ho Je1eJ1J ao 1eJce1Jo
pJ1me1Jo.pJox1mo = seguhdo.pJox1mo
# sepaJa o seguhdo ho do Jes1o da 1s1a
seguhdo.pJox1mo = hohe
Je1uJh seguhdo
Novamente, estamos usando variveis
temporrias para tornar o cdigo mais fcil de ser lido. Aqui
est como usar este mtodo:
>>> 1mpJ1meL1s1a{ho1)
1 2 3
>>> Jemov1do = JemoveSeguhdo{ho1)
>>> 1mpJ1meL1s1a{Jemov1do)
2
>>> 1mpJ1meL1s1a{ho1)
1 3
Este diagrama de estado mostra o efeito da
operao:
O que acontece se voc invocar este mtodo e
passar uma lista com somente um elemento (um singleton)? O
que acontece se voc passar a lista vazia como um argumento?
Existe uma pr-condio para este mtodo? Se houver, corrija
o mtodo para tratar uma violao da pr-condio de modo
razovel.
17.8 Envoltrios e Ajudadores
Freqentemente til dividir uma operao de lista em dois
mtodos. Por exemplo, para imprimir uma lista de trs para
frente no formato convencional de lista [3, 2, 1], podemos
usar o mtodo imprimeDeTrasParaFrente para imprimir 3, 2,
mas queremos um metodo separado para imprimir os
braquetes e o primeiro n. Vamos cham-lo de
imprimeDeTrasParaFrenteLegal:
de1 1mpJ1me0eTJasPaJaFJeh1eLega{1s1a).
pJ1h1 "|",
11 1s1a != hohe .
cabeca = 1s1a
Jabo = 1s1a.pJox1mo
1mpJ1me0eTJasPaJaFJeh1e{Jabo)
pJ1h1 cabeca,
pJ1h1 "]",
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.
17.9 A Classe ListaLigada
Existem alguns problemas sutis com o modo que
implementamos listas. Em um inverso de causa e efeito,
proporemos uma implementao alternativa primeiro e ento
explicaremos qual problema ela resolve.
Primeiro, criaremos uma nova classe chamada
ListaLigada. Seus atributos so um inteiro que contm o
comprimento da lista e uma referncia para o primeiro n.
Objetos do tipo ListaLigada servem como cabos (handles)
para se manipular listas de objetos No:
cass L1s1aL1gada.
de1 __1h11__{se1).
se1.compJ1meh1o = 0
se1.cabeca = hohe
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:
cass L1s1aL1gada.
...
de1 1mpJ1me0eTJasPaJaFJeh1e{se1).
pJ1h1 "|",
11 se1.cabeca != hohe .
se1.cabeca.1mpJ1me0eTJasPaJaFJeh1e{)
pJ1h1 "]",
cass ho.
...
de1 1mpJ1me0eTJasPaJaFJeh1e{se1).
11 se1.pJox1mo != hohe.
Jabo = se1.pJox1mo
Jabo.1mpJ1me0eTJasPaJaFJeh1e{)
pJ1h1 se1.caJga,
Apenas para tornar as coisas confusas,
mudamos o nome de imprimeDeTrasParaFrenteLegal. Agora
existem dois mtodos chamados imprimeDeTrasParaFrente:
um na classe No (o ajudador); e um na classe ListaLigada``(o
envoltrio). Quano o envoltrio invoca
``self.cabeca.imprimeDeTrasParaFrente, ele est invocando o
ajudador, porque self.cabeca um objeto No.
Outro benefcio da classe ListaLigada que ela
torna mais fcil adicionar e remover o primeiro elemento de
uma lista. Por exemplo, adicionaPrimeiro um mtodo para
ListaLigada; ele toma um item de carga como argumento e o
coloca no incio da lista:
cass L1s1aL1gada.
...
Captulo 17: Listas encadeadas #82
Como pensar como um cientista da Computao usando Python
de1 ad1c1ohaPJ1me1Jo{se1, caJga).
ho = ho{caJga)
ho.pJox1mo = se1.cabeca
se1.cabeca = ho
se1.compJ1meh1o = se1.compJ1meh1o + 1
Como de costume, voc deve conferir cdigos
como este para ver se eles tratam os casos especiais. Por
exemplo, o que acontece se a lista est inicialmente vazia?
17.10 Invariantes
Algumas listas so "bem formadas"; outras no o so. Por
exemplo, se uma lista contm um lao, ela far muitos de
nossos mtodos falharem, de modo que podemos querer
requerer que listas no contenham laos. Outro requerimento
que o valor de comprimento no objeto ListaLigada seja igual
ao nmero real de ns da lista.
Requerimentos como estes so chamados de
invariantes porque, idealmente, eles deveriam ser verdade para
cada objeto o tempo todo. Especificar invariantes para objetos
um prtica de programao til porque torna mais fcil
provar a correo do cdigo, verificar a integridade das
estruturas de dados e detectar erros.
Uma coisa que algumas vezes confusa acerca
de invariantes que existem momentos em que eles so
violados. Por exemplo, no meio de adicionaPrimeiro, aps
termos adicionado o n mas antes de termos incrementado
comprimento, o invariante violado. Este tipo de violao
aceitvel; de fato, freqentemente impossvel modificar um
objeto sem violar um invariante por, no mnimo, um pequeno
instante. Normalmente, requeremos que cada mtodo que
viola um invariante deve restaurar este invariante.
Se h qualquer aumento significativo de cdigo
no qual o invariante violado, importante tornar isto claro
nos comentrios, de modo que nenhuma operao seja feita
que dependa daquele invariante.
17.11 Glossrio
referncia embutida Uma referncia
(embedded
reference)
armazenada/associada em/a um
atributo de um objeto.
lista ligada (linked
list)
Uma estrutura de dados que
implementa uma coleo usando
uma sequncia de ns ligados.
n ou nodo (node) Um elemento de uma lista,
usualmente implementado como um
objeto que contm uma referncia
para outro objeto do mesmo tipo.
carga (cargo) Um item de dado contido em um n.
ligao (link) Uma referncia embutida usada para
ligar/conectar um objeto a outro.
pr-condio
(precondition)
Uma assero que precisa/deve ser
verdadeira para que um mtodo
trabalhe corretamante.
teorema da
ambigidade
fundamental
(fundamental
ambiguity theorem)
Uma referncia para um n de uma
lista pode ser tratada como um
objeto nico ou como o primeiro em
uma lista de ns.
singleton (singleton) Uma lista ligada com somente um
n.
envoltrio (wrapper) Um mtodo que atua como um
intermedirio (middleman) entre um
chamador e um mtodo ajudador
(helper), freqentemente tornando a
invocao do mtodo mais fcil ou
menos propensa a erros.
ajudador (helper) Um mtodo que no invocado
diretamente pelo chamador (caller)
mas usado por outro mtodo para
realizar parte de uma operao.
invariante
(invariant)
Uma assero que deveria ser
verdadeira sempre para um objeto
(exceto talvez enquanto o objeto
estiver sendo modificado).
Captulo 17: Listas encadeadas #83
Como pensar como um cientista da Computao usando Python
Captulo 18: Pilhas Captulo 18: Pilhas
18.1 Tipos abstratos de dados
Os tipos de dados que voc viu at agora so todos concretos,
no sentido que ns especificamos completamente como eles
so implementados. Por exemplo, a classe Card(XXX ver
como foi traduzido) representa uma carta utilizando dois
inteiros. Como discutimos no momento, esta no a nica
maneira de representar uma carta; existem muitas
implementaes alternativas.
Um tipo abstrato de dado, ou TAD, especifica
um conjunto de operaes (ou mtodos) e a semntica das
operaes (o que elas fazem), mas no especifica a
implementao das operaes. Isto o que o faz abstrato.
Por que isto til?
e Simplifica a tarefa dde especificar um algoritmo se
voc pode XXXdenotar(denote) as operaes que
voc precisa sem ter que pensar, ao mesmo tempo,
como as operaes so executadas.
e Uma vez que existem geralmente muitas maneiras de
implementar um TAD, pode ser til escrever um
algritmo que pode ser usado com qualquer das
possveis implementaes.
e TADs bastante conhecidos, como o TAD Pilha deste
captulo, j esto implementados em bibliotecas
padro, ento eles podem ser escritos uma vez e
usado por muitos programadores.
e As operaes em TADs provm uma linguagem de
alto nvel comum para especificar e falar sobre
algoritmos.
Quando falamos sobre TADs, geralmente
distinguimos o cdigo que usa o TAD, chamado cliente, do
cdigo que implementa o TAD, chamado cdigo fornecedor.
18.2 O TAD Pilha
Neste captulo, iremos olhar um TAD comum, a pilha. Uma
pilha uma coleo, ou seja, uma estrutura de dados que
contei mltiplos elementos. Outras colees que vimos
incluem dicionrios e listas.
Um TAd definido pelo conjunto de operaes
que podem ser executadas nele, que chamado interface. A
interface para uma pilha consiste nestas operaes:
__init__ : Inicializa uma nova pilha vazia.
push : Adiciona um novo item na pilha
pop : Remove um tem da pilha e o retorna, O
tem que retornadao sempre o ltimo adicionado.
isEmpty : Verifica se a pilha est vazia.
Uma s vezes chamada uma estrutura de
dados "last in, first out" ou LIFO, porque o ltimo tem
adicionad o primeiro a ser removido.
18.3 Implementando pilhas com listas de Python
As operaes de lista que Python oferecem so similares s
operaes que definem uma pilha. A interface no
exatamente o que se supe ser, mas podemos escrever um
cdigo para traduzir do TAD Pilha para as operaes nativas.
Este cdigo chamado uma implementao do
TAD Pilha. Geralmente, uma implementaa um conjunto
de mtodos que satisfazem os requisitos sintticos e
semnticos de uma interface.
Aqui est uma implementao do TAD Pilha
que usa uma lista do Python:
cass S1ack .
de1 __1h11__{se1) .
se1.11ems = |]
de1 push{se1, 11em) .
se1.11ems.apehd{11em)
de1 pop{se1) .
Je1uJh se1.11ems.pop{)
de1 1sEmp1y{se1) .
Je1uJh {se1.11ems == |])
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.
18.4 Empilhando e desempilhando
Uma pilha uma estrutura de dados genrica, o que
significa que podemos adicionar qualquer tipo de tem a ela. O
exemplo a seguir empilha dois inteiros e uma XXXstring na
pilha:
>>> s = S1ack{)
>>> s.push{54)
>>> s.push{45)
>>> s.push{"+")
Podemos usar isEmpty e pop para remover e
imprimir todos os tens da pilha:
Captulo 18: Pilhas #84
Como pensar como um cientista da Computao usando Python
wh1e ho1 s.1sEmp1y{) .
pJ11h1 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.
18.5 Usando uma pilha para avaliar expresses ps-
fixas
Em muitas linguagens de programao, expresses
matemticas so executadas com o poerador entre os roid
operandos, como em 1 + 2. Este formato chamado notao
infixa. Uma alternativa usada por algumas calculadoras
chamada notao ps-fixa. Em notao ps-fixa, o operador
segue os operandos, como em 1 2 +.
A razo pela qual a notao ps-fixa til
algumas vezes que existe uma maneira natural de avaliar
uma expresso ps-fixa usando uma pilha:
e comeando no incio da expresso, peque um termo
(operador ou operando) de cada vez.
e Se o termo um operando, empilhe-o
e Se o termo um operador, desempilhe dois
operandos, execute a operao neles, e empilhe o
resultado.
e Quando chegar ao fim da expresso, deve existir
exatamente um operando sobrando na pilha. Este
operando o resultado.
e Como um exerccio, aplique este algoritmo
expresso 1 2 + 3 * .
Este exemplo demonstra uma das vantagens da
notao ps-fixa - no necessrio usar parnteses para
controlar a ordem das operaes. Para ter o mesmo resultado
em notao infixa, deveramos escrever (1 + 2) * 3.
Como um exerccio, escreva a expresso ps-
fixa que equivalente a 1 + 2 * 3.
18.6 Anlise sinttica
Para implementar o algoritmo anterior, necessitamos estar
prontos para percorrer uma string e quebr-la em operandos e
operadores. Este process um exemplo de parsing, e o
resultado - os pedaos da string - so chamados tokens. Voc
deve lembrar estas palavras do captulo 1.
Python fornece um mtodo split nos mdulos
string e re (expresses regulares). A funo string.split separa
uma string numa lista usando um nico caracter como
delimitador. Por exemplo:
>>> 1mpoJ1 s1J1hg
>>> s1J1hg.sp11 {"how 1s 1he 11me", " ")
|`how`, `1s`, `1he`, `11me`]
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.
>>> 1mpoJ1 Je
>>> Je.sp11 {"|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.
18.7 Avaliando em ps-fixo.
Para avaliar uma expresso ps-fixa, usaremos o parser da
seo anterior e o algoritmo da seo anterior a ela. Para
manter as coisas simples, comearemos com um avaliador que
implementa somente os operadores + e .
de1 evaPos111x {expJ) .
1mpoJ1 Je
1okehL1s1 = Je.sp11 {"{|0-9])", expJ)
s1ack = S1ack{)
1oJ 1okeh 1h 1okehL1s1
11 1okeh == `` oJ 1okeh = ` ` .
coh11hue
11 1okeh == `+` .
sum = s1ack.pop{) + s1ack.pop{)
s1ack.push{sum)
11 1okeh == `*` .
pJoduc1 = s1ack.pop{) * s1ack.pop{)
s1ack.push{pJoduc1)
ese.
s1ack.push{1h1{1okeh))
Je1uJh s1ack.pop{)
A primeira condio cuida de espaos e strings
vazias. As duas prximas condies manipulam os
operadores. Ns assumimos, agora que qualquer coisa um
operador. claro, seria melhor chegar por entrada errnea e
enviar uma mensagem de erro, mas faremos isto depois.
Vamos test-lo avaliando a forma ps-fixa de
(56 + 47) * 2
>>> pJ1h1 evaPos111x{"56 47 + 2 *")
206
18.8 Clientes de fornecedores.
Um dos objetivos de um TAD separar os interesses do
fornecedor, quem escreve o cdigo que implementa o TAD, e
o cliente, que usa o TAD. O fornecedor tem que se preocupar
apenas se a implementao est correta - de acordo com a
especificao do TAD - e no como ele ser usado.
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
Captulo 18: Pilhas #85
Como pensar como um cientista da Computao usando Python
deve fazer algum esfor para manter a trilha do papel que
est fazendo a cada momento.
18.9 Glossrio
tipo abstrato
de dados
(TAD)
(abstract data
type(ADT)):
Um tipo de dado(geralmente uma coleo
de objetos) que definidopor um conjunto
de operaes, que podem ser implementadas
de vrias maneiras.
interface
(interface):
o conjunto de operaes que definem um
TDA.
implementa
o
(implementati
on):
Cdigo que satisfaz(preenche?) os requisitos
sintticos e semnticos de uma interface.
cliente
(client):
Um programa (ou o programador que o
escreveu) que faz utilizao de um TDA.
fornecedor
(provider):
Cdigo (ou o programador que o escreveu)
que implementa um TDA.
revestimento
(veneer):
Definio de classe que implementa um
TDA com definies de mtodos que so
chamadas a outros mtodos, s vezes com
pequenas modificaes. A lmina faz um
trabalho insignificante, mas melhora ou
padroniza a interface dada ao cliente.
estrutura de
dados
genrica
(generic data
structure):
Tipo de estrutura de dados que contem data
de um tipo qualquer(tipo genrico).
infixa (infix): Notao matemtica em que os operadores
se situam entre os operandos.
ps-fixa
(postfix):
Notao matemtica em que os operadores
se situam aps os operandos.
parse (parse): Ler um conjunto de caracteres(string de
caracteres) ou tokens(smbolos atmicos) e
analisar sua estrutura gramatical.
token (token): Conjunto de caracteres que so tratados
como uma unidade atmica para fins de
anlise gramatical, como as palavras na
linguagem natural.
delimitador
(delimiter):
Um caracter que utilizado para separar os
smbolos atmicos(tokens), como a
pontuao na linguagem natural.
Captulo 18: Pilhas #86
Como pensar como um cientista da Computao usando Python
Captulo 19: Filas Captulo 19: Filas
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.
19.1 Um TDA Fila
O TDA Fila definido pelas seguintes operaes:
__init__ Inicializar uma nova fila vazia.
insert Adicionar um novo item fila.
remove Remover e retornar um item da fila. O item
retornado o que foi adicionado primeiro.
isEmpty Checar se a fila est vazia.
19.2 Fila encadeada
A primeira implementao que vamos ver de um TDA Fila
chama-se fila encadeada porque feita de objetos Ns
encadeados. A definio da classe a seguinte:
cass 0ueue.
de1 __1h11__{se1).
se1.ehg1h = 0
se1.head = hohe
de1 1sEmp1y{se1).
Je1uJh {se1.ehg1h == 0)
de1 1hseJ1{se1, caJgo).
hode = hode{caJgo)
hode.hex1 = hohe
11 se1.head == hohe.
# 11 1s1 1s emp1y 1he hew hode goes 11Js1
se1.head = hode
ese.
# 11hd 1he as1 hode 1h 1he 1s1
as1 = se1.head
wh1e as1.hex1. as1 = as1.hex1
# appehd 1he hew hode
as1.hex1 = hode
se1.ehg1h = se1.ehg1h + 1
de1 Jemove{se1).
caJgo = se1.head.caJgo
se1.head = se1.head.hex1
se1.ehg1h = se1.ehg1h - 1
Je1uJh caJgo
Os mtodos isEmpty e remove so idnticos aos
mtodos isEmpty e removeFirst de LinkedList. O mtodo
insert novo e um pouco mais complicado.
Queremos inserir novos itens no fim da lista. Se
a fila estiver vazia, basta fazer head apontar ao novo n. Se
no, percorremos a lista at o ltimo n e l penduramos o
novo n. possvel identificar o ltimo n porque o seu
atributo next None.
Existem duas invariantes para um objeto Fila
bem formado: o atributo length deve ser o nmero de ns na
fila, e o ltimo n deve ter seu atributo next igual a None.
Estude o mtodo at ficar convencido de que ele preserva
ambas invariantes.
19.3 Caractersticas de performance
Quando invocamos um mtodo, normalmente no estamos
preocupados com os detalhes da sua implementao. Porm,
h um certo "detalhe" que pode ser bom conhecer: as
caractersticas de performance do mtodo. Quanto tempo leva,
e como o tempo de execuo muda medida em que aumenta
o nmero de itens da coleo?
Primeiro, olhe para remove. No h laos ou
chamadas de funo aqui, o que sugere que o tempo de
execuo desse mtodo sempre o mesmo, toda vez. Um
mtodo assim chamado de operao de tempo constante.
Na verdade, o mtodo pode ser ligeiramente mais rpido
quando a lista est vazia, uma vez que ele pula o corpo da
condicional, mas essa diferena no significativa. XXX: o
condicional s aparece na re-implementao do mtodo na
classe ImprovedQueue, p.200; essa inconsistncia pode ser
conferida tambm nas pginas 198-199 do livro original (PDF
e impresso).
A performance de insert muito diferente. No
caso geral, temos de percorrer a lista para achar o ltimo
elemento.
Este percurso leva um tempo proporcional
extenso da lista. Uma vez que o tempo de execuo uma
funo linear da extenso, dizemos que este mtodo opera em
tempo linear. Isso bem ruim, se comparado com o tempo
constante.
19.4 Fila encadeada aprimorada
Queremos uma implementao do TDA Fila que possa
Captulo 19: Filas #87
Como pensar como um cientista da Computao usando Python
realizar todas as operaes em tempo constante. Uma maneira
de fazer isso modificar a classe Fila, de modo que ela
mantenha a referncia tanto ao primeiro quanto ao ltimo n,
como mostra a figura:
A implementao de ImprovedQueue tem essa
cara:
cass TmpJoved0ueue.
de1 __1h11__{se1).
se1.ehg1h = 0
se1.head = hohe
se1.as1 = hohe
de1 1sEmp1y{se1).
Je1uJh {se1.ehg1h == 0)
At agora, a nica mudana o atributo last. Ele
usado nos mtodos insert e remove:
cass TmpJoved0ueue.
# ...
de1 1hseJ1{se1, caJgo).
hode = hode{caJgo)
hode.hex1 = hohe
11 se1.ehg1h == 0.
#11 1s1 1s emp1y, 1he hew hode 1s head & as1
se1.head = se1.as1 = hode
ese.
# 11hd 1he as1 hode
as1 = se1.as1
# appehd 1he hew hode
as1.hex1 = hode
se1.as1 = hode
se1.ehg1h = se1.ehg1h + 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:
cass TmpJoved0ueue.
#...
de1 Jemove{se1).
caJgo = se1.head.caJgo
se1.head = se1.head.hex1
se1.ehg1h = se1.ehg1h - 1
11 se1.ehg1h == 0.
se1.as1 = hohe
Je1uJh caJgo
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.
19.5 Fila por prioridade
O TDA Fila por Prioridade tem a mesma interface que o TDA
Fila, mas semntica diferente. Mais uma vez, a interface a
seguinte:
__init__ Inicializar uma nova fila vazia.
insert Adicionar um novo item fila.
remove Remover e retornar um item da fila. O item
retornado aquele que tiver maior prioridade.
isEmpty Checar se a fila est vazia.
A diferena semntica que o item removido da
fila no necessariamente o que foi includo primeiro e, sim,
o que tem maior prioridade. Que prioridades so essas e como
elas se comparam umas com as outras no especificado pela
implementao Fila por Prioridade. Isso depende de quais
itens esto na fila.
Por exemplo, se os itens da fila tiverem nome,
podemos escolh-los por ordem alfabtica. Se for a pontuao
de um jogo de boliche, podemos ir da maior para a menor,
mas se for pontuao de golfe, teramos que ir da menor para
a maior. Se possvel comparar os itens da fila, possvel
achar e remover o que tem maior prioridade. Essa
implementao da Fila por Prioridade tem como atributo uma
lista Python chamada items, que contm os itens da fila.
cass PJ1oJ11y0ueue.
de1 __1h11__{se1).
se1.11ems = |]
de1 1sEmp1y{se1).
Je1uJh se1.11ems == |]
de1 1hseJ1{se1, 11em).
se1.11ems.appehd{11em)
O mtodo de inicializao, isEmpty, e insert so
apenas uma fachada para operaes bsicas de lista. O nico
mtodo interessante remove:
cass PJ1oJ11y0ueue.
# ...
de1 Jemove{se1).
max1 = 0
1oJ 1 1h Jahge{1,eh{se1.11ems)).
11 se1.11ems|1] > se1.11ems|max1].
max1 = 1
11em = se1.11ems|max1]
se1.11ems|max1.max1+1] = |]
Je1uJh 11em
No incio de cada iterao, maxi armazena o
ndice do maior item (a prioridade mais alta de todas) que
vimos at agora. A cada volta do lao, o programa compara o
i-simo item ao campeo. Se o novo item for maior, maxi
recebe o valor de i.
Quando o comando for se completa, maxi o
ndice do maior item. Esse item removido da lista e
retornado.
Vamos testar a implementao:
>>> q = PJ1oJ11y0ueue{)
>>> q.1hseJ1{11)
>>> q.1hseJ1{12)
>>> q.1hseJ1{14)
>>> q.1hseJ1{13)
>>> wh1e ho1 q.1sEmp1y{). pJ1h1 q.Jemove{)
14
Captulo 19: Filas #88
Como pensar como um cientista da Computao usando Python
13
12
11
Se a fila contm nmeros ou strings simples,
eles so removidas em ordem numrica decrescente ou
alfabtica invertida (de Z at A). Pyhton consegue achar o
maior inteiro ou string porque consegue compar-los usando
os operadores de comparao nativos.
Se a fila contm objetos de outro tipo, os
objetos tm que prover um mtodo __cmp__. Quando remove
usa o operador > para comparar dois itens, o mtodo __cmp__
de um dos itens invocado, recebendo o segundo item como
argumento. Desde que o mtodo __cmp__ funcione de forma
consistente, a Fila por Prioridade vai funcionar.
19.6 A classe Golfer
Como exemplo de um objeto com uma definio no-usual de
prioridade, vamos implementar uma classe chamada Golfer
(golfista), que mantm registro dos nomes e da pontuao de
golfistas. Como sempre, comeamos definindo __init__ e
__str__:
cass Co1eJ.
de1 __1h11__{se1, hame, scoJe).
se1.hame = hame
se1.scoJe= scoJe
de1 __s1J__{se1).
Je1uJh "-16s. d" {se1.hame, se1.scoJe)
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.
cass Co1eJ.
#...
de1 __cmp__{se1, o1heJ).
11 se1.scoJe < o1heJ.scoJe. Je1uJh 1 # ess
1s moJe
11 se1.scoJe > o1heJ.scoJe. Je1uJh -1
Je1uJh 0
Agora estamos prontos para testar a fila por
prioridade com a classe Golfer:
>>> 11geJ = Co1eJ{"T1geJ Woods", 61)
>>> ph1 = Co1eJ{"Ph1 h1ckesoh", 72)
>>> ha = Co1eJ{"ha Su11oh", 69)
>>>
>>> pq = PJ1oJ11y0ueue{)
>>> pq.1hseJ1{11geJ)
>>> pq.1hseJ1{ph1)
>>> pq.1hseJ1{ha)
>>> wh1e ho1 pq.1sEmp1y{). pJ1h1 pq.Jemove{)
T1geJ Woods . 61
ha Su11oh . 69
Ph1 h1ckesoh . 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.
19.7 Glossrio
fila (queue) Conjunto de objetos ordenados esperando
algum tipo de servio.
Fila (Queue) TAD (Tipo Abstrato de Dado) que realiza
operaes comuns de acontecerem em
uma fila.
poltica de
enfileiramento
(queueing
policy)
As regras que determinam qual membro
de uma fila o prximo a ser removido.
FIFO "First In, First Out," (primeiro a entrar,
primeiro a sair) poltica de enfileiramento
em que o primeiro membro a chegar o
primeiro a ser removido.
fila por
prioridade
(priority queue)
Poltica de enfileiramento em que cada
membro tem uma prioridade, determinada
por fatores externos. O membro com a
maior prioridade o primeiro a ser
removido.
Fila por
Prioridade
(Priority
Queue)
TAD que define as operaes comuns de
acontecerem em uma fila por prioridade.
fila encadeada
(linked queue)
Implementao de uma fila usando uma
lista encadeada.
tempo constante
(constant time)
Operao cujo tempo de execuo no
depende do tamanho da estrutura de
dados.
tempo linear
(linear time)
Operao cujo tempo de execuo uma
funo linear do tamanho da estrutura de
dados.
Captulo 19: Filas #89
Como pensar como um cientista da Computao usando Python
Captulo 20: rvores Captulo 20: rvores
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:
Para evitar a sobrecarga da figura, ns
frequentemente omitimos os Nones.
O topo da rvore (a clula qual o apontador
tree se refere) chamada de raiz. Seguindo a metfora das
rvores, as outras clulas so chamadas de galhos e as clulas
nas pontas contendo as referncias vazia so chamadas de
folhas. Pode parecer estranho que desenhamos a figura com a
raiz em cima e as folhas em baixo, mas isto nem ser a coisa
mais estranha.
Para piorar as coisas, cientistas da computao
misturam outra metfora alm da metfora biolgica - a rvore
genealgica. Uma clula superior pode ser chamada de pai e
as clulas a que ela se refere so chamadas de seus filhos.
Clulas com o mesmo pai so chamadas de irmos.
Finalmente, existe tambm o vocabulrio
geomtrico para falar de rvores. J mencionamos esquerda e
direita, mas existem tambm as direes "para cima" (na
direo da raiz) e "para baixo" (na direo dos filhos/folhas).
Ainda nesta terminologia, todas as clulas situadas mesma
distncia da raiz constituem um nvel da rvore.
Provavelmente no precisamos de trs
metforas para falar de rvores, mas a elas esto.
Como listas ligadas, rvores so estruturas de
dados recursivas j que elas so definidas recursivamente:
Uma rvore
e a rvore vazia, representada por None, ou
e uma clula que contm uma referncia a um objeto (a
carga da clula) e duas referncias a rvores.
20.1 Construindo rvores
O processo de montar uma rvore similar ao processo de
montar uma lista ligada. cada invocao do construtor cria
uma clula.
cass TJee .
de1 __1h11__{se1, caJgo, e11=hohe, J1gh1=hohe) .
se1.caJgo = caJgo
se1.e11 = e11
se1.J1gh1 = J1gh1
de1 __s1J__{se1) .
Je1uJh s1J{se1.caJgo)
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:
e11 = TJee{2)
J1gh1 = TJee{3)
Em seguida crie a clula pai e ligue ela a seus
filhos:
1Jee = TJee{1, e11, J1gh1),
Podemos escrever este cdigo mais
concisamente encaixando as invocaes do construtor:
>>> 1Jee = TJee{1, TJee{2), TJee{3))
De qualquer forma, o resultado a rvore que
apareceu no incio do captulo.
20.2 Percorrendo rvores
Cada vez que Voc v uma nova estrutura de dados, sua
primeira pergunta deveria ser "Como eu percorro esta
estrutura?" A forma mais natural de percorrer uma rvore
fazer o percurso recursivamente. Por exemplo, se a rvore
contm inteiros na carga, a funo abaixo retorna a soma das
cargas:
de1 1o1a{1Jee) .
11 1Jee == hohe . Je1uJh 0
Je1uJh 1o1a{1Jee.e11) + 1o1a{1Jee.J1gh1) +
1Jee.caJgo
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.
20.3 rvores de expresses
Uma rvore uma forma natural para representar a estrutura
de uma expresso. Ao contrrio de outras notaes, a rvore
pode representar a computao de forma no ambgua. Por
exemplo, a expresso infixa 1 + 2 * 3 ambgua, a menos que
Captulo 20: rvores #90
Como pensar como um cientista da Computao usando Python
saibamos que a multiplicao feita antes da adio.
A rvore de expresso seguinte representa a
mesma computao:
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:
>>> 1Jee = TJee{`+`, TJee{1), TJee{`*`, TJee{2),
TJee{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.
20.4 Percurso de rvores
Podemos percorrer uma rvore de expresso e imprimir o seu
contedo como segue:
de1 pJ1h1TJee{1Jee) .
11 1Jee == hohe . Je1uJh
pJ1h1 1Jee.caJgo,
pJ1h1TJee{1Jee.e11)
pJ1h1TJee{1Jee.J1gh1)
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 :
>>> 1Jee = TJee{`+`, TJee{1), TJee{`*`, TJee{2),
TJee{3)))
>>> pJ1h1TJee{1Jee)
+ 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:
de1 pJ1h1TJeePos1oJdeJ{1Jee) .
11 1Jee == hohe . Je1uJh
pJ1h1TJeePos1oJdeJ{1Jee.e11)
pJ1h1TJeePos1oJdeJ{1Jee.J1gh1)
pJ1h1 1Jee.caJgo,
O resultado, 1 2 3 * +, est na notao psfixa!
Esta ordem de percurso chamada de psordem.
Finalmente, para percorrer uma rvore em
inordem, Voc imprime a subrvore esquerda, depois a raiz e
depois a subrvore direita:
de1 pJ1h1TJeeThoJdeJ{1Jee) .
11 1Jee == hohe . Je1uJh
pJ1h1TJeeThoJdeJ{1Jee.e11)
pJ1h1 1Jee.caJgo,
pJ1h1TJeeThoJdeJ{1Jee.J1gh1)
O resultado 1 + 2 * 3, que a expresso na
notao infixa.
Para sermos justos, devemos lembrar que
acabamos de omitir uma complicao importante. algumas
vezes quando escrevemos expresses na notao infixa
devemos usar parntesis para prescrever a ordem das
operaes. Ou seja, um percurso em inordem no suficiente
para gerar a expresso infixa.
Ainda assim, com alguns aperfeioamentos, a
rvore de expresso e os trs modos recursivos de percurso
resultam em algoritmos para transformar expresses de uma
notao para outra.
Como um exerccio, modifique
`printTreeInorder` de modo que ele coloque parntesis em
volta de cada operador e par de operandos. A sada correta
e no ambgua? Os parntesis so sempre necessrios?
Se percorrermos uma rvore em inordem e
acompanharmos em qual nvel na rvore estamos, podemos
gerar uma representao grfica da rvore:
de1 pJ1h1TJeeThdeh1ed{1Jee, eve=0) .
11 1Jee == hohe . Je1uJh
pJ1h1TJeeThdeh1ed{1Jee.J1gh1, eve+1)
pJ1h1 ` `*eve + s1J{1Jee.caJgo)
pJ1h1TJeeThdeh1ed{1Jee.e11, eve+1)
O parmetro level registra aonde estamos na
rvore. Por 'default', o nvel inicialmente zero. A cada
chamada recursiva repassamos level+1 porque o nvel do filho
sempre um a mais do que o nvel do pai. Cada item
indentado dois espaos por nvel. Para o nosso exemplo
obtemos:
>>> pJ1h1TJeeThdeh1ed{1Jee)
3
*
2
+
1
Se Voc deitar a sada acima Voc enxerga uma
verso simplificada da figura original.
20.5 Construindo uma rvore de expresso
Nesta seo analisamos expresses infixas e construmos as
rvores de express correspondentes. Por exemplo, para a
expresso (3+7)*9 resultar a seguinte rvore:
Captulo 20: rvores #91
Como pensar como um cientista da Computao usando Python
Note que simplificamos o diagrama omitindo os
nomes dos campos.
O analisador que escreveremos aceitar
expresses que incluam nmeros, parntesis e as operaes +
e *. Vamos supor que a cadeia de entrada j foi tokenizada
numa lista do Python. A lista de tokens para a expresso
(3+7)*9 :
|`{`, 3, `+`, 7, `)`, `*`, 9, `ehd`]
O token final end prtico para prevenir que o
analisador tente buscar mais dados aps o trmino da lista.
A ttulo de um exerccio, escreva uma funo
que recebe uma expresso na forma de uma cadeia e
devolve a lista de tokens.
A primeira funo que escreveremos getToken
que recebe como parmetros uma lista de tokens e um token
esperado. Ela compara o token esperado com o o primeiro
token da lista: se eles batem a funo remove o token da lista e
devolve um valor verdadeiro, caso contrrio a funo devolve
um valor falso:
de1 ge1Tokeh{1okehL1s1, expec1ed) .
11 1okehL1s1|0] == expec1ed .
1okehL1s1|0.1] = |] # Jemove 1he 1okeh
Je1uJh 1
ese .
Je1uJh 0
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.
de1 ge1humbeJ{1okehL1s1) .
x = 1okehL1s1|0]
11 1ype{x) != 1ype{0) . Je1uJh hohe
de 1okehL1s1|0]
Je1uJh TJee{x, hohe, hohe)
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:
>>> 1okehL1s1 = |9, 11, `ehd`]
>>> x = ge1humbeJ{1okehL1s1)
>>> pJ1h1TJeePos1oJdeJ{x)
9
>>> pJ1h1 1okehL1s1
|11, `ehd`]
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.
de1 ge1PJoduc1{1okehL1s1) .
a = ge1humbeJ{1okehL1s1)
11 ge1Tokeh{1okehL1s1, `*`) .
b = ge1humbeJ{1okehL1s1)
Je1uJh TJee{`*`, a, b)
ese .
Je1uJh 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:
>>> 1okehL1s1 = |9, `*`, 11, `ehd`]
>>> 1Jee = ge1PJoduc1{1okehL1s1)
>>> pJ1h1TJeePos1oJdeJ{1Jee)
9 11 *
>>> 1okehL1s1 = |9, `+`, 11, `ehd`]
>>> 1Jee = ge1PJoduc1{1okehL1s1)
>>> pJ1h1TJeePos1oJdeJ{1Jee)
9
O segundo exemplo sugere que ns
consideramos um operando unitrio como uma espcie de
produto. Esta definio de "produto" talvez no seja intuitiva,
mas ela ser til.
Agora tratamos produtos compostos, como 3 * 5
* 13. Encaramos esta expresso como um produto de
produtos, mais precisamente como 3 * (5 * 13). A rvore
resultante :
Com uma pequena alterao em getProduct,
podemos acomodar produtos arbitrariamente longos:
de1 ge1PJoduc1{1okehL1s1) .
a = ge1humbeJ{1okehL1s1)
11 ge1Tokeh{1okehL1s1, `*`) .
b = ge1PJoduc1{1okehL1s1) # 1h1s 1he chahged
Je1uJh TJee{`*`, a, b)
ese .
Captulo 20: rvores #92
Como pensar como um cientista da Computao usando Python
Je1uJh 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:
>>> 1okehL1s1 = |2, `*`, 3, `*`, 5 , `*`, 7, `ehd`]
>>> 1Jee = ge1PJoduc1{1okehL1s1)
>>> pJ1h1TJeePos1oJdeJ{1Jee)
2 3 5 7 * * *
A seguir adicionamos o tratamento de somas.
De novo, usamos uma definio de "soma" que ligeiramente
no intuitiva. Para ns, uma soma pode ser uma rvore com +
na raiz, que tem um produto como filho esquerdo e uma soma
como filho direito. Ou, uma soma pode ser simplesmente um
produto.
Se Voc est disposto a brincar com esta
definio, ela tem uma propriedade interessante: podemos
representar 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.
de1 ge1Sum{1okehL1s1) .
a = ge1PJoduc1{1okehL1s1)
11 ge1Tokeh{1okehL1s1, `+`) .
b = ge1Sum{1okehL1s1)
Je1uJh TJee{`+`, a, b)
ese .
Je1uJh a
Vamos testar o algoritmo com 9 * 11 + 5 * 7:
>>> 1okehL1s1 = |9, `*`, 11, `+`, 5, `*`, 7, `ehd`]
>>> 1Jee = ge1Sum{1okehL1s1)
>>> pJ1h1TJeePos1oJdeJ{1Jee)
9 11 * 5 7 * +
Quase terminamos, mas ainda temos que tratar
dos parntesis. Em qualquer lugar numa expresso onde
podemos ter um nmero, podemos tambm ter uma soma
inteira envolvida entre parntesis. Precisamos, apenas,
modificar getNumber para que ela possa tratar de
subexpresses:
de1 ge1humbeJ{1okehL1s1) .
11 ge1Tokeh{1okehL1s1, `{`) .
x = ge1Sum{1okehL1s1) # ge1 subexpJess1oh
ge1Tokeh{1okehL1s1, `)`) #ea1 cos1hg paJeh1hes1s
Je1uJh x
ese .
x = 1okehL1s1|0]
11 1ype{x) != 1ype{0) . Je1uJh hohe
1okehL1s1|0.1] = |] # Jemove 1he 1okeh
Je1uJh TJee{x, hohe, hohe) # Je1uJh a ea1
w11h 1he humbeJ
Testemos este cdigo com 9 * (11 + 5) * 7:
>>> 1okehL1s1 = |9, `*`, `{`, 11, `+`, 5, `)`, `*`,
7, `ehd`]
>>> 1Jee = ge1Sum{1okehL1s1)
>>> pJ1h1TJeePos1oJdeJ{1Jee)
9 11 5 + 7 * *
O analisador tratou os parntesis corretamente; a
adio feita antes da multiplicao.
Na verso final do programa, seria uma boa
idia dar a getNumber um nome mais descritivo do seu novo
papel.
20.6 Manipulando erros
Ao longo do analisador sinttico tnhamos suposto que as
expresses (de entrada) so bem formadas. Por exemplo,
quando atingimos o fim de uma subexpresso, supomos que o
prximo caractere um facha parntesis. Caso haja um erro e
o prximo caractere seja algo diferente, devemos tratar disto.
de1 ge1humbeJ{1okehL1s1) .
11 ge1Tokeh{1okehL1s1, `{`) .
x = ge1Sum{1okehL1s1)
11 ho1 ge1Tokeh{1okehL1s1, `)`).
Ja1se `BadExpJess1ohEJJoJ`,
`m1ss1hg paJeh1hes1s`
Je1uJh x
ese .
# 1he Jes1 o1 1he 1uhc11oh om111ed
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.
20.7 A rvore dos animais
Nesta seo, desenvolvemos um pequeno programa que usa
uma rvore para representar uma base de conhecimento.
O programa interage com o usurio para criar
uma rvore de perguntas e de nomes de animais. Segue uma
amostra da funcionalidade:
AJe you 1h1hk1hg o1 ah ah1ma? y
Ts 11 a b1Jd? h
Wha1 1s 1he ah1mas hame? dog
Wha1 ques11oh woud d1s11hgu1sh a dog 1Jom a b1Jd?
Cah 11 1y
T1 1he ah1ma weJe dog 1he ahsweJ woud be? h
AJe you 1h1hk1hg o1 ah ah1ma? y
Cah 11 1y? h
Ts 11 a dog? h
Wha1 1s 1he ah1mas hame? ca1
Wha1 ques11oh woud d1s11hgu1sh a ca1 1Jom a dog?
0oes 11 baJk
T1 1he ah1ma weJe ca1 1he ahsweJ woud be? h
AJe you 1h1hk1hg o1 ah ah1ma? y
Cah 11 1y? h
0oes 11 baJk? y
Ts 11 a dog? y
T Jue!
AJe you 1h1hk1hg o1 ah ah1ma? h
Aqui est a rvore que este dilogo constri:
Captulo 20: rvores #93
Como pensar como um cientista da Computao usando Python
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.
Aqui est o cdigo:
de1 ah1ma{) .
# s1aJ1 w11h a s1hge1oh
Joo1 = TJee{"b1Jd")
# oop uh11 1he useJ qu11s
wh1e 1 .
pJ1h1
11 ho1 yes{"AJe you 1h1hk1hg o1 ah ah1ma? ") .
bJeak
# wak 1he 1Jee
1Jee = Joo1
wh1e 1Jee.ge1Le11{) != hohe .
pJomp1 = 1Jee.ge1CaJgo{) + "? "
11 yes{pJomp1).
1Jee = 1Jee.ge1R1gh1{)
ese.
1Jee = 1Jee.ge1Le11{)
# make a guess
guess = 1Jee.ge1CaJgo{)
pJomp1 = "Ts 11 a " + guess + "? "
11 yes{pJomp1) .
pJ1h1 "T Jue!"
coh11hue
# ge1 hew 1h1oJma11oh
pJomp1 = "Wha1 1s 1he ah1ma\`s hame? "
ah1ma = Jaw_1hpu1{pJomp1)
pJomp1 = "Wha1 ques11oh woud d1s11hgu1sh a s
1Jom a s? "
ques11oh = Jaw_1hpu1{pJomp1 {ah1ma,guess))
# add hew 1h1oJma11oh 1o 1he 1Jee
1Jee.se1CaJgo{ques11oh)
pJomp1 = "T1 1he ah1ma weJe s 1he ahsweJ woud
be? "
11 yes{pJomp1 ah1ma) .
1Jee.se1Le11{TJee{guess))
1Jee.se1R1gh1{TJee{ah1ma))
ese .
1Jee.se1Le11{TJee{ah1ma))
1Jee.se1R1gh1{TJee{guess))
A funo yes um auxiliar; ele imprime um
prompt e em seguida solicita do usurio uma entrada. Se a
resposta comear com y ou Y, a funo devolve um valor
verdadeiro:
de1 yes{ques) .
1Jom s1J1hg 1mpoJ1 oweJ
ahs = oweJ{Jaw_1hpu1{ques))
Je1uJh {ahs|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!
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.
20.8 Glossrio
rvore binria
(binary tree)
Uma rvore em que cada clula tem zero,
um ou dois descendentes.
raiz (root) A clula mais alta de uma rvore, a (nica)
clula de uma rvore que no tem pai.
folha (leaf) Uma clula mais baixa numa rvore; uma
clula que no tem descendentes.
pai (parent) A clula que aponta para uma clula dada.
filho (child) Uma clula apontada por uma clula dada.
irmos
(siebling)
Clulas que tem o mesmo pai.
nvel (level) Um conjunto de clulas equidistantes da
raiz.
operador
binrio
(binary
operator)
Um operador sobre dois operandos.
subexpresso
(subexpressio
n)
Uma expresso entre parntesis que se
comporta como um operando simples numa
expresso maior.
pr-ordem
(preorder)
Uma forma de percorrer uma rvore
visitando cada clula antes dos seus filhos.
notao
prefixa (prefix
notation)
Uma forma de escrever uma expresso
matemtica em que cada operador aparece
antes dos seus operandos.
ps-ordem
(postorder)
Uma forma de percorrer uma rvore
visitando os filhos de cada clula antes da
prpria clula.
in-ordem
(inorder)
Uma forma de percorrer uma rvore
visitando a subrvore esquerda, seguida da
raiz e finalmente da subrvore direita.
Captulo 20: rvores #94
Como pensar como um cientista da Computao usando Python
GNU Free Documentation License GNU Free Documentation License
Version 1.2, November 2002
CopyJ1gh1 {C) 2000,2001,2002 FJee So11waJe
Fouhda11oh, Thc.
51 FJahk1h S1, F111h FooJ, Bos1oh, hA 02110-1301
bSA
EveJyohe 1s peJm111ed 1o copy ahd d1s1J1bu1e
veJba11m cop1es
o1 1h1s 1cehse documeh1, bu1 chahg1hg 11 1s ho1
aowed.
0. PREAMBLE
The purpose of this License is to make a manual, textbook, or
other functional and useful document "free" in the sense of
freedom: to assure everyone the effective freedom to copy and
redistribute it, with or without modifying it, either
commercially or noncommercially. Secondarily, this License
preserves for the author and publisher a way to get credit for
their work, while not being considered responsible for
modifications made by others.
This License is a kind of "copyleft", which
means that derivative works of the document must themselves
be free in the same sense. It complements the GNU General
Public License, which is a copyleft license designed for free
software.
We have designed this License in order to use it
for manuals for free software, because free software needs
free documentation: a free program should come with manuals
providing the same freedoms that the software does. But this
License is not limited to software manuals; it can be used for
any textual work, regardless of subject matter or whether it is
published as a printed book. We recommend this License
principally for works whose purpose is instruction or
reference.
1. APPLICABILITY AND DEFINITIONS
This License applies to any manual or other work, in any
medium, that contains a notice placed by the copyright holder
saying it can be distributed under the terms of this License.
Such a notice grants a world-wide, royalty-free license,
unlimited in duration, to use that work under the conditions
stated herein. The "Document", below, refers to any such
manual or work. Any member of the public is a licensee, and
is addressed as "you". You accept the license if you copy,
modify or distribute the work in a way requiring permission
under copyright law.
A "Modified Version" of the Document means
any work containing the Document or a portion of it, either
copied verbatim, or with modifications and/or translated into
another language.
A "Secondary Section" is a named appendix or a
front-matter section of the Document that deals exclusively
with the relationship of the publishers or authors of the
Document to the Document's overall subject (or to related
matters) and contains nothing that could fall directly within
that overall subject. (Thus, if the Document is in part a
textbook of mathematics, a Secondary Section may not
explain any mathematics.) The relationship could be a matter
of historical connection with the subject or with related
matters, or of legal, commercial, philosophical, ethical or
political position regarding them.
The "Invariant Sections" are certain Secondary
Sections whose titles are designated, as being those of
Invariant Sections, in the notice that says that the Document is
released under this License. If a section does not fit the above
definition of Secondary then it is not allowed to be designated
as Invariant. The Document may contain zero Invariant
Sections. If the Document does not identify any Invariant
Sections then there are none.
The "Cover Texts" are certain short passages of
text that are listed, as Front-Cover Texts or Back-Cover Texts,
in the notice that says that the Document is released under this
License. A Front-Cover Text may be at most 5 words, and a
Back-Cover Text may be at most 25 words.
A "Transparent" copy of the Document means a
machine-readable copy, represented in a format whose
specification is available to the general public, that is suitable
for revising the document straightforwardly with generic text
editors or (for images composed of pixels) generic paint
programs or (for drawings) some widely available drawing
editor, and that is suitable for input to text formatters or for
automatic translation to a variety of formats suitable for input
to text formatters. A copy made in an otherwise Transparent
file format whose markup, or absence of markup, has been
arranged to thwart or discourage subsequent modification by
readers is not Transparent. An image format is not
Transparent if used for any substantial amount of text. A copy
that is not "Transparent" is called "Opaque".
Examples of suitable formats for Transparent
copies include plain ASCII without markup, Texinfo input
format, LaTeX input format, SGML or XML using a publicly
available DTD, and standard-conforming simple HTML,
PostScript or PDF designed for human modification.
Examples of transparent image formats include PNG, XCF
and JPG. Opaque formats include proprietary formats that can
be read and edited only by proprietary word processors,
SGML or XML for which the DTD and/or processing tools
are not generally available, and the machine-generated
HTML, PostScript or PDF produced by some word processors
for output purposes only.
The "Title Page" means, for a printed book, the
title page itself, plus such following pages as are needed to
hold, legibly, the material this License requires to appear in
the title page. For works in formats which do not have any
title page as such, "Title Page" means the text near the most
prominent appearance of the work's title, preceding the
beginning of the body of the text.
A section "Entitled XYZ" means a named
subunit of the Document whose title either is precisely XYZ
or contains XYZ in parentheses following text that translates
XYZ in another language. (Here XYZ stands for a specific
section name mentioned below, such as "Acknowledgements",
"Dedications", "Endorsements", or "History".) To "Preserve
the Title" of such a section when you modify the Document
means that it remains a section "Entitled XYZ" according to
this definition.
The Document may include Warranty
Disclaimers next to the notice which states that this License
applies to the Document. These Warranty Disclaimers are
considered to be included by reference in this License, but
only as regards disclaiming warranties: any other implication
that these Warranty Disclaimers may have is void and has no
effect on the meaning of this License.
GNU Free Documentation License #95
Como pensar como um cientista da Computao usando Python
2. VERBATIM COPYING
You may copy and distribute the Document in any medium,
either commercially or noncommercially, provided that this
License, the copyright notices, and the license notice saying
this License applies to the Document are reproduced in all
copies, and that you add no other conditions whatsoever to
those of this License. You may not use technical measures to
obstruct or control the reading or further copying of the copies
you make or distribute. However, you may accept
compensation in exchange for copies. If you distribute a large
enough number of copies you must also follow the conditions
in section 3.
You may also lend copies, under the same
conditions stated above, and you may publicly display copies.
3. COPYING IN QUANTITY
If you publish printed copies (or copies in media that
commonly have printed covers) of the Document, numbering
more than 100, and the Document's license notice requires
Cover Texts, you must enclose the copies in covers that carry,
clearly and legibly, all these Cover Texts: Front-Cover Texts
on the front cover, and Back-Cover Texts on the back cover.
Both covers must also clearly and legibly identify you as the
publisher of these copies. The front cover must present the full
title with all words of the title equally prominent and visible.
You may add other material on the covers in addition.
Copying with changes limited to the covers, as long as they
preserve the title of the Document and satisfy these
conditions, can be treated as verbatim copying in other
respects.
If the required texts for either cover are too
voluminous to fit legibly, you should put the first ones listed
(as many as fit reasonably) on the actual cover, and continue
the rest onto adjacent pages.
If you publish or distribute Opaque copies of the
Document numbering more than 100, you must either include
a machine-readable Transparent copy along with each Opaque
copy, or state in or with each Opaque copy a computer-
network location from which the general network-using public
has access to download using public-standard network
protocols a complete Transparent copy of the Document, free
of added material. If you use the latter option, you must take
reasonably prudent steps, when you begin distribution of
Opaque copies in quantity, to ensure that this Transparent
copy will remain thus accessible at the stated location until at
least one year after the last time you distribute an Opaque
copy (directly or through your agents or retailers) of that
edition to the public.
It is requested, but not required, that you contact
the authors of the Document well before redistributing any
large number of copies, to give them a chance to provide you
with an updated version of the Document.
4. MODIFICATIONS
You may copy and distribute a Modified Version of the
Document under the conditions of sections 2 and 3 above,
provided that you release the Modified Version under
precisely this License, with the Modified Version filling the
role of the Document, thus licensing distribution and
modification of the Modified Version to whoever possesses a
copy of it. In addition, you must do these things in the
Modified Version:
A. Use in the Title Page (and on the covers, if any) a
title distinct from that of the Document, and from
those of previous versions (which should, if there
were any, be listed in the History section of the
Document). You may use the same title as a previous
version if the original publisher of that version gives
permission.
B. List on the Title Page, as authors, one or more
persons or entities responsible for authorship of the
modifications in the Modified Version, together with
at least five of the principal authors of the Document
(all of its principal authors, if it has fewer than five),
unless they release you from this requirement.
C. State on the Title page the name of the publisher
of the Modified Version, as the publisher.
D. Preserve all the copyright notices of the
Document.
E. Add an appropriate copyright notice for your
modifications adjacent to the other copyright notices.
F. Include, immediately after the copyright notices, a
license notice giving the public permission to use the
Modified Version under the terms of this License, in
the form shown in the Addendum below.
G. Preserve in that license notice the full lists of
Invariant Sections and required Cover Texts given in
the Document's license notice.
H. Include an unaltered copy of this License.
I. Preserve the section Entitled "History", Preserve its
Title, and add to it an item stating at least the title,
year, new authors, and publisher of the Modified
Version as given on the Title Page. If there is no
section Entitled "History" in the Document, create
one stating the title, year, authors, and publisher of
the Document as given on its Title Page, then add an
item describing the Modified Version as stated in the
previous sentence.
J. Preserve the network location, if any, given in the
Document for public access to a Transparent copy of
the Document, and likewise the network locations
given in the Document for previous versions it was
based on. These may be placed in the "History"
section. You may omit a network location for a work
that was published at least four years before the
Document itself, or if the original publisher of the
version it refers to gives permission.
K. For any section Entitled "Acknowledgements" or
"Dedications", Preserve the Title of the section, and
preserve in the section all the substance and tone of
each of the contributor acknowledgements and/or
dedications given therein.
L. Preserve all the Invariant Sections of the
Document, unaltered in their text and in their titles.
Section numbers or the equivalent are not considered
part of the section titles.
M. Delete any section Entitled "Endorsements". Such
a section may not be included in the Modified
Version.
N. Do not retitle any existing section to be Entitled
"Endorsements" or to conflict in title with any
Invariant Section.
O. Preserve any Warranty Disclaimers.
If the Modified Version includes new front-
matter sections or appendices that qualify as Secondary
Sections and contain no material copied from the Document,
you may at your option designate some or all of these sections
as invariant. To do this, add their titles to the list of Invariant
Sections in the Modified Version's license notice. These titles
must be distinct from any other section titles.
You may add a section Entitled
"Endorsements", provided it contains nothing but
endorsements of your Modified Version by various parties--
for example, statements of peer review or that the text has
been approved by an organization as the authoritative
definition of a standard.
GNU Free Documentation License #96
Como pensar como um cientista da Computao usando Python
You may add a passage of up to five words as a
Front-Cover Text, and a passage of up to 25 words as a Back-
Cover Text, to the end of the list of Cover Texts in the
Modified Version. Only one passage of Front-Cover Text and
one of Back-Cover Text may be added by (or through
arrangements made by) any one entity. If the Document
already includes a cover text for the same cover, previously
added by you or by arrangement made by the same entity you
are acting on behalf of, you may not add another; but you may
replace the old one, on explicit permission from the previous
publisher that added the old one.
The author(s) and publisher(s) of the Document
do not by this License give permission to use their names for
publicity for or to assert or imply endorsement of any
Modified Version.
5. COMBINING DOCUMENTS
You may combine the Document with other documents
released under this License, under the terms defined in section
4 above for modified versions, provided that you include in
the combination all of the Invariant Sections of all of the
original documents, unmodified, and list them all as Invariant
Sections of your combined work in its license notice, and that
you preserve all their Warranty Disclaimers.
The combined work need only contain one copy
of this License, and multiple identical Invariant Sections may
be replaced with a single copy. If there are multiple Invariant
Sections with the same name but different contents, make the
title of each such section unique by adding at the end of it, in
parentheses, the name of the original author or publisher of
that section if known, or else a unique number. Make the same
adjustment to the section titles in the list of Invariant Sections
in the license notice of the combined work.
In the combination, you must combine any
sections Entitled "History" in the various original documents,
forming one section Entitled "History"; likewise combine any
sections Entitled "Acknowledgements", and any sections
Entitled "Dedications". You must delete all sections Entitled
"Endorsements."
6. COLLECTIONS OF DOCUMENTS
You may make a collection consisting of the Document and
other documents released under this License, and replace the
individual copies of this License in the various documents
with a single copy that is included in the collection, provided
that you follow the rules of this License for verbatim copying
of each of the documents in all other respects.
You may extract a single document from such a
collection, and distribute it individually under this License,
provided you insert a copy of this License into the extracted
document, and follow this License in all other respects
regarding verbatim copying of that document.
7. AGGREGATION WITH INDEPENDENT
WORKS
A compilation of the Document or its derivatives with other
separate and independent documents or works, in or on a
volume of a storage or distribution medium, is called an
"aggregate" if the copyright resulting from the compilation is
not used to limit the legal rights of the compilation's users
beyond what the individual works permit. When the
Document is included in an aggregate, this License does not
apply to the other works in the aggregate which are not
themselves derivative works of the Document.
If the Cover Text requirement of section 3 is
applicable to these copies of the Document, then if the
Document is less than one half of the entire aggregate, the
Document's Cover Texts may be placed on covers that bracket
the Document within the aggregate, or the electronic
equivalent of covers if the Document is in electronic form.
Otherwise they must appear on printed covers that bracket the
whole aggregate.
8. TRANSLATION
Translation is considered a kind of modification, so you may
distribute translations of the Document under the terms of
section 4. Replacing Invariant Sections with translations
requires special permission from their copyright holders, but
you may include translations of some or all Invariant Sections
in addition to the original versions of these Invariant Sections.
You may include a translation of this License, and all the
license notices in the Document, and any Warranty
Disclaimers, provided that you also include the original
English version of this License and the original versions of
those notices and disclaimers. In case of a disagreement
between the translation and the original version of this License
or a notice or disclaimer, the original version will prevail.
If a section in the Document is Entitled
"Acknowledgements", "Dedications", or "History", the
requirement (section 4) to Preserve its Title (section 1) will
typically require changing the actual title.
9. TERMINATION
You may not copy, modify, sublicense, or distribute the
Document except as expressly provided for under this
License. Any other attempt to copy, modify, sublicense or
distribute the Document is void, and will automatically
terminate your rights under this License. However, parties
who have received copies, or rights, from you under this
License will not have their licenses terminated so long as such
parties remain in full compliance.
10. FUTURE REVISIONS OF THIS LICENSE
The Free Software Foundation may publish new, revised
versions of the GNU Free Documentation License from time
to time. Such new versions will be similar in spirit to the
present version, but may differ in detail to address new
problems or concerns. See http://www.gnu.org/copyleft/.
Each version of the License is given a
distinguishing version number. If the Document specifies that
a particular numbered version of this License "or any later
version" applies to it, you have the option of following the
terms and conditions either of that specified version or of any
later version that has been published (not as a draft) by the
Free Software Foundation. If the Document does not specify a
GNU Free Documentation License #97
Como pensar como um cientista da Computao usando Python
version number of this License, you may choose any version
ever published (not as a draft) by the Free Software
Foundation.
How to use this License for your documents
To use this License in a document you have
written, include a copy of the License in the document and put
the following copyright and license notices just after the title
page:
CopyJ1gh1 {c) YEAR Y0bR hAhE.
PeJm1ss1oh 1s gJah1ed 1o copy, d1s1J1bu1e ahd/oJ
mod11y 1h1s documeh1
uhdeJ 1he 1eJms o1 1he Chb FJee 0ocumeh1a11oh
L1cehse, veJs1oh 1.2
oJ ahy a1eJ veJs1oh pub1shed by 1he FJee So11waJe
Fouhda11oh,
w11h ho ThvaJ1ah1 Sec11ohs, ho FJoh1-CoveJ Tex1s,
ahd ho Back-CoveJ
Tex1s. A copy o1 1he 1cehse 1s 1hcuded 1h 1he
sec11oh eh111ed "Chb
FJee 0ocumeh1a11oh L1cehse".
If you have Invariant Sections, Front-Cover
Texts and Back-Cover Texts, replace the "with...Texts." line
with this:
w11h 1he ThvaJ1ah1 Sec11ohs be1hg LTST ThETR
TTTLES, w11h 1he
FJoh1-CoveJ Tex1s be1hg LTST, ahd w11h 1he Back-
CoveJ Tex1s be1hg LTST.
If you have Invariant Sections without Cover
Texts, or some other combination of the three, merge those
two alternatives to suit the situation.
If your document contains nontrivial examples
of program code, we recommend releasing these examples in
parallel under your choice of free software license, such as the
GNU General Public License, to permit their use in free
software.
GNU Free Documentation License #98