pense em python · 2020. 7. 12. · fred bremmer enviou uma correção da seção 2.1. jonah cohen...

309

Upload: others

Post on 31-Dec-2020

5 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo
Page 2: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

PrefácioAestranhahistóriadestelivro

Emjaneirode1999eumepreparavaparadaraulaaumaturmadeprogramaçãointrodutória em Java. Já tinha dado esse curso três vezes e estava ficandofrustrado. O índice de aprovação era muito baixo e mesmo entre os alunosaprovados,onívelgeraldasnotaserabaixodemais.

Umdosproblemasqueeuviaeramoslivros.Erammuitograndes,comdetalhesdesnecessários sobre o Java, e não havia orientação de alto nível sobre comoprogramar.Etodoselessofriamdoefeitoalçapão:noinícioerafácil,osalunosiam aprendendo aos poucos, e lá peloCapítulo 5, perdiam o chão. Eramuitomaterialnovo,muitorápido,eelesacabavamengatinhandonorestodosemestre.

Duas semanas antes do primeiro dia de aula, eu decidi escrever meu própriolivro.Meusobjetivoseram:

que o livro fosse curto. Eramelhor os alunos lerem 10 páginas que nãolerem50.

abordar o vocabulário com cuidado. Tentei minimizar o jargão e definircadatermonomomentodoprimeirouso.

construir o aprendizado passo a passo. Para evitar alçapões, dividi ostópicosmaisdifíceiseemumasériedeetapasmenores.

queoconteúdofosseconcentradoemprogramarmesmo,nãonalinguagemdeprogramação.SelecioneiumsubconjuntomínimoútildoJavaeomitioresto.

Euprecisavadeumtítulo,então,porcapricho,decidichamá-lodePensecomoumcientistadacomputação.

Aminhaprimeiraversãoeraapenasumesboço,masfuncionou.Osalunosliame entendiamo suficiente para podermos usar o tempo de aula para os tópicosdifíceis, interessantes e (o mais importante) para permitir que os alunos

Page 3: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

praticassem.

LanceiolivrosobumaLicençadeDocumentaçãoLivreGNU,quepermiteaosusuárioscopiar,modificaredistribuirolivro.

E o que aconteceu em seguida foi legal. Jeff Elkner, um professor de ensinomédio naVirgínia adotoumeu livro e o traduziu para Python. Eleme enviouumacópiadesuatraduçãoetiveaexperiênciaexcepcionaldeaprenderPythonlendoomeuprópriolivro.ComaeditoraGreenTea,publiqueiaprimeiraversãoemPythonem2001.

Em2003comeceiatrabalharnoOlinCollegeeaensinarPythonpelaprimeiraveznavida.Ocontraste como Javaeranotável.Osestudantes tinhammenosdificuldades, aprendiam mais, trabalhavam em projetos mais interessantes egeralmentesedivertiammuitomais.

Desde então continuei a desenvolver o livro, corrigindo erros, melhorandoalgunsexemploseacrescentandomaterial,especialmenteexercícios.

Oresultadoestáaqui,agoracomotítulomenosgrandiosodePenseemPython.Fizalgumasalterações:

Acrescentei uma seção sobre depuração (debugging) no fim de cadacapítulo. Essas seções apresentam técnicas gerais para encontrar e evitarbugs(errosdeprogramação)eavisossobrearmadilhasdoPython.

Acrescentei exercícios, incluindo testes curtos de compreensão e algunsprojetos substanciais. A maior parte dos exercícios tem um link para aminhasolução.

Acrescentei uma série de estudos de caso – exemplos mais longos comexercícios,soluçõesediscussões.

Expandi a discussão sobre planos de desenvolvimento de programas epadrõesdedesignbásicos.

Acrescenteiapêndicessobredepuraçãoeanálisedealgoritmos.

EstaediçãodePenseemPythontemasseguintesnovidades:

Page 4: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

OlivroetodoocódigodeapoioforamatualizadosparaoPython3.

Acrescentei algumas seções e mais detalhes sobre a web, para ajudar osprincipiantesaexecutaroPythonemumnavegador,enãoterquelidarcomainstalaçãodoprogramaatéquesejanecessário.

Para “Módulo turtle” na página 63 troquei meu próprio pacote gráficoturtle,chamadoSwampy,paraummóduloPythonmaispadronizado,turtle,queémaisfácildeinstalaremaiseficiente.

Acrescentei um novo capítulo chamado “Extra”, que introduz algunsrecursosadicionaisdoPython,nãoestritamentenecessários,masàsvezespráticos.

Espero que goste de trabalhar com este livro, e que ele o ajude a aprender aprogramar e pensar, pelo menos um pouquinho, como um cientista dacomputação.

AllenB.DowneyOlinCollege

Convençõesusadasnestelivro

Asseguintesconvençõestipográficassãousadasnestelivro:

Itálico

Indicanovostermos,URLs,endereçosdeemail,nomesdearquivoeextensõesdearquivo.

Negrito

Indicatermosdefinidosnoglossárionofinaldecapítulo.

Monoespaçado

Usadaparacódigodeprograma,bemcomodentrodeparágrafosparareferir-seaelementos do programa, como nomes de variáveis ou de funções, bancos dedados,tiposdedados,variáveisdeambiente,instruçõesepalavras-chave.

Page 5: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Monoespaçadonegrito

Exibe comandos ou outros textos que devem ser digitados literalmente pelousuário.

Monoespaçadoitálico

Exibetextosquedevemsersubstituídosporvaloresfornecidospelosusuáriosouporvaloresdeterminadospelocontexto.

Usodocódigodosexemplos(deacordocomapolíticadaO'Reilly)

Hámaterial suplementar (exemplos de código, exercícios etc.) disponível parabaixaremhttp://www.greenteapress.com/thinkpython2/code.

Este livro serve para ajudar você a fazer o que precisa. Em geral, se o livrooferece exemplos de código, você pode usá-los nos seus programas edocumentação.Nãoéprecisoentraremcontatoconoscoparapedirpermissão,amenos que esteja reproduzindo uma porção significativa do código. Porexemplo, escrever um programa que use vários pedaços de código deste livronãoexigepermissão.VenderoudistribuirumCD-ROMdeexemplosdoslivrosda O’Reilly exige permissão. Responder a uma pergunta citando este livro ereproduzindo exemplos de código não exige permissão. Incorporar umaquantidadesignificativadeexemplosdecódigodestelivronadocumentaçãodoseuprodutoexigepermissão.

Agradecemos,masnãoexigimos,crédito.Ocréditonormalmenteincluiotítulo,o autor, a editora e o ISBN. Por exemplo: “Pense em Python, 2ª edição, porAllenB.Downey(O’Reilly).Copyright2016AllenDowney,978-1-4919-3936-9.”

Se acreditar que o seu uso dos exemplos de código não se ajusta à permissãodadaanteriormente,fiqueàvontadeparaentraremcontatoconoscopeloemailpermissions@oreilly.com.

Comoentraremcontatoconosco

Page 6: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Envie comentários e dúvidas sobre este livro à editora, escrevendo para:[email protected].

Temos uma páginaweb para este livro na qual incluímos erratas, exemplos equaisqueroutrasinformaçõesadicionais.

Páginadaediçãoemportuguês

http://www.novatec.com.br/catalogo/7522508-pense-em-python

Páginadaediçãooriginaleminglês

http://bit.ly/think-python_2E

Paraobtermais informações sobreos livros daNovatec, acessenosso site emhttp://www.novatec.com.br.

Agradecimentos

MuitoobrigadoaJeffElkner,que traduziumeulivrodeJavaparaoPython,oque deu início a este projeto e me apresentou ao que acabou sendo a minhalinguagemfavorita.

Agradeço também aChrisMeyers, que contribuiu em várias seções doPensecomoumcientistadacomputação.

Obrigado à Fundação do Software Livre pelo desenvolvimento da Licença deDocumentaçãoLivreGNU,quemeajudouatornarpossívelacolaboraçãocomJeffeChris,eaoCreativeCommonspelalicençaqueestouusandoagora.

ObrigadoaoseditoresdoLulu,quetrabalharamnoPensecomoumcientistadacomputação.

ObrigadoaoseditoresdaO’ReillyMedia,quetrabalharamnoPenseemPython.

Obrigado a todos os estudantes que trabalharam com versões anteriores destelivro e a todos os contribuidores (listados a seguir) que enviaram correções esugestões.

Page 7: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Listadecontribuidores

Maisdecemleitoresperspicazeseatentosenviaramsugestõesecorreçõesnosúltimos anos. Suas contribuições e entusiasmo por este projeto foraminestimáveis.

Se tiver alguma sugestão ou correção, por favor, envie um email [email protected]. Se eu fizer alguma alteração baseada no seucomentário,acrescentareiseunomeàlistadecontribuidores(amenosquevocêpeçaparaeuomitirainformação).

Sevocêincluirpelomenosumapartedafraseondeoerroaparece,émaisfácilparaeuprocurá-lo.Tambémpodeseronúmerodapáginaeseção,masaíéumpouquinhomaisdifícildeencontraroerroasercorrigido.Obrigado!

LloydHughAllenenviouumacorreçãodaSeção8.4.

YvonBoulianneenviouacorreçãodeumerrosemânticonoCapítulo5.

FredBremmerenviouumacorreçãodaSeção2.1.

JonahCohenescreveuosscriptsemPerlparaconverterafontedeLaTeXdestelivroparaobeloHTML.

Michael Conlon enviou uma correção gramatical do Capítulo 2 e umamelhoria no estilo do Capítulo 1, além de iniciar a discussão sobre osaspectostécnicosdeinterpretadores.

BenoitGirardenviouumacorreçãoaumerrohumorísticonaSeção5.6.

CourtneyGleasoneKatherineSmithescreveramhorsebet.py,quefoiusadocomo um estudo de caso em uma versão anterior do livro. O programaagorapodeserencontradonosite.

LeeHarrenvioumaiscorreçõesdoquetemosespaçopararelacionaraqui,enaverdadeeledeveserapontadocomoumdoseditoresprincipaisdotexto.

JamesKaylinéumestudantequeusaotexto.Eleenviouváriascorreções.

DavidKershawcorrigiuafunçãocatTwicedefeituosanaSeção3.10.

Page 8: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

EddieLamentregoudiversascorreçõesaosCapítulos1,2,e3.EletambémcorrigiuoMakefile para criar um índicenaprimeiravezque rodar e nosajudouaestabelecerumesquemadeversionamento.

Man-YongLeeenviouumacorreçãodocódigodeexemplonaSeção2.4.

David Mayo indicou que a palavra “inconscientemente” no Capítulo 1deviaseralteradapara“subconscientemente”.

ChrisMcAloonenviouváriascorreçõesparaasSeções3.9e3.10.

Matthew J. Moelter tem contribuído já há um bom tempo e entregoudiversascorreçõesesugestõesparaolivro.

Simon Dicon Montford informou que havia uma definição de funçãoausenteevárioserrosdeortografianoCapítulo3.Ele tambémencontrouerrosnafunçãoincrementnoCapítulo13.

JohnOuztscorrigiuadefiniçãode“valorderetorno”noCapítulo3.

Kevin Parks enviou comentários e sugestões valiosos para melhorar adistribuiçãodolivro.

DavidPoolencontrouumerrodeortografianoglossáriodoCapítulo1,etambémenvioupalavrasgentisdeencorajamento.

Michael Schmitt enviou uma correção ao capítulo sobre arquivos eexceções.

RobinShaw indicouumerronaSeção13.1,ondea funçãoprintTime foiusadaemumexemplosemserdefinida.

PaulSleighencontrouumerronoCapítulo7eumbugnoscriptemPerldeJonahCohen,quegeraoHTMLdoLaTeX.

CraigT.SnydalestátestandootextoemumcursonaDrewUniversity.Elecontribuiucomváriassugestõesvaliosasecorreções.

Ian Thomas e seus alunos estão usando o texto em um curso deprogramação.Elessãoosprimeirosatestaroscapítulosdasegundametade

Page 9: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

dolivroefizerammuitascorreçõesesugestões.

KeithVerheydenenviouumacorreçãonoCapítulo3.

PeterWinstanleynosavisousobreumerroantigonolatimdoCapítulo3.

Chris Wrobel fez correções ao código no capítulo sobre arquivos E/S eexceções.

Moshe Zadka fez contribuições inestimáveis para este projeto. Além deescrever o primeiro rascunho do capítulo sobreDicionários, ele forneceuorientaçãocontínuanasprimeirasetapasdolivro.

Christoph Zwerschke enviou várias correções e sugestões pedagógicas, eexplicouadiferençaentregleicheselbe.

James Mayer enviou-nos um monte de erros tipográficos e ortográficos,inclusivedoisdalistadecontribuidores.

HaydenMcAfeepercebeuumainconsistênciapotencialmenteconfusaentredoisexemplos.

Angel Arnal faz parte de uma equipe internacional de tradutores quetrabalhounaversãodotextoparaoespanhol.Eletambémencontrouvárioserrosnaversãoeminglês.

Tauhidul Hoque e Lex Berezhny criaram as ilustrações do Capítulo 1 emelhorarammuitasdasoutrasilustrações.

O Dr. Michele Alzetta pegou um erro no Capítulo 8 e enviou algunscomentáriospedagógicosinteressantesesugestõessobreFibonaccieojogodoMico.

AndyMitchell pegouumerro de ortografia noCapítulo 1 e umexemploruimnoCapítulo2.

Kalin Harvey sugeriu um esclarecimento no Capítulo 7 e achou algunserrosdeortografia.

Christopher P. Smith encontrou vários erros de ortografia e ajudou-nos a

Page 10: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

atualizarolivroparaoPython2.2.

DavidHutchinsencontrouumerrodeortografianoprefácio.

GregorLingl é professor dePython emuma escola deEnsinoMédio emViena, naÁustria. Ele está trabalhando emuma tradução do livro para oalemãoeencontroualgunserrosfeiosnoCapítulo5.

JuliePetersachouumerrodeortografianoprefácio.

Florin Oprina enviou uma melhoria para o makeTime, uma correção noprintTimeeumbeloerrodeortografia.

D.J.WebresugeriuumesclarecimentonoCapítulo3.

KenencontrouumpunhadodeerrosnosCapítulos8,9e11.

Ivo Wever achou um erro de ortografia no Capítulo 5 e sugeriu umesclarecimentonoCapítulo3.

CurtisYankosugeriuumesclarecimentonoCapítulo2.

BenLoganenviouvárioserrosdeortografiaeproblemascomatraduçãodolivroparaHTML.

JasonArmstrongpercebeuquefaltavaumapalavranoCapítulo2.

Louis Cordier notou um ponto no Capítulo 16 onde o código nãocorrespondiacomotexto.

BrianCaimsugeriuváriosesclarecimentosnosCapítulos2e3.

RobBlackentregouummontedecorreções, inclusivealgumasalteraçõesparaPython2.2.

Jean-PhilippeRey, daÉcoleCentrale Paris, enviou uma série de patches,inclusive algumas atualizações do Python 2.2 e outras melhorias bempensadas.

JasonMader,daGeorgeWashingtonUniversity,fezumasériedesugestõesecorreçõesúteis.

Page 11: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

JanGundtofte-Bruunnoslembroudeque“unerro”éumerro.

AbelDavideAlexisDinnonos lembraramdequeopluralde“matriz”é“matrizes”, não “matrixes”. Este erro esteve no livro por anos,mas doisleitorescomasmesmasiniciaisinformaramarespeitodelenomesmodia.Bizarro.

Charles Thayer nos estimulou a sumir com os pontos e vírgulas quetínhamos posto no final de algumas instruções e a otimizar nosso uso de“argumento”e“parâmetro”.

RogerSperbergindicouumapartedistorcidadelógicanoCapítulo3.

SamBullindicouumparágrafoconfusonoCapítulo2.

AndrewCheungindicouduasocorrênciasde“usoantesdadefinição”.

C. Corey Capel notou uma palavra ausente e um erro de ortografia noCapítulo4.

AlessandraajudouaeliminaralgumascoisasconfusasdoTurtle.

WimChampagneencontrouumaconfusãodepalavrasemumexemplodedicionário.

DouglasWrightindicouumproblemacomadivisãopelopisoemarc.

JaredSpindorencontrouumaconfusãonofimdeumafrase.

LinPeihengenviouváriassugestõesmuitoúteis.

RayHagtvedtenvioudoiserroseumquaseerro.

TorstenHübschindicouumainconsistêncianoSwampy.

IngaPetuhhovcorrigiuumexemplonoCapítulo14.

ArneBabenhauserheideenviouváriascorreçõesúteis.

MarkE.Casidaéébomemencontrarpalavrasrepetidas.

Page 12: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ScottTylerpreencheuumquefaltava.Eemseguidaenviouummontedecorreções.

GordonShephardenviouváriascorreções,todasememailsseparados.

AndrewTurnernotouumerronoCapítulo8.

AdamHobartcorrigiuumproblemacomadivisãopelopisoemarc.

DarylHammond e SarahZimmerman indicaramque eu trouxe omath.piparaamesacedodemais.EZimachouumerrodeortografia.

GeorgeSassencontrouumbugemumaseçãodedepuração.

BrianBinghamsugeriuoExercício11.5.

LeahEngelbert-Fentonindicouqueuseituplecomoumnomedevariável,contrariandomeupróprioconselho.E,emseguida,encontrouumaporçãodeerrosdeortografiaeum“usoantesdadefinição”.

JoeFunkeachouumerrodeortografia.

Chao-chaoChenencontrouumainconsistêncianoexemplodeFibonacci.

JeffPainesabeadiferençaentreespaçoespam.

LubosPintesenviouumerrodeortografia.

GreggLindeAbigailHeithoffsugeriramoExercício14.3.

MaxHailperinentregouumasériedecorreçõesesugestões.Maxéumdosautores das extraordinárias Abstrações Concretas (Tecnologia de curso,1998),quevocêpodequererlerquandoterminarestelivro.

ChotipatPornavalaiencontrouumerroemumamensagemdeerro.

StanislawAntolenviouumalistacomváriassugestõesúteis.

EricPashmanenviouumasériedecorreçõesparaosCapítulos4-11.

MiguelAzevedoencontroualgunserrosdeortografia.

Page 13: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

JianhuaLiuenviouumalongalistadecorreções.

NickKingencontrouumapalavraquefaltava.

MartinZutherenviouumalongalistadesugestões.

Adam Zimmerman encontrou uma inconsistência em uma ocorrência de“ocorrência”eváriosoutroserros.

Ratnakar Tiwari sugeriu uma nota de rodapé explicando triângulosdegenerados.

AnuragGoel sugeriuoutra soluçãopara is_abecedarian e enviou algumascorreçõesadicionais.EelesabesoletrarJaneAusten.

KelliKratzernotouumdoserrosdeortografia.

MarkGriffithsindicouumexemploconfusonoCapítulo3.

RoydanOngieencontrouumerronomeumétododeNewton.

PatrykWolowiecmeajudoucomumproblemanaversãodoHTML.

MarkChonofskymefaloudeumanovapalavra-chavenoPython3.

RussellColemanajudoucomaminhageometria.

WeiHuangnotouvárioserrostipográficos.

KarenBarberachouoerrodeortografiamaisantigonolivro.

Nam Nguyen encontrou um erro de ortografia e indicou que usei oDecorator,masnãomencioneionome.

StéphaneMorinenviouváriascorreçõesesugestões.

PaulStoopcorrigiuumerrodeortografiaemuses_only.

EricBronnerindicouumaconfusãonadiscussãodaordemdeoperações.

AlexandrosGezerlisdefiniuumnovopadrãoparaonúmeroeaqualidade

Page 14: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

dassugestõesqueenviou.Estamosprofundamentegratos!

GrayThomassabediferenciaradireitadaesquerda.

GiovanniEscobarSosaenviouumalongalistadecorreçõesesugestões.

AlixEtiennecorrigiuumadasURLs.

KuangHeencontrouumerrodeortografia.

DanielNeilsoncorrigiuumerrosobreaordemdeoperações.

WillMcGinnisindicouquepolylinefoidefinidadeformadiferenteemdoislugares.

SwarupSahoonotouquefaltavaumpontoevírgula.

Frank Hecker indicou que um exercício estava mal especificado eencontroualgunslinksquebrados.

AnimeshBmeajudouaesclarecerumexemploconfuso.

MartinCaspersenencontroudoiserrosdearredondamento.

GregorUlmenviouváriascorreçõesesugestões.

DimitriosTsirigkassugeriuqueeuesclarecesseumexercício.

CarlosTafurenviouumapáginadecorreçõesesugestões.

MartinNordslettenencontrouumbugnasoluçãodeumexercício.

LarsO.D.Christensenencontrouumareferênciaquebrada.

VitorSimeoneencontrouumerrodeortografia.

Sven Hoexter indicou que uma entrada de uma variável nomeada sesobrepõeaumafunçãointegrada.

VietLeencontrouumerrodeortografia.

Page 15: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

StephenGregoryindicouoproblemacomcmpnoPython3.

MatthewShultzmeavisousobreumlinkquebrado.

LokeshKumarMakanimeavisousobrealgunslinksquebradosealgumasalteraçõesemmensagensdeerro.

IshwarBhatcorrigiuminhadeclaraçãodoúltimoteoremadeFermat.

BrianMcGhiesugeriuumesclarecimento.

Andrea Zanella traduziu o livro para o italiano e enviou uma série decorreçõesaolongodocaminho.

Muito, muito obrigado a Melissa Lewis e Luciano Ramalho peloscomentáriosesugestõesexcelentesnasegundaedição.

Obrigado a Harry Percival do PythonAnywhere por ajudar as pessoas acomeçarausaroPythonemumnavegador.

XavierVanAubelfezváriascorreçõesúteisnasegundaedição.

Page 16: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo1:AjornadadoprogramaOobjetivodestelivroéensinarapensarcomoumcientistadacomputação.Estaformadepensar combinaalgumasdasmelhores característicasdamatemática,daengenhariaedasciênciasnaturais.Assimcomoosmatemáticos,oscientistasda computação usam linguagens formais para denotar ideias (especificamenteoperações de computação). Como engenheiros, eles projetam coisas, reunindocomponentes em sistemas e avaliando as opções de melhor retorno entre asalternativas à disposição. Como cientistas, observam o comportamento desistemascomplexos,formamhipótesesetestamprevisões.

A habilidade específica mais importante de um cientista da computação é aresolução de problemas. Resolução de problemas significa a capacidade deformularproblemas,pensarcriativamenteemsoluçõeseexpressarumasoluçãode forma clara e precisa. Assim, o processo de aprender a programar é umaoportunidadeexcelenteparaexercitarahabilidadederesolverproblemas.Éporissoqueestecapítulosechama“Ajornadadoprograma”.

Emumnívelvocêaprenderáaprogramar,umahabilidadeútilporsimesma.Emoutro nível usará a programação como um meio para um fim. Conformeavançarmos,estefimficarámaisclaro.

1.1-Oqueéumprograma?

Umprogramaéumasequênciadeinstruçõesqueespecificacomoexecutarumaoperaçãodecomputação.Aoperaçãodecomputaçãopodeseralgomatemático,como solucionar um sistema de equações ou encontrar as raízes de umpolinômio,mastambémpodeserumaoperaçãodecomputaçãosimbólica,comoabuscaea substituiçãode textosemumdocumento;oualgográfico,comooprocessamentodeumaimagemouareproduçãodeumvídeo.

Os detalhes parecem diferentes em linguagens diferentes, mas algumasinstruçõesbásicasaparecememquasetodasaslinguagens:

entradaReceber dados do teclado, de um arquivo, da rede ou de algum outro

Page 17: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

dispositivo.saída

Exibirdadosnatela,salvá-losemumarquivo,enviá-lospelaredeetc.matemática

Executaroperaçõesmatemáticasbásicascomoadiçãoemultiplicação.execuçãocondicional

Verificaraexistênciadecertascondiçõeseexecutarocódigoadequado.repetição

Executarváriasvezesalgumaação,normalmentecomalgumasvariações.

Acrediteounão,istoébasicamentetudooqueéprecisosaber.Cadaprogramaquevocêjáusou,complicadoounão,écompostodeinstruçõesmuitoparecidascomessas.Podemosentãochegaràconclusãodequeprogramaréoprocessodequebrarumatarefagrandeecomplexaemsubtarefascadavezmenores,atéqueestas sejam simples o suficiente para serem executadas por uma dessasinstruçõesbásicas.

1.2-ExecuçãodoPython

UmdosdesafiosdecomeçarausarPythonéterqueinstalarnoseucomputadoro próprio programa e outros relacionados. Se tiver familiaridade com o seusistemaoperacional,eespecialmentesenãotiverproblemascomainterfacedelinha de comando, você não terá dificuldade para instalar o Python.Mas paraprincipiantes pode ser trabalhoso aprender sobre administração de sistemas eprogramaçãoaomesmotempo.

Paraevitaresseproblema,recomendoquecomeceaexecutaroPythonemumnavegador. Depois, quando você já conhecer o Python um pouco mais, dareisugestõesparainstalá-loemseucomputador.

Há uma série de sites que ajudam a usar e executar o Python. Se já tem umfavorito,váemfrenteeuse-o.Senão,recomendooPythonAnywhere.Apresentoinstruções detalhadas sobre os primeiros passos no linkhttp://tinyurl.com/thinkpython2e.

Há duas versões do Python, o Python 2 e o Python 3. Como elas são muitosemelhantes, sevocêaprenderumaversão,é fácil trocarparaaoutra.Comoéiniciante,vocêencontrarápoucasdiferenças.EstelivrofoiescritoparaoPython3,mastambémincluíalgumasnotassobreoPython2.

Page 18: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

O interpretadordoPythonéumprogramaque lêeexecutaocódigoPython.Dependendodoseuambiente,épossíveliniciarointerpretadorclicandoemumícone,oudigitandopythonemumalinhadecomando.Quandoeleiniciar,vocêdeveráverumasaídacomoesta:

Python3.4.0(default,Jun192015,14:20:21)

[GCC4.8.2]onlinux

Type"help","copyright","credits"or"license"formoreinformation.

>>>

As trêsprimeiras linhas contêm informações sobreo interpretador e o sistemaoperacional em que está sendo executado, portanto podem ser diferentes paravocê.Maséprecisoconferirseonúmerodaversão,queé3.4.0nesteexemplo,começacom3,oqueindicaquevocêestáexecutandooPython3.Secomeçarcom2,vocêestáexecutando(adivinhe!)oPython2.

Aúltimalinhaéumpromptindicandoqueointerpretadorestáprontoparavocêdigitar o código. Se digitar uma linha de código e pressionar Enter, ointerpretadorexibeoresultado:

>>>1+1

2

Agoravocêestáprontoparacomeçar.Daquiemdiante,vousuporquevocêsabecomoinicializarointerpretadordoPythoneexecutarocódigo.

1.3-Oprimeiroprograma

Tradicionalmente,oprimeiroprogramaqueseescreveemumanovalinguagemchama-se “Hello,World!”, porque tudo o que faz é exibir as palavras “Hello,World!”natela.NoPython,eleseparececomisto:

>>>print('Hello,World!')

Esteéumexemplodeumainstruçãoprint(instruçãodeimpressão),emboranarealidadeelanãoimprimanadaempapel.Elaexibeumresultadonatela.Nessecaso,oresultadosãoaspalavras:

Hello,World!

As aspas apenas marcam o começo e o fim do texto a ser exibido; elas não

Page 19: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

aparecemnoresultado.

Osparêntesesindicamqueoprintéumafunção.VeremosfunçõesnoCapítulo3.

NoPython2,a instruçãoprinté ligeiramentediferente;elanãoéuma função,portantonãousaparênteses.

>>>print'Hello,World!'

Estadistinçãofarámaissentidoembreve,masissoéosuficienteparacomeçar.

1.4-Operadoresaritméticos

Depois do “Hello, World”, o próximo passo é a aritmética. O Python temoperadores,quesãosímbolosespeciaisrepresentandooperaçõesdecomputação,comoadiçãoemultiplicação.

Osoperadores+,-e*executamaadição,asubtraçãoeamultiplicação,comonosseguintesexemplos:

>>>40+2

42

>>>43-1

42

>>>6*7

42

Ooperador/executaadivisão:

>>>84/2

42.0

Pode ser que você fique intrigado pelo resultado ser 42.0 em vez de 42.Vouexplicarissonapróximaseção.

Finalmente,ooperador**executaaexponenciação;istoé,elevaumnúmeroaumapotência:

>>>6**2+6

42

Em algumas outras linguagens, o ^ é usado para a exponenciação, mas noPythonéumoperadorbitwise,chamadoXOR.Senão tiver familiaridadecom

Page 20: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

operadoresbitwise,oresultadoosurpreenderá:

>>>6^2

4

Nãoabordareioperadoresbitwiseneste livro,masvocêpode lersobreelesemhttp://wiki.python.org/moin/BitwiseOperators.

1.5-Valoresetipos

Umvaloréumadascoisasbásicascomasquaisumprograma trabalha,comouma letraouumnúmero.Algunsvaloresquevimosatéagora foram2,42.0e'Hello,World!'.

Esses valores pertencem a tipos diferentes: 2 é umnúmero inteiro, 42.0 é umnúmerodepontoflutuantee'Hello,World!'éumastring,assimchamadaporqueasletrasquecontémestãoemumasequênciaemcadeia.

Senãotivercertezasobrequaléotipodecertovalor,ointerpretadorpodedizerissoavocê:

>>>type(2)

<class'int'>

>>>type(42.0)

<class'float'>

>>>type('Hello,World!')

<class'str'>

Nessesresultados,apalavra“class”[classe]éusadanosentidodecategoria;umtipoéumacategoriadevalores.

Como se poderia esperar, números inteiros pertencem ao tipo int, stringspertencemaotipostreosnúmerosdepontoflutuantepertencemaotipofloat.

Evalores como '2' e '42.0'?Parecemnúmeros,mas estão entre aspas como sefossemstrings:

>>>type('2')

<class'str'>

>>>type('42.0')

<class'str'>

Page 21: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Entãosãostrings.

Aodigitarumnúmero inteirogrande,algunspodemusaranotaçãoamericana,comvírgulasentregruposdedígitos,comoem1,000,000.EstenãoéumnúmerointeirolegítimonoPythoneresultaráem:

>>>1,000,000

(1,0,0)

Oquenãoédemodoalgumoqueesperávamos!OPythoninterpreta1,000,000comoumasequênciadenúmerosinteirosseparadosporvírgulas.Aprenderemosmaissobreestetipodesequênciamaisadiante.

1.6-Linguagensformaisenaturais

As linguagens naturais são os idiomas que as pessoas falam, como inglês,espanhol e francês. Elas não foram criadas pelas pessoas (embora as pessoastentemimporcertaordemaelas);desenvolveram-senaturalmente.

As linguagens formais são linguagens criadas pelas pessoas para aplicaçõesespecíficas.Porexemplo,anotaçãoqueosmatemáticosusaméumalinguagemformal especialmente boa para denotar relações entre números e símbolos.Osquímicos usamuma linguagem formal para representar a estrutura química demoléculas.Eomaisimportante:

As linguagens de programação são idiomas formais criados para expressaroperaçõesdecomputação.

Aslinguagensformaisgeralmentetêmregrasdesintaxeestritasquegovernamaestruturadedeclarações.Porexemplo,namatemáticaadeclaração3+3=6temuma sintaxe correta, mas não 3 + = 3$6. Na química, H2O é uma fórmulasintaticamentecorreta,mas2Zznãoé.

Asregrasdesintaxevêmemduascategoriasrelativasasímboloseestrutura.Ossímbolos são os elementos básicos da linguagem, como palavras, números eelementos químicos. Um dos problemas com 3 + = 3$6 é que o $ não é umsímbololegítimonamatemática(pelomenosatéondeeusei).Deformasimilar,2ZznãoélegítimoporquenãohánenhumelementocomaabreviaturaZz.

Osegundotipoderegradesintaxerefere-seaomodonoqualossímbolossão

Page 22: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

combinados. A equação 3 + = 3 não é legítima porque, embora + e = sejamsímboloslegítimos,nãosepodeterumnasequênciadooutro.Deformasimilar,em uma fórmula química o subscrito vem depois do nome de elemento, nãoantes.

Estaéum@frasebemestruturadaemportuguê$,mascoms*mbolosinválidos.Estafrasetodosossímbolosválidostem,masestruturaválidasem.

Aolerumafraseemportuguêsouumadeclaraçãoemumalinguagemformal,éprecisocompreenderaestrutura (emboraemuma linguagemnaturalvocê façaistodeformasubconsciente).Esteprocessoéchamadodeanálise.

Embora as linguagens formais e naturais tenham muitas características emcomum–símbolos,estruturaesintaxe–háalgumasdiferenças:

ambiguidadeAslinguagensnaturaissãocheiasdeambiguidadeeaspessoaslidamcomissousandopistascontextuaiseoutrasinformações.Aslinguagensformaissãocriadasparaserquaseoucompletamenteinequívocas,ouseja,qualquerafirmaçãotemexatamenteumsignificado,independentementedocontexto.

redundânciaParacompensaraambiguidadeereduzirequívocos,aslinguagensnaturaisusammuita redundância.Porcausadisso,muitasvezessãoverborrágicas.Aslinguagensformaissãomenosredundantesemaisconcisas.

literalidadeAs linguagens naturais são cheias de expressões emetáforas. Se eu digo“Caiuaficha”,provavelmentenãoháfichanenhumanahistória,nemnadaquetenhacaído(estaéumaexpressãoparadizerquealguémentendeualgodepois de certo período de confusão). As linguagens formais têmsignificadosexatamenteiguaisaoqueexpressam.

Como todos nós crescemos falando linguagens naturais, às vezes é difícil seajustaralinguagensformais.Adiferençaentrealinguagemnaturaleaformalésemelhanteàdiferençaentrepoesiaeprosa,masvaialém:

PoesiaAspalavrassãousadastantopelossonscomopelossignificados,eopoemainteirocriaumefeitoourespostaemocional.Aambiguidadenãoéapenascomum,masmuitasvezesproposital.

Page 23: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ProsaOsignificadoliteraldaspalavraséomaisimportanteeaestruturacontribuiparaestesignificado.Aprosaémaisacessívelàanálisequeapoesia,masmuitasvezesaindaéambígua.

ProgramasAsignificadodeumprogramadecomputadoréinequívocoeliteralepodeserentendidointeiramentepelaanálisedossímbolosedaestrutura.

As linguagens formais são mais densas que as naturais, então exigem maistempoparaaleitura.Alémdisso,aestruturaéimportante,entãonemsempreémelhor ler de cima para baixo e da esquerda para a direita. Em vez disso,aprenda a analisar o programa primeiro, identificando os símbolos einterpretando a estrutura. E os detalhes fazem diferença. Pequenos erros emortografiaepontuação,quepodemnão importar tantonas linguagensnaturais,podemfazerumagrandediferençaemumalínguaformal.

1.7-Depuração

Osprogramadoreserram.Porumcaprichododestino,errosdeprogramaçãosãochamados de bugs (insetos) e o processo de rastreá-los chama-se depuração(debugging).

Programar,eespecialmentefazeradepuração,àsvezestrazemoçõesfortes.Setiver dificuldade com certo bug, você pode ficar zangado, desesperado ouconstrangido.

Háevidênciasdequeaspessoasrespondemnaturalmenteacomputadorescomosefossempessoas.Quandofuncionambem,pensamosnelescomoparceirosdaequipe,equandosãoteimososougrosseiros,respondemosaelesdomesmojeitoque fazemos com pessoas grosseiras e teimosas (Reeves e Nass, The MediaEquation:HowPeopleTreatComputers,Television,andNewMediaLikeRealPeople and Places — A equação da mídia: como as pessoas tratam oscomputadores,atelevisãoeasnovasmídiascomosefossempessoaselugaresreais).

Prepare-se para essas reações, pois isso pode ajudar a lidar com elas. Umaabordagemépensarnocomputadorcomoumfuncionáriocomcertasvantagens,comovelocidadeeprecisão,ecertasdesvantagens,comoafaltadeempatiaeaincapacidadedecompreenderumcontextomaisamplo.

Page 24: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Seutrabalhoéserumbomgerente:encontrarformasdeaproveitarasvantagense atenuar as desvantagens. E também encontrar formas de usar suas emoçõespara lidar com o problema sem deixar suas reações interferirem na suacapacidadedetrabalho.

Aprenderadepurarerrospodeserfrustrante,maséumahabilidadevaliosa,útilparamuitas atividadesalémdaprogramação.No fimdecadacapítuloháumaseçãocomoesta,comasminhassugestõespara fazeradepuração.Esperoquesejamúteis!

1.8-Glossário

resoluçãodeproblemasOprocessodeformularumproblema,encontrarumasoluçãoeexpressá-la.

linguagemdealtonívelUmalinguagemdeprogramaçãocomoPython,quefoicriadacomointuitodeserfácilparaoshumanosescreveremelerem.

linguagemdebaixonívelUma linguagem de programação criada para o computador executar comfacilidade; também chamada de “linguagem de máquina” ou “linguagemassembly”.

portabilidadeApropriedadedeumprogramadepoderserexecutadoemmaisdeumtipodecomputador.

interpretadorUmprogramaquelêoutroprogramaeoexecuta.

promptCaracteres expostos pelo interpretador para indicar que está pronto parareceberentradasdousuário.

programaConjuntodeinstruçõesqueespecificamumaoperaçãodecomputação.

instruçãoprintUmainstruçãoquefazointerpretadordoPythonexibirumvalornatela.

operadorUmsímboloespecialquerepresentaumaoperaçãodecomputaçãosimplescomoadição,multiplicaçãoouconcatenaçãodestrings.

valorUmadasunidadesbásicasdedados, comoumnúmeroou string, queum

Page 25: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

programamanipula.tipo

Umacategoriadevalores.Os tiposquevimospor enquanto sãonúmerosinteiros(tipoint),númerosdepontoflutuante(tipofloat)estrings(tipostr).

inteiroUmtipoquerepresentanúmerosinteiros.

pontoflutuanteUmtipoquerepresentanúmeroscompartesfracionárias.

stringUmtipoquerepresentasequênciasdecaracteres.

linguagemnaturalQualquer linguagem que as pessoas falam e que se desenvolveunaturalmente.

linguagemformalQualquer linguagem que as pessoas criaram com objetivos específicos,comorepresentarideiasmatemáticasouprogramasdecomputador;todasaslinguagensdeprogramaçãosãolinguagensformais.

símboloUmdoselementosbásicosdaestruturasintáticadeumprograma,análogoaumapalavraemlinguagemnatural.

sintaxeAsregrasquegovernamaestruturadeumprograma.

análiseExaminarumprogramaesuaestruturasintática.

bugUmerroemumprograma.

depuraçãoOprocessodeencontrarecorrigir(depurar)bugs.

1.9-Exercícios

Exercício1.1

É uma boa ideia ler este livro em frente a um computador para testar osexemplosdurantealeitura.

Semprequeestivertestandoumnovorecurso,vocêdevetentarfazererros.Porexemplo,noprograma“Hello,World!”,oqueaconteceseomitirumadasaspas?

Page 26: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Eseomitirambas?Esevocêsoletrarainstruçãoprintdeformaerrada?

Estetipodeexperimentoajudaalembraroquefoilido;tambémajudaquandovocêestiverprogramando,porqueassimconheceráosignificadodasmensagensdeerro.Émelhorfazererrosagoraedepropósitoquedepoiseacidentalmente.

1. Emumainstruçãoprint,oqueacontecesevocêomitirumdosparêntesesouambos?

2. Seestivertentandoimprimirumastring,oqueaconteceseomitirumadasaspasouambas?

3. Vocêpodeusarumsinaldemenosparafazerumnúmeronegativocomo-2.O que acontece se puser um sinal de mais antes de um número? E seescreverassim:2++2?

4. Na notaçãomatemática, zeros à esquerda são aceitáveis, como em 02.OqueacontecesevocêtentarusarissonoPython?

5. Oqueacontecesevocêtiverdoisvaloressemnenhumoperadorentreeles?

Exercício1.2

InicializeointerpretadordoPythoneuse-ocomoumacalculadora.

1. Quantossegundosháem42minutose42segundos?

2. Quantasmilhas há em 10 quilômetros?Dica: umamilha equivale a 1,61quilômetro.

3. Sevocêcorrer10quilômetrosem42minutose42segundos,qualéoseupasso médio (tempo por milha em minutos e segundos)? Qual é a suavelocidademédiaemmilhasporhora?

Page 27: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo2:Variáveis,expressõeseinstruçõesUm dos recursos mais eficientes de uma linguagem de programação é acapacidadedemanipularvariáveis.Umavariáveléumnomequeserefereaumvalor.

2.1-Instruçõesdeatribuição

Umainstruçãodeatribuiçãocriaumanovavariáveledáumvaloraela:

>>>message='Andnowforsomethingcompletelydifferent'

>>>n=17

>>>pi=3.141592653589793

Esse exemplo faz três atribuições. A primeira atribui uma string a uma novavariável chamada message; a segunda dá o número inteiro 17 a n; a terceiraatribuiovalor(aproximado)deπapi.

Uma formacomumde representarvariáveisporescritoécolocaronomecomuma flecha apontando para o seu valor. Este tipo de número é chamado dediagramadeestadoporquemostraoestadonoqualcadaumadasvariáveisestá(pense nele como o estado de espírito da variável). A Figura 2.1 mostra oresultadodoexemploanterior.

Figura2.1–Diagramadeestado.

2.2-Nomesdevariáveis

Os programadores geralmente escolhem nomes significativos para as suasvariáveis–elesdocumentamousodavariável.

Page 28: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Nomes de variáveis podem ser tão longos quanto você queira. Podem contertanto letras comonúmeros,masnãopodemcomeçar comumnúmero.É legalusar letrasmaiúsculas,mas a convenção é usar apenas letrasminúsculas paranomesdevariáveis.

Ocaracteredesublinhar(_)podeapareceremumnome.Muitasvezeséusadoem nomes com várias palavras, como your_name ouairspeed_of_unladen_swallow.

Sevocêderumnomeilegalaumavariável,recebeumerrodesintaxe:

>>>76trombones='bigparade'

SyntaxError:invalidsyntax

>>>more@=1000000

SyntaxError:invalidsyntax

>>>class='AdvancedTheoreticalZymurgy'

SyntaxError:invalidsyntax

76trombones é ilegal porque começa com um número. more@ é ilegal porquecontémumcaractereilegal,[email protected]ádeerradocomclass?

Aquestãoéqueclasséumadaspalavras-chavedoPython.Ointerpretadorusapalavras-chave para reconhecer a estrutura do programa e elas não podem serusadascomonomesdevariável.

OPython3temestaspalavras-chave:

anddelfromNoneTrue

aselifglobalnonlocaltry

assertelseifnotwhile

breakexceptimportorwith

classFalseinpassyield

continuefinallyisraise

defforlambdareturn

Você não precisa memorizar essa lista. Na maior parte dos ambientes dedesenvolvimento,aspalavras-chavesãoexibidasemumacordiferente;sevocêtentarusarumacomonomedevariável,vaiperceber.

2.3-Expressõeseinstruções

Page 29: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Umaexpressãoéumacombinaçãodevalores,variáveiseoperadores.Umvalorporsimesmoéconsideradoumaexpressão,assimcomoumavariável,portantoasexpressõesseguintessãotodaslegais:

>>>42

42

>>>n

17

>>>n+25

42

Quandovocêdigitaumaexpressãonoprompt,ointerpretadoraavalia,ouseja,eleencontraovalordaexpressão.Nesteexemplo,ontemovalor17en+25temovalor42.

Uma instrução é uma unidade de código que tem um efeito, como criar umavariávelouexibirumvalor.

>>>n=17

>>>print(n)

Aprimeiralinhaéumainstruçãodeatribuiçãoquedáumvaloran.Asegundalinhaéumainstruçãodeexibiçãoqueexibeovalorden.

Quandovocêdigitaumainstrução,ointerpretadoraexecuta,oquesignificaqueelefazoqueainstruçãodiz.Emgeral,instruçõesnãotêmvalores.

2.4-Modoscript

Até agora executamos o Python no modo interativo, no qual você interagediretamente com o interpretador. O modo interativo é uma boa forma decomeçar,masseestivertrabalhandocommaisdoquealgumaslinhasdocódigo,oprocessopodeficardesorganizado.

Aalternativaésalvarocódigoemumarquivochamadoscripteentãoexecutarointerpretador no modo script para executá-lo. Por convenção, os scripts noPythontêmnomesqueterminamcom.py.

Sesoubercomocriareexecutarumscriptnoseucomputador,vocêestápronto.Senão, recomendousar oPythonAnywhere novamente. Inseri instruções sobrecomoexecutarprogramasnomodoscriptemhttp://tinyurl.com/thinkpython2e.

Page 30: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ComooPythonofereceosdoismodos,vocêpodetestarpedaçosdocódigonomodo interativo antes de colocá-los em um script.Mas há diferenças entre omodointerativoeomodoscriptquepodemconfundiraspessoas.

Por exemplo, se estiverusandooPythoncomoumacalculadora,vocêpoderiadigitar:

>>>miles=26.2

>>>miles*1.61

42.182

Aprimeiralinhaatribuiumvaloramiles,masnãotemefeitovisível.Asegundalinhaéumaexpressão,entãoointerpretadoraavaliaeexibeoresultado.Nofim,chega-se ao resultado de que uma maratona tem aproximadamente 42quilômetros.

Mas se você digitar o mesmo código em um script e executá-lo, não recebenenhuma saída. Uma expressão, por conta própria, não tem efeito visível nomodoscript.OPython,naverdade,avaliaaexpressão,masnãoexibeovaloramenosquevocêespecifique:

miles=26.2

print(miles*1.61)

Estecomportamentopodeconfundirumpouconoinício.

Umscriptnormalmentecontémumasequênciadeinstruções.Sehouvermaisdeumainstrução,osresultadosaparecemumapósooutro,conformeasinstruçõessejamexecutadas.

Porexemplo,oscript

print(1)

x=2

print(x)

produzasaída

1

2

Ainstruçãodeatribuiçãonãoproduznenhumasaída.

Page 31: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Para verificar sua compreensão, digite as seguintes instruções no interpretadordoPythonevejaoquefazem:

5

x=5

x+1

Agoraponhaasmesmas instruções emumscript eo execute.Qual é a saída?Altere o script transformando cada expressão em uma instrução de exibição eentãooexecutenovamente.

2.5-Ordemdasoperações

Quando uma expressão contém mais de um operador, a ordem da avaliaçãodependedaordemdasoperações.Paraoperadoresmatemáticos,oPythonsegueaconvençãomatemática.OacrônimoPEMDASpodeserútilparalembrardasregras:

OsParêntesestêmaprecedênciamaisaltaepodemserusadosparaforçaraavaliaçãodeumaexpressãonaordemquevocêquiser.Comoasexpressõesemparêntesessãoavaliadasprimeiro,2*(3-1)é4,e(1+1)**(5-2)é8.Tambémépossívelusarparêntesesparafacilitaraleituradeumaexpressão,como no caso de (minute * 100) / 60, mesmo se o resultado não foralterado.

AExponenciaçãotemapróximaprecedênciamaisalta,então1+2**3é9,não27,e2*3**2é18,não36.

AMultiplicação e aDivisão têmprecedênciamais alta que aAdição e aSubtração.Assim,2*3-1é5,não4,e6+4/2é8,não5.

Osoperadorescomamesmaprecedênciasãoavaliadosdaesquerdaparaadireita(excetonaexponenciação).Assim,naexpressãodegrees/2*pi,adivisãoaconteceprimeiroeoresultadoémultiplicadoporpi.Paradividirpor2π,vocêpodeusarparêntesesouescreverdegrees/2/pi.

Eu não fico sempre tentando lembrar da precedência de operadores. Se aexpressãonãoestiverclaraàprimeiravista,usoparêntesesparafazerisso.

Page 32: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

2.6-Operaçõescomstrings

Emgeral,nãoépossívelexecutaroperaçõesmatemáticascomstrings,mesmoseelaspareceremnúmeros,entãocoisasassimsãoilegais:

'2'-'1''eggs'/'easy''third'*'acharm'

Masháduasexceções,+e*.

Ooperador+executaumaconcatenaçãodestrings,ouseja,uneasstringspelasextremidades.Porexemplo:

>>>first='throat'

>>>second='warbler'

>>>first+second

throatwarbler

Ooperador*tambémfuncionaemstrings;eleexecutaarepetição.Porexemplo,'Spam'*3é'SpamSpamSpam'.Seumdosvaloresforumastring,ooutrotemdeserumnúmerointeiro.

Esteusode+e* fazsentidoporanalogiacomaadiçãoeamultiplicação.Talcomo 4 * 3 é equivalente a 4 + 4 + 4, esperamos que 'Spam' * 3 seja omesmoque'Spam'+'Spam'+'Spam',eassimé.Poroutrolado,háumadiferençasignificativaentreaconcatenaçãodestringsearepetiçãoemrelaçãoàadiçãoeàmultiplicaçãode números inteiros.Você conseguepensar emumapropriedadequeaadiçãotem,masaconcatenaçãodestringsnãotem?

2.7-Comentários

Conforme os programas ficam maiores e mais complicados, eles são maisdifíceisdeler.Aslinguagensformaissãodensasemuitasvezesédifícilverumpedaçodecódigoecompreenderoqueelefazouporquefazisso.

Por essa razão, é uma boa ideia acrescentar notas aos seus programas paraexplicaremlinguagemnaturaloqueoprogramaestáfazendo.Essasnotassãochamadasdecomentários,ecomeçamcomosímbolo#:

#computaapercentagemdahoraquepassou

percentage=(minute*100)/60

Page 33: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Nessecaso,ocomentárioaparecesozinhoemumalinha.Vocêtambémpodepôrcomentáriosnofimdaslinhas:

percentage=(minute*100)/60#percentagemdeumahora

Tudodo#aofimdalinhaéignorado–nãotemefeitonaexecuçãodoprograma.

Oscomentários tornam-semaisúteisquandodocumentamalgono códigoquenão está óbvio. Podemos supor que o leitor compreenda o que o código faz;assim,émaisútilexplicarporquefazoquefaz.

Estecomentárioéredundanteemrelaçãoaocódigo,alémdeinútil:

v=5#atribui5av

Estecomentáriocontéminformaçõesúteisquenãoestãonocódigo:

v=5#velocidadeemmetros/segundo.

Bons nomes de variáveis podem reduzir a necessidade de comentários, masnomeslongospodemtornarexpressõescomplexasdifíceisdeler,entãoéprecisoanalisaroquevalemaisapena.

2.8-Depuração

Há três tipos de erros que podem ocorrer em um programa: erros de sintaxe,errosdetempodeexecuçãoeerrossemânticos.Éútildistinguirentreelespararastreá-losmaisrapidamente.

ErrodesintaxeA“sintaxe”refere-seàestruturadeumprogramaesuasrespectivasregras.Porexemplo,osparêntesesdevemviremparescorrespondentes,então(1+2)élegal,mas8)éumerrodesintaxe.Sehouverumerrodesintaxeemalgumlugarnoseuprograma,oPythonexibe uma mensagem de erro e para, e não será possível executar oprograma.Nasprimeiraspoucassemanasdasuacarreiraemprogramação,você pode passar muito tempo rastreando erros de sintaxe. Ao adquirirexperiência,vocêfarámenoserroseosencontrarámaisrápido.

ErrodetempodeexecuçãoO segundo tipo de erro é o erro de tempo de execução, assim chamado

Page 34: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

porqueoerronãoapareceatéqueoprogramasejaexecutado.Esseserrostambém se chamam de exceções porque normalmente indicam que algoexcepcional(eruim)aconteceu.Os erros de tempo de execução são raros nos programas simples queveremos nos primeiros capítulos, então pode demorar umpouco até vocêencontraralgum.

ErrosemânticoOterceiro tipodoerroé“semântico”,ouseja, relacionadoaosignificado.Se houver um erro semântico no seu programa, ele será executado semgerarmensagens de erro,mas não vai fazer a coisa certa.Vai fazer algodiferente.Especificamente,vaifazeroquevocêdisserparafazer.Identificar erros semânticos pode ser complicado, porque é precisotrabalhar de trás para a frente, vendo a saída do programa e tentandocompreenderoqueeleestáfazendo.

2.9-Glossário

variávelUmnomequeserefereaumvalor.

atribuiçãoUmainstruçãoqueatribuiumvaloraumavariável.

diagramadeestadoUmarepresentaçãográficadeumgrupodevariáveiseosvaloresaquesereferem.

palavra-chaveUmapalavra reservada, usada para analisar umprograma; não é possívelusarpalavras-chavecomoif,defewhilecomonomesdevariáveis.

operandoUmdosvaloresqueumoperadorproduz.

expressãoUma combinação de variáveis, operadores e valores que representa umresultadoúnico.

avaliarSimplificarumaexpressãoexecutandoasoperaçõesparaproduzirumvalorúnico.

instruçãoUmaseçãodocódigoquerepresentaumcomandoouação.Porenquanto,asinstruçõesquevimossãoinstruçõesdeatribuiçõesedeexibição.

Page 35: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

executarExecutarumainstruçãoparafazeroqueeladiz.

modointerativoUmmododeusarointerpretadordoPython,digitandoocódigonoprompt.

modoscriptUmmododeusarointerpretadordoPythonparalercódigoemumscripteexecutá-lo.

scriptUmprogramaarmazenadoemumarquivo.

ordemdasoperaçõesAs regras que governam a ordem na qual as expressões que envolvemváriosoperadoreseoperandossãoavaliadas.

concatenarJuntardoisoperandospelasextremidades.

comentáriosInformações em um programa destinadas a outros programadores (ouqualquerpessoaqueleiaotextofonte)quenãotêmefeitosobreaexecuçãodoprograma.

errodesintaxeUm erro em um programa que torna sua análise impossível (e por issoimpossíveldeinterpretar).

exceçãoUmerroquesedescobrequandooprogramaéexecutado.

semânticaOsignificadodeumprograma.

errosemânticoUm erro que faz com que um programa faça algo diferente do que oprogramadorpretendia.

2.10-Exercícios

Exercício2.1

Repetindoomeuconselhodocapítulo anterior, semprequevocêaprenderumrecursonovo,vocêdeve testá-lonomodo interativoe fazererrosdepropósitoparaveroqueacontece.

Vimosquen=42élegal.E42=n?

Page 36: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Oux=y=1?

Emalgumaslinguagens,cadainstruçãoterminaemumpontoevírgula;.OqueacontecesevocêpuserumpontoevírgulanofimdeumainstruçãonoPython?

Esepuserumpontonofimdeumainstrução?

Emnotaçãomatemáticaépossívelmultiplicarxeydestaforma:xy.OqueacontecesevocêtentarfazeromesmonoPython?

Exercício2.2

PratiqueousodointerpretadordoPythoncomoumacalculadora:

1. Ovolumedeumaesferacomraioré .Qualéovolumedeumaesferacomraio5?

2. Suponhaqueopreçodecapadeum livrosejaR$24,95,masas livrariasrecebemumdescontode40%.OtransportecustaR$3,00paraoprimeiroexemplare75centavosparacadaexemplaradicional.Qualéocustototaldeatacadopara60cópias?

3. Se eu sair daminha casa às 6:52 e correr 1 quilômetro a umcerto passo(8min15s por quilômetro), então 3 quilômetros a um passo mais rápido(7min12s por quilômetro) e 1 quilômetro no mesmo passo usado emprimeirolugar,quehoraschegoemcasaparaocafédamanhã?

Page 37: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo3:FunçõesNo contexto da programação, uma função é uma sequência nomeada deinstruções que executa uma operação de computação.Ao definir uma função,você especifica o nomee a sequência de instruções.Depois, pode “chamar” afunçãopelonome.

3.1-Chamadadefunção

Jávimosumexemplodechamadadefunção:

>>>type(42)

<class'int'>

Onomedafunçãoétype.Aexpressãoentreparênteseséchamadadeargumentodafunção.Paraestafunção,oresultadoéotipodoargumento.

É comum dizer que uma função “recebe” um argumento e “retorna” umresultado.Oresultadotambéméchamadodevalorderetorno.

OPythonoferecefunçõesqueconvertemvaloresdeumtipoemoutro.Afunçãointrecebequalquervaloreoconverteemumnúmerointeiro,seforpossível,oudeclaraqueháumerro:

>>>int('32')

32

>>>int('Hello')

ValueError:invalidliteralforint():Hello

intpodeconvertervaloresdepontoflutuanteemnúmerosinteiros,masnãofazarredondamentos;elaapenascortaapartedafração:

>>>int(3.99999)

3

>>>int(-2.3)

-2

floatconvertenúmerosinteirosestringsemnúmerosdepontoflutuante:

Page 38: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>float(32)

32.0

>>>float('3.14159')

3.14159

Finalmente,strconverteoargumentoemumastring:

>>>str(32)

'32'

>>>str(3.14159)

'3.14159'

3.2-Funçõesmatemáticas

O Python tem um módulo matemático que oferece a maioria das funçõesmatemáticas comuns. Ummódulo é um arquivo que contém uma coleção defunçõesrelacionadas.

Antesquepossamosusarasfunçõesemummódulo,precisamosimportá-locomumainstruçãodeimportação:

>>>importmath

Esta instrução cria um objeto de módulo chamadomath (matemática). Ao seexibiroobjetodemódulo,sãoapresentadasinformaçõessobreele:

>>>math

<module'math'(built-in)>

Oobjeto demódulo contém as funções e variáveis definidas nomódulo. Paraacessarumadasfunções,éprecisoespecificaronomedomóduloeonomedafunção,separadosporumponto.Esteformatoéchamadodenotaçãodeponto.

>>>ratio=signal_power/noise_power

>>>decibels=10*math.log10(ratio)

>>>radians=0.7

>>>height=math.sin(radians)

Oprimeiroexemplousamath.log10paracalcularaproporçãodesinalederuídoem decibéis (assumindo que signal_power e noise_power tenham sidodefinidos). O módulo matemático também oferece a função log, que calculalogaritmosdebasee.

Page 39: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Osegundoexemploencontraosenoderadians.Onomedavariávelindicaquesin e outras funções trigonométricas (cos, tan etc.) recebem argumentos emradianos.Paraconvertergrausemradianos,dividapor180emultipliqueporπ:

>>>degrees=45

>>>radians=degrees/180.0*math.pi

>>>math.sin(radians)

0.707106781187

A expressãomath.pi recebe a variável pi domódulomatemático. Seu valor éuma aproximação de ponto flutuante de π, com precisão aproximada de 15dígitos.

Sesoubertrigonometria,vocêpodeverificaroresultadoanteriorcomparando-ocomaraizquadradade2divididapor2:

>>>math.sqrt(2)/2.0

0.707106781187

3.3-Composição

Por enquanto, falamos sobre os elementos de um programa – variáveis,expressõeseinstruções–deformaisolada,masnãosobrecomocombiná-los.

Uma das características mais úteis das linguagens de programação é a suacapacidade de usar pequenos blocos de montar para compor programas. Porexemplo, o argumento de uma função pode ser qualquer tipo de expressão,inclusiveoperadoresaritméticos:

x=math.sin(degrees/360.0*2*math.pi)

Eatéchamadasdefunção:

x=math.exp(math.log(x+1))

Épossívelcolocarumvalor,umaexpressãoarbitrária,emquasequalquerlugar.Comumaexceção:oladoesquerdodeumainstruçãodeatribuiçãotemqueserumnomedevariável.Qualqueroutraexpressãonoladoesquerdoéumerrodesintaxe(veremosexceçõesaestaregradepois).

>>>minutes=hours*60#correto

>>>hours*60=minutes#errado!

SyntaxError:can'tassigntooperator

Page 40: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

3.4-Comoacrescentarnovasfunções

Por enquanto, só usamos funções que vêm com o Python, mas também épossívelacrescentarnovasfunções.Umadefiniçãodefunçãoespecificaonomedeumanova funçãoe a sequênciade instruçõesque sãoexecutadasquandoafunçãoéchamada.

Aquiestáumexemplo:

defprint_lyrics():

print("I'malumberjack,andI'mokay.")

print("IsleepallnightandIworkallday.")

deféumapalavra-chavequeindicaumadefiniçãodefunção.Onomedafunçãoé print_lyrics. As regras para nomes de função são as mesmas que as dasvariáveis:letras,númerosesublinhadosãolegais,masoprimeirocaracterenãopodeserumnúmero.Nãopodemosusarumapalavra-chavecomonomedeumafunçãoedevemosevitarterumavariáveleumafunçãocomomesmonome.

Os parênteses vazios depois do nome indicam que esta função não usaargumentos.

Aprimeiralinhadadefiniçãodefunçãochama-secabeçalho;orestoéchamadode corpo. O cabeçalho precisa terminar em dois pontos e o corpo precisa serendentado.Por convenção, a endentação sempre édequatro espaços.Ocorpopodeconterqualquernúmerodeinstruções.

As stringsnas instruçõesdeexibição são limitadasporaspasduplas.Asaspassimpleseasaspasduplasfazemamesmacoisa;amaiorpartedaspessoasusaaspas simples apenas nos casos em que aspas simples (que também sãoapóstrofes)aparecemnastring.

Todas as aspas (simples e duplas) devem ser “aspas retas”, normalmenteencontradasaoladodoEnternoteclado.“Aspascurvas”,comoasdestaoração,nãosãolegaisnoPython.

Se digitar uma definição de função nomodo interativo, o interpretador exibepontos(...)paramostrarqueadefiniçãonãoestácompleta:

>>>defprint_lyrics():

Page 41: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

...print("I'malumberjack,andI'mokay.")

...print("IsleepallnightandIworkallday.")

...

Paraterminarafunção,éprecisoinserirumalinhavazia.

Adefiniçãodeumafunçãocriaumobjetodefunção,quetemotipofunction:

>>>print(print_lyrics)

<functionprint_lyricsat0xb7e99e9c>

>>>type(print_lyrics)

<class'function'>

Asintaxeparachamaranovafunçãoéamesmaqueadasfunçõesintegradas:

>>>print_lyrics()

I'malumberjack,andI'mokay.

IsleepallnightandIworkallday.

Uma vez que a função tenha sido definida, é possível usá-la dentro de outrafunção. Por exemplo, para repetir o refrão anterior, podemos escrever umafunçãochamadarepeat_lyrics:

defrepeat_lyrics():

print_lyrics()

print_lyrics()

Edaíchamarrepeat_lyrics:

>>>repeat_lyrics()

I'malumberjack,andI'mokay.

IsleepallnightandIworkallday.

I'malumberjack,andI'mokay.

IsleepallnightandIworkallday.

Masacançãonãoébemassim.

3.5-Usoedefinições

Juntandofragmentosdecódigodaseçãoanterior,oprogramainteiroficaassim:

defprint_lyrics():

Page 42: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

print("I'malumberjack,andI'mokay.")

print("IsleepallnightandIworkallday.")

defrepeat_lyrics():

print_lyrics()

print_lyrics()

repeat_lyrics()

Este programa contém duas definições de função: print_lyrics erepeat_lyrics.Asdefiniçõesdefunçãosãoexecutadascomooutrasinstruções,masoefeitoécriarobjetosdefunção.As instruçõesdentrodafunçãonãosãoexecutadas até que a função seja chamada, e a definição de função não geranenhumasaída.

Comopoderíamosesperar,éprecisocriaruma funçãoantesdeexecutá-la.Emoutraspalavras,adefiniçãodefunçãotemqueserexecutadaantesqueafunçãosejachamada.

Como exercício,mova a última linha deste programa para o topo, para que achamadadefunçãoapareçaantesdasdefinições.Executeoprogramaevejaqualéamensagemdeerroqueaparece.

Agoramova a chamada de função de volta para baixo emova a definição deprint_lyrics para depois da definição de repeat_lyrics. O que acontecequandoesteprogramaéexecutado?

3.6-Fluxodeexecução

Paragarantirqueumafunçãosejadefinidaantesdoseuprimeirouso,éprecisosaberaordemnaqualasinstruçõesserãoexecutadas.Issoéchamadodefluxodeexecução.

A execução sempre começa na primeira instrução do programa.As instruçõessãoexecutadasumaapósaoutra,decimaparabaixo.

As definições de função não alteram o fluxo da execução do programa, maslembre-sedequeasinstruçõesdentrodafunçãonãosãoexecutadasatéafunçãoserchamada.

Page 43: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Umachamadadefunçãoécomoumdesvionofluxodeexecução.Emvezdeiràpróximainstrução,ofluxosaltaparaocorpodafunção,executaasinstruçõeslá,eentãovoltaparacontinuardeondeparou.

Parecebastante simples, atévocê lembrarqueuma funçãopodechamaroutra.Enquantoestivernomeiodeumafunção,oprogramapodeterqueexecutarasinstruçõesemoutrafunção.Então,enquantoestiverexecutandoanovafunção,oprogramapodeterqueexecutarmaisumafunção!

Felizmente,oPythonébomemnãoperderofiodameada,entãocadavezqueuma função é concluída, o programa continuade ondeparouna funçãoqueochamou.Quandocheganofimdoprograma,eleéencerrado.

Resumindo,nemsempresedevelerumprogramadecimaparabaixo.Àsvezesfazmaissentidoseguirofluxodeexecução.

3.7-Parâmetroseargumentos

Algumas funções que vimos exigem argumentos. Por exemplo, ao chamarmath.sin,vocêusaumnúmerocomoargumento.Algumasfunçõesexigemmaisdeumargumento:omath.powexigedois,abaseeoexpoente.

Dentro da função, os argumentos são atribuídos a variáveis chamadasparâmetros.Aquiestáadefiniçãodeumafunçãoqueprecisadeumargumento:

defprint_twice(bruce):

print(bruce)

print(bruce)

Esta função atribui o argumento a um parâmetro chamado bruce. Quando afunçãoéchamada,elaexibeovalordoparâmetro(sejaqualfor)duasvezes.

Estafunçãofuncionacomqualquervalorquepossaserexibido:

>>>print_twice('Spam')

Spam

Spam

>>>print_twice(42)

42

42

>>>print_twice(math.pi)

Page 44: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

3.14159265359

3.14159265359

Asmesmas regras de composição usadas para funções integradas também sãoaplicadasafunçõesdefinidaspelosprogramadores,entãopodemosusarqualquertipodeexpressãocomoargumentoparaprint_twice:

>>>print_twice('Spam'*4)

SpamSpamSpamSpam

SpamSpamSpamSpam

>>>print_twice(math.cos(math.pi))

-1.0

-1.0

Oargumentoéavaliadoantesdeafunçãoserchamada.Então,nosexemplos,asexpressões'Spam*4emath.cos(math.pi)sósãoavaliadasumavez.

Vocêtambémpodeusarumavariávelcomoargumento:

>>>michael='Eric,thehalfabee.'

>>>print_twice(michael)

Eric,thehalfabee.

Eric,thehalfabee.

Onomedavariávelquepassamoscomoargumento(michael)nãotemnadaavercomonomedoparâmetro(bruce).Nãoimportaqueovalortenhasidochamadode volta (em quem chama); aqui emprint_twice, chamamos todomundo debruce.

3.8-Asvariáveiseosparâmetrossãolocais

Quandovocêcriaumavariáveldentrodeumafunção,elaélocal,ouseja,elasóexistedentrodafunção.Porexemplo:

defcat_twice(part1,part2):

cat=part1+part2

print_twice(cat)

Esta função recebe dois argumentos, concatena-os e exibe o resultado duasvezes.Aquiestáumexemploqueausa:

>>>line1='Bingtiddle'

>>>line2='tiddlebang.'

Page 45: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>cat_twice(line1,line2)

Bingtiddletiddlebang.

Bingtiddletiddlebang.

Quandocat_twiceéencerrada,avariávelcatédestruída.Setentarmosexibi-la,recebemosumaexceção:

>>>print(cat)

NameError:name'cat'isnotdefined

Osparâmetrostambémsãolocais.Porexemplo,alémdeprint_twice,nãoexisteobruce.

3.9-Diagramadapilha

Para monitorar quais variáveis podem ser usadas e onde, é uma boa ideiadesenharumdiagramadapilha.Assimcomodiagramasdeestado,osdiagramasdapilhamostramovalordecadavariável,mastambémmostramafunçãoàqualcadavariávelpertence.

Cadafunçãoérepresentadaporumframe(quadro).Umframeéumacaixacomo nome de uma função junto a ele e os parâmetros e as variáveis da funçãodentrodele.Odiagramadapilhaparao exemplo anterior é exibidonaFigura3.1.

Figura3.1–Diagramadapilha.

Os frames são organizados em uma pilha que indica qual função que foichamada por outra, e assim por diante. Neste exemplo, print_twice foi

Page 46: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

chamadaporcat_twiceecat_twicefoichamadapor__main__,queéumnomeespecial para o frame na posição mais proeminente. Quando você cria umavariávelforadequalquerfunção,elapertencea__main__.

Cadaparâmetrorefere-seaomesmovalorcomoseuargumentocorrespondente.Destaforma,part1temomesmovalorqueline1,part2temomesmovalorqueline2ebrucetemomesmovalorquecat.

Seocorrerumerroduranteumachamadadefunção,oPythonexibeonomedafunção,onomedafunçãoqueachamoueonomedafunçãoquechamouestafunçãoporsuavez,voltandoaté__main__.

Porexemplo,sevocêtentaracessarcatdedentrodeprint_twice,receberáumamensagemdeNameError:

Traceback(innermostlast):

File"test.py",line13,in__main__

cat_twice(line1,line2)

File"test.py",line5,incat_twice

print_twice(cat)

File"test.py",line9,inprint_twice

print(cat)

NameError:name'cat'isnotdefined

Estalistadefunçõeséchamadadetraceback.Elamostraoarquivodoprogramaemqueoerroocorreueemquelinha,equaisfunçõesestavamsendoexecutadasnomomento.Eletambémmostraalinhadecódigoquecausouoerro.

A ordem das funções no traceback é a mesma que a ordem dos frames nodiagramadapilha.Afunçãoqueestásendoexecutadanomomentoestánofinal.

3.10-Funçõescomresultadoefunçõesnulas

Algumas funções que usamos, como as funções matemáticas, devolvemresultados; por falta de um nome melhor, vou chamá-las de funções comresultados. Outras funções, como print_twice, executam uma ação, mas nãodevolvemumvalor.Elassãochamadasdefunçõesnulas.

Quandovocê chamauma função com resultado, quase semprequer fazer algocom o resultado; por exemplo, você pode atribui-lo a uma variável ou usá-la

Page 47: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

comopartedeumaexpressão:

x=math.cos(radians)

golden=(math.sqrt(5)+1)/2

Quandovocêchamaumafunçãonomodointerativo,oPythonexibeoresultado:

>>>math.sqrt(5)

2.2360679774997898

Mas emum script, se você chamar uma função com resultado emais nada, ovalorderetornoéperdidoparasempre!

math.sqrt(5)

Este script calcula a raiz quadrada de 5,mas como não armazena ou exibe oresultado,nãoémuitoútil.

Asfunçõesnulaspodemexibiralgonatelaouteralgumoutroefeito,masnãotêmumvalorderetorno.Sevocêatribuiroresultadoaumavariável,recebeumvalorespecialchamadoNone:

>>>result=print_twice('Bing')

Bing

Bing

>>>print(result)

None

OvalorNonenãoéomesmoqueastring'None'.Éumvalorespecialquetemseuprópriotipo:

>>>print(type(None))

<class'NoneType'>

As funçõesque apresentamospor enquanto são todasnulas.Vamos apresentarfunçõescomresultadomaisadiante.

3.11-Porquefunções?

Casooobjetivodedividirumprogramaemfunçõesnãoestejaclaro,saibaquenaverdadeháváriasrazões:

Page 48: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Criar uma nova função dá a oportunidade de nomear um grupo deinstruções,oquedeixaoseuprogramamaisfácildelerededepurar.

As funções podem tornar um programa menor, eliminando o códigorepetitivo.Depois,sefizeralgumaalteração,bastafazê-laemumlugarsó.

Dividirumprograma longoemfunçõespermitedepuraraspartesumadecadavezeentãoreuni-lasemumconjuntofuncional.

Asfunçõesbemprojetadasmuitasvezessãoúteisparamuitosprogramas.Umavezqueescrevaedepureuma,vocêpodereutilizá-la.

3.12-Depuração

Uma das habilidades mais importantes que você vai aprender é a depuração.Emborapossaserfrustrante,adepuraçãoéumadaspartesmaisintelectualmentericas,desafiadoraseinteressantesdaprogramação.

Decertaforma,depurarésimilaraotrabalhodeumdetetive.Vocêtempistaseprecisainferirosprocessoseeventosquelevaramaosresultadosexibidos.

A depuração também é como ciência experimental. Uma vez que você tenhaumaideiasobreoqueestáerrado,bastaalteraroprogramaetentarnovamente.Se a sua hipótese estava correta, você pode prever o resultado da alteração echegarumpassomaispertodeumprogramafuncional.Seasuahipóteseestavaerrada,éprecisocriaroutra.ComodiziaSherlockHolmes,“Quandoseeliminaoimpossível,oquesobra,pormais incrívelquepareça, sópodeseraverdade.”(A.ConanDoyle,Osignodosquatro).

Para algumas pessoas, programar e depurar são a mesma coisa. Isto é, aprogramação é o processo de depurar gradualmente um programa até que elefaçaoqueoprogramadorquer.A ideiaéquevocêcomececomumprogramafuncionalefaçapequenasalterações,depurando-asnodecorrerdotrabalho.

Porexemplo,oLinuxéumsistemaoperacionalquecontémmilhõesdelinhasdecódigo, mas começou como um programa simples que Linus Torvalds usavaparaexplorarochipIntel80386.SegundoLarryGreenfield,“UmdosprimeirosprojetosdeLinusfoiumprogramaquealternariaentreaexibiçãodeAAAAeBBBB.MaistardeissosedesenvolveuatéviraroLinux.”(Guiadousuáriode

Page 49: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Linuxversãobeta1).

3.13-Glossário

funçãoUmasequêncianomeadadedeclaraçõesqueexecutaalgumaoperaçãoútil.As funções podem receber argumentos ou não e podem ou não produziralgumresultado.

definiçãodefunçãoUma instrução que cria uma função nova, especificando seu nome,parâmetroseasinstruçõesquecontém.

objetodafunçãoUmvalorécriadoporumadefiniçãodefunção.Onomedafunçãoéumavariávelqueserefereaumobjetodefunção.

cabeçalhoAprimeiralinhadeumadefiniçãodefunção.

corpoAsequênciadeinstruçõesdentrodeumadefiniçãodefunção.

parâmetroUm nome usado dentro de uma função para se referir ao valor passadocomoargumento.

chamadadefunçãoUmainstruçãoqueexecutaumafunção.Écompostapelonomedafunçãoseguidodeumalistadeargumentosentreparênteses.

argumentoUmvalorapresentadoaumafunçãoquandoafunçãoéchamada.Estevaloréatribuídoaoparâmetrocorrespondentenafunção.

variávellocalUmavariáveldefinidadentrodeumafunção.Umavariável local sópodeserusadadentrodasuafunção.

valorderetornoO resultado de uma função. Se uma chamada de função for usada comoumaexpressão,ovalorderetornoéovalordaexpressão.

funçãocomresultadoUmafunçãoquedevolveumvalor.

funçãonulaUmafunçãoquesempredevolveNone.

None

Page 50: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Umvalorespecialapresentadoporfunçõesnulas.módulo

Um arquivo que contém uma coleção de funções relacionadas e outrasdefinições.

instruçãodeimportaçãoUmainstruçãoquelêumarquivodemóduloecriaumobjetodemódulo.

objetodemóduloUmvalorcriadoporuma instrução importqueofereceacessoaosvaloresdefinidosemummódulo.

notaçãodepontoAsintaxeparachamarumafunçãoemoutromóduloespecificandoonomedomóduloseguidodeumpontoeonomedafunção.

composiçãoOuso de uma expressão comoparte de uma expressãomaior ou de umainstruçãocomopartedeumainstruçãomaior.

fluxodeexecuçãoAordemnaqualasinstruçõessãoexecutadas.

diagramadapilhaRepresentaçãográficadeumapilhadefunções,suasvariáveiseosvaloresaquesereferem.

frameUma caixa em um diagrama da pilha que representa uma chamada defunção.Contémasvariáveislocaiseosparâmetrosdafunção.

tracebackListadasfunçõesqueestãosendoexecutadas,exibidasquandoocorreumaexceção.

3.14-Exercícios

Exercício3.1

Escreva uma função chamada right_justify, que receba uma string chamada scomo parâmetro e exiba a string com espaços suficientes à frente para que aúltimaletradastringestejanacoluna70datela:

>>>right_justify('monty')

monty

Dica: Use concatenação de strings e repetição. Além disso, o Python oferece

Page 51: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

umafunçãointegradachamadalen,queapresentaocomprimentodeumastring,entãoovalordelen('monty')é5.

Exercício3.2

Um objeto de função é um valor que pode ser atribuído a uma variável oupassado como argumento. Por exemplo, do_twice é uma função que toma umobjetodefunçãocomoargumentoeochamaduasvezes:

defdo_twice(f):

f()

f()

Aqui está um exemplo que usa do_twice para chamar uma função chamadaprint_spamduasvezes:

defprint_spam():

print('spam')

do_twice(print_spam)

1. Digiteesteexemploemumscripteteste-o.

2. Alteredo_twiceparaque recebadoisargumentos,umobjetode funçãoeum valor, e chame a função duas vezes, passando o valor como umargumento.

3. Copieadefiniçãodeprint_twicequeapareceanteriormentenestecapítulonoseuscript.

4. Use aversãoalteradadedo_twice para chamarprint_twice duas vezes,passando'spam'comoumargumento.

5. Definaumafunçãonovachamadado_fourquerecebaumobjetodefunçãoe um valor e chame a função quatro vezes, passando o valor como umparâmetro. Deve haver só duas afirmações no corpo desta função, nãoquatro.

Solução:http://thinkpython2.com/code/do_four.py.

Exercício3.3

Page 52: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Nota: Este exercício deve ser feito usando-se apenas as instruções e osoutrosrecursosqueaprendemosatéagora.

1. Escrevaumafunçãoquedesenheumagradecomoaseguinte:

+----+----+

|||

|||

|||

|||

+----+----+

|||

|||

|||

|||

+----+----+

Dica: para exibir mais de um valor em uma linha, podemos usar umasequênciadevaloresseparadosporvírgula:

print('+','-')

Porpadrão,printavançaparaa linhaseguinte,maspodemos ignoraressecomportamento e inserir um espaço no fim, desta forma: python

print('+',end='')print('-')Asaídadessasinstruçõesé+-.Umainstruçãoprintsemargumentoterminaalinhaatualevaiparaapróximalinha.

2. Escrevaumafunçãoquedesenheumagradesemelhantecomquatrolinhasequatrocolunas.

Solução:http://thinkpython2.com/code/grid.py.Crédito:EsteexercícioébaseadoemoutroapresentadoporOualline,emPracticalCProgramming,ThirdEdition,O’ReillyMedia,1997.

Page 53: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo4:Estudodecaso:projetodeinterfaceEstecapítuloapresentaumestudodecasoquedemonstraoprocessodecriaçãodefunçõesqueoperamsimultaneamente.

Ele apresenta o módulo turtle, que permite criar imagens usando [turtlegraphics][1]. O módulo turtle é incluído na maior parte das instalações doPython,mas se estiver executando a linguagem com o PythonAnywhere vocênãopoderáexecutarosexemplosdoturtle(pelomenosnãoerapossívelquandoescreviestelivro).

Se já tiver instalado o Python no seu computador, você poderá executar osexemplos.Casonão,agoraéumaboahoraparainstalar.Publiqueiinstruçõesnositehttp://tinyurl.com/thinkpython2e.

Os exemplos de código deste capítulo estão disponíveis emhttp://thinkpython2.com/code/polygon.py.

4.1-Móduloturtle

Para conferir se você tem o módulo turtle, abra o interpretador do Python edigite:

>>>importturtle

>>>bob=turtle.Turtle()

Ao executar este código o programa deve abrir uma nova janela com umapequenaflechaquerepresentaoturtle.Fecheajanela.

Crieumarquivochamadomypolygon.pyedigiteoseguintecódigo:

importturtle

bob=turtle.Turtle()

print(bob)

turtle.mainloop()

Page 54: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Omóduloturtle(comtminúsculo)apresentaumafunçãochamadaTurtle(comT maiúsculo), que cria um objeto Turtle, ao qual atribuímos uma variávelchamadabob.Exibirbobfazalgoassim:

<turtle.Turtleobjectat0xb7bfbf4c>

Isto significa que bob se refere a um objeto com o tipo Turtle definido nomóduloturtle.

mainloopdizque a janeladeve esperar queousuário faça algo, emboranestecasonãohajamuitoafazer,excetofecharajanela.

UmavezquetenhacriadooTurtle,vocêpodechamarummétodoparamovê-lopela janela. Método é semelhante a uma função, mas usa uma sintaxeligeiramentediferente.Porexemplo,paramoveroturtleparaafrente:

bob.fd(100)

Ométodofdéassociadocomoobjetoturtle,quedenominamosbob.Chamardeummétodoécomofazerumpedido:vocêestápedindoquebobavance.

Oargumentodefdéumadistânciaempíxeis,entãootamanhorealdependedasuatela.

OutrosmétodosquevocêpodechamaremumTurtlesãobkparamover-separatrás,ltparaviraràesquerdaertparaviraràdireita.Oargumentoparaltertéumânguloemgraus.

Alémdisso,cadaTurtleseguraumacaneta,queestáabaixadaoulevantada;seacanetaestiverabaixada,oTurtledeixaumrastroquandosemove.Osmétodospuepdrepresentam“canetaparacima”e“canetaparabaixo”.

Para desenhar um ângulo reto, acrescente estas linhas ao programa (depois decriarbobeantesdechamaromainloop):

bob.fd(100)

bob.lt(90)

bob.fd(100)

Aoexecutaresteprograma,vocêdeveriaverbobmover-separaolesteedepoisparaonorte,deixandodoissegmentosderetaparatrás.

Page 55: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Agora altere o programa para desenhar um quadrado. Só siga adiante nestecapítuloseelefuncionaradequadamente!

4.2-Repetiçãosimples

Provavelmentevocêescreveualgoassim:

bob.fd(100)

bob.lt(90)

bob.fd(100)

bob.lt(90)

bob.fd(100)

bob.lt(90)

bob.fd(100)

Podemos fazer amesma coisa de formamais concisa com uma instrução for.Acrescenteesteexemploamypolygon.pyeexecute-onovamente:

foriinrange(4):

print('Hello!')

Vocêdeveveralgoassim:

Hello!

Hello!

Hello!

Hello!

Esteéousomaissimplesdainstruçãofor;depoisveremosmaissobreisso.Masisso deve ser o suficiente para que você possa reescrever o seu programa dedesenharquadrados.Nãocontinuealeituraatéquedêcerto.

Aquiestáumainstruçãoforquedesenhaumquadrado:

foriinrange(4):

bob.fd(100)

bob.lt(90)

Asintaxedeumainstruçãoforésemelhanteàdefiniçãodeumafunção.Temumcabeçalho que termina em dois pontos e um corpo endentado. O corpo podeconterqualquernúmerodeinstruções.

Page 56: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Umainstruçãofortambéméchamadadeloopporqueofluxodaexecuçãopassapelocorpoedepoisvoltaaotopo.Nestecaso,elepassapelocorpoquatrovezes.

Estaversão,naverdade, éumpoucodiferentedocódigoanteriorquedesenhaquadradosporquefazoutravoltadepoisdedesenharoúltimoladodoquadrado.A volta extra levamais tempo,mas simplifica o código se fizermos amesmacoisaacadavezpeloloop.Estaversãotambémtemoefeitodetrazeroturtledevoltaàposiçãoinicial,defrenteparaamesmadireçãoemqueestava.

4.3-Exercícios

Aseguir,umasériedeexercíciosusandoTurtleWorld.Elesservemparadivertir,mas também têm outro objetivo. Enquanto trabalha neles, pense que objetivopodeser.

As seções seguintes têm as soluções para os exercícios,mas não olhe até quetenhaterminado(ou,pelomenos,tentado).

1. Escrevaumafunçãochamadasquarequerecebaumparâmetrochamadot,queéumturtle.Eladeveusaroturtleparadesenharumquadrado.

Escrevaumachamadadefunçãoquepassebobcomoumargumentoparaosquareeentãoexecuteoprogramanovamente.

2. Acrescente outro parâmetro, chamado length, ao square. Altere o corpoparaqueocomprimentodosladossejalengtheentãoaltereachamadadafunção para fornecer um segundo argumento. Execute o programanovamente. Teste o seu programa com uma variedade de valores paralength.

3. Façaumacópiadosquareemudeonomeparapolygon.Acrescenteoutroparâmetro chamado n e altere o corpo para que desenhe um polígonoregulardenlados.

Dica:osângulosexterioresdeumpolígonoregulardenladossão360/ngraus.

4. Escreva uma função chamada circle que use o turtle, t e um raio r comoparâmetrosedesenheumcírculoaproximadoaochamarpolygoncomum

Page 57: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

comprimento enúmerode lados adequados.Teste a sua função comumasériedevaloresder.

Dica:descubraacircunferênciadocírculoecertifique-sedequelength*n=circumference.

5. Faça uma versão mais geral do circle chamada arc, que receba umparâmetroadicionaldeangle,paradeterminarqualfraçãodocírculodeveserdesenhada.angleestáemunidadesdegraus,entãoquandoangle=360,oarcdevedesenharumcírculocompleto.

4.4-Encapsulamento

Oprimeiroexercíciopedequevocêponhaseucódigoparadesenharquadradosemuma definição de função e então chame a função, passando o turtle comoparâmetro.Aquiestáumasolução:

defsquare(t):

foriinrange(4):

t.fd(100)

t.lt(90)

square(bob)

Asinstruçõesmaisinternas,fdelt,sãoendentadasduasvezesparamostrarqueestão dentro do loop for, que está dentro da definição da função. A linhaseguinte,square(bob),estáalinhadaàmargemesquerda,oqueindicatantoofimdoloopforcomodadefiniçãodefunção.

Dentroda função,o t indicaomesmo turtlebob, então t.lt (90) temomesmoefeitoquebob.lt(90).Nestecaso,porquenãochamaroparâmetrobob?Aideiaé que t pode ser qualquer turtle, não apenas bob, então você pode criar umsegundoturtleepassá-locomoargumentoaosquare:

alice=turtle.Turtle()

square(alice)

Incluirumapartedocódigoemumafunçãochama-seencapsulamento.Umdosbenefíciosdoencapsulamentoéqueeleatribuiumnomeaocódigo,oqueservecomoumaespéciededocumentação.Outravantageméquesevocêreutilizaro

Page 58: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

código, é mais conciso chamar uma função duas vezes que copiar e colar ocorpo!

4.5-Generalização

Opróximopassoéacrescentarumparâmetro lengthaosquare.Aquiestáumasolução:

defsquare(t,length):

foriinrange(4):

t.fd(length)

t.lt(90)

square(bob,100)

Acrescentar um parâmetro a uma função chama-se generalização porque eletorna a funçãomaisgeral: naversãoanterior, oquadradoé sempredomesmotamanho;nestaversão,podeserdequalquertamanho.

Opróximopassotambéméumageneralização.Emvezdedesenharquadrados,polygondesenhapolígonosregularescomqualquernúmerodelados.Aquiestáumasolução:

defpolygon(t,n,length):

angle=360/n

foriinrange(n):

t.fd(length)

t.lt(angle)

polygon(bob,7,70)

Esteexemplodesenhaumpolígonode7lados,cadaumdecomprimento70.

SeestiverusandoPython2,ovalordoanglepoderiaestarerradoporcausadadivisão de número inteiro.Uma solução simples é calcular angle = 360.0 / n.Como o numerador é um número de ponto flutuante, o resultado é em pontoflutuante.

Quando uma função temvários argumentos numéricos, é fácil esquecer o queelessãoouaordemnaqualelesdevemestar.Nestecaso,muitasvezeséumaboaideiaincluirosnomesdosparâmetrosnalistadeargumentos:

Page 59: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

polygon(bob,n=7,length=70)

Esses são os argumentos de palavra-chave porque incluem os nomes dosparâmetroscomo“palavras-chave” (paranãoconfundircompalavras-chavedoPython,taiscomowhileedef).

Esta sintaxe torna o programa mais legível. Também é uma lembrança sobrecomo os argumentos e os parâmetros funcionam: quando você chama umafunção,osargumentossãoatribuídosaosparâmetros.

4.6-Projetodainterface

Opróximopassoéescrevercircle,querecebeumraior,comoparâmetro.Aquiestáumasoluçãosimplesqueusaopolygonparadesenharumpolígonode50lados:

importmath

defcircle(t,r):

circumference=2*math.pi*r

n=50

length=circumference/n

polygon(t,n,length)

Aprimeira linhacalculaacircunferênciadeumcírculocomo raio rusandoafórmula2πr.Jáqueusamosmath.pi, temosque importarmath.Porconvenção,instruçõesimportnormalmenteficamnoiníciodoscript.

néonúmerodesegmentosderetananossaaproximaçãodeumcírculo,entãolength é o comprimento de cada segmento. Assim, polygon desenha umpolígono50ladosqueseaproximadeumcírculocomoraior.

Uma limitação desta solução é que n é uma constante. Para círculos muitograndes, os segmentos de reta são longos demais, e para círculos pequenos,perdemos tempo desenhando segmentos muito pequenos. Uma solução seriageneralizar a função tomando n como parâmetro. Isso daria ao usuário (sejaquemforquechamecircle)maiscontrole,masainterfaceseriamenoslimpa.

A interface de uma função é um resumo de como ela é usada: Quais são osparâmetros?Oqueafunçãofaz?Equaléovalorderetorno?Umainterfaceé“limpa”sepermitiràpessoaqueachamafazeroquequiser sem terque lidar

Page 60: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

comdetalhesdesnecessários.

Neste exemplo, r pertence à interface porque especifica o círculo a serdesenhado.némenosadequadoporquepertenceaosdetalhesdecomoocírculodeveserapresentado.

Em vez de poluir a interface, é melhor escolher um valor adequado para n,dependendodacircumference:

defcircle(t,r):

circumference=2*math.pi*r

n=int(circumference/3)+1

length=circumference/n

polygon(t,n,length)

Neste ponto, o número de segmentos é um número inteiro próximo acircumference/3,entãoocomprimentodecadasegmentoéaproximadamente3,pequenoosuficienteparaqueoscírculosfiquembons,masgrandesosuficienteparaseremeficienteseaceitáveisparacírculosdequalquertamanho.

##4.7-Refatoração

Quando escrevi circle, pude reutilizar polygon porque um polígono demuitosladoséumaboaaproximaçãodeumcírculo.Masoarcnãoé tãocooperativo;nãopodemosusarpolygonoucircleparadesenharumarco.

Umaalternativaécomeçarcomumacópiadepolygonetransformá-laemarc.Oresultadopoderiaseralgoassim:

defarc(t,r,angle):

arc_length=2*math.pi*r*angle/360

n=int(arc_length/3)+1

step_length=arc_length/n

step_angle=angle/n

foriinrange(n):

t.fd(step_length)

t.lt(step_angle)

Asegundametadedesta funçãoparece comadopolygon,masnãoépossívelreutilizaropolygonsemmudarainterface.Poderíamosgeneralizarpolygonparareceberumângulo comoum terceiro argumento,mas entãopolygonnão seriamaisumnomeadequado!Emvezdisso,vamoschamarafunçãomaisgeralde

Page 61: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

polyline:

defpolyline(t,n,length,angle):

foriinrange(n):

t.fd(length)

t.lt(angle)

Agorapodemosreescreverpolygonearcparausarpolyline:

defpolygon(t,n,length):

angle=360.0/n

polyline(t,n,length,angle)

defarc(t,r,angle):

arc_length=2*math.pi*r*angle/360

n=int(arc_length/3)+1

step_length=arc_length/n

step_angle=float(angle)/n

polyline(t,n,step_length,step_angle)

Finalmente,podemosreescrevercircleparausararc:

defcircle(t,r):

arc(t,r,360)

Este processo – recompor um programa para melhorar interfaces e facilitar areutilização do código – é chamado de refatoração. Neste caso, notamos quehouve código semelhante em arc e polygon, então nós o “fatoramos” nopolyline.

Se tivéssemos planejado, poderíamos ter escrito polyline primeiro e evitado arefatoração, mas muitas vezes não sabemos o suficiente já no início de umprojetoparaprojetartodasasinterfaces.Quandocomeçarmosaescrevercódigo,entenderemosmelhor o problema. Às vezes, a refatoração é um sinal de queaprendemosalgo.

4.8-Umplanodedesenvolvimento

Um plano de desenvolvimento é um processo para escrever programas. Oprocessoqueusamosnesteestudodecasoé“encapsulamentoegeneralização”.Ospassosdesteprocessosão:

1. Comeceescrevendoumpequenoprogramasemdefiniçõesdefunção.

Page 62: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

2. Uma vez que o programa esteja funcionando, identifique uma partecoerentedele,encapsuleessaparteemumafunçãoedêumnomeaela.

3. Generalizeafunçãoacrescentandoosparâmetrosadequados.

4. Repita os passos 1-3 até que tenha um conjunto de funções operantes.Copieecoleocódigooperanteparaevitararedigitação(eredepuração).

5. Procure oportunidades de melhorar o programa pela refatoração. Porexemplo, se você temumcódigo semelhante emvários lugares, pode serumaboaideiafatorá-loemumafunçãogeraladequada.

Este processo tem algumas desvantagens – veremos alternativas mais tarde –maspodeserútilsevocênãosouberdeantemãocomodividiroprogramaemfunções.Estaabordagempermitecriaroprojetonodecorrerdotrabalho.

4.9-docstring

Uma docstring é uma string no início de uma função que explica a interface(“doc”éumaabreviaçãopara“documentação”).Aquiestáumexemplo:

defpolyline(t,n,length,angle):

"""Desenhansegmentosderetacomocomprimentodadoe

ângulo(emgraus)entreeles.téumturtle.

"""

foriinrange(n):

t.fd(length)

t.lt(angle)

Porconvenção,todasasdocstringstêmaspastriplas,tambémconhecidascomostringsmultilinhaporqueasaspas triplaspermitemqueastringseestendapormaisdeumalinha.

Éconciso,mascontémainformaçãoessencialquealguémprecisariaparausarestafunção.Explicasucintamenteoqueafunçãofaz(sementrarnosdetalhesdecomoofaz).Explicaqueefeitocadaparâmetrotemsobreocomportamentodafunçãoeotipoquecadaparâmetrodeveser(senãoforóbvio).

Escrever este tipo de documentação é uma parte importante do projeto dainterface.Umainterfacebemprojetadadevesersimplesdeexplicar;senãofor

Page 63: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

assim,talvezainterfacepossasermelhorada.

4.10-Depuração

Uma interface é comoumcontrato entre uma função e quema chama.Quemchama concorda em fornecer certos parâmetros e a função concorda em fazercertaação.

Porexemplo,polylineprecisadequatroargumentos:ttemqueserumTurtle;ntemqueserumnúmerointeiro;lengthdeveserumnúmeropositivo;eoangletemqueserumnúmero,queseesperaestaremgraus.

Essas exigências são chamadas de precondições porque se supõe que sejamverdadeantesquea funçãosejaexecutada.De forma inversa, ascondiçõesnofimdafunçãosãopós-condições.Aspós-condiçõesincluemoefeitodesejadodafunção(comoodesenhodesegmentosdereta)equalquerefeitocolateral(comomoveroTurtleoufazeroutrasmudanças).

Precondiçõessãoresponsabilidadedequemchama.Sequemchamaviolarumaprecondição (adequadamente documentada!) e a função não funcionarcorretamente,oproblemaestánestapessoa,nãonafunção.

Seasprecondiçõesforemsatisfeitaseaspós-condiçõesnãoforem,oproblemaestá na função. Se as suas precondições e pós-condições forem claras, elaspodemajudarnadepuração.

4.11-Glossário

métodoUmafunçãoassociadaaumobjetoechamadausandoanotaçãodeponto.

loopPartedeumprogramaquepodeserexecutadarepetidamente.

encapsulamentoOprocessodetransformarumasequênciadeinstruçõesemumadefiniçãodefunção.

generalizaçãoO processo de substituir algo desnecessariamente específico (como umnúmero)poralgoadequadamentegeral(comoumavariávelouparâmetro).

Page 64: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

argumentodepalavra-chaveUmargumentoqueincluionomedoparâmetrocomouma“palavra-chave”.

interfaceUmadescriçãodecomousarumafunção,incluindoonomeeasdescriçõesdosargumentosedovalorderetorno.

refatoraçãoOprocessodealterarumprogramafuncionalparamelhorarainterfacedefunçõeseoutrasqualidadesdocódigo.

planodedesenvolvimentoUmprocessodeescreverprogramas.

docstringUma string que aparece no início de uma definição de função paradocumentarainterfacedafunção.

precondiçãoUmaexigênciaquedevesersatisfeitaporquemchamaafunção,antesdeexecutá-la.

pós-condiçãoUma exigência que deve ser satisfeita pela função antes que ela sejaencerrada.

4.12-Exercícios

Exercício4.1

Baixeocódigodestecapítulonositehttp://thinkpython2.com/code/polygon.py.

1. Desenheumdiagramadapilhaquemostreoestadodoprogramaenquantoexecuta circle (bob, radius). Você pode fazer a aritmética à mão ouacrescentarinstruçõesprintaocódigo.

2. Aversãodearcnaseção4.7-Refatoraçãonãoémuitoprecisaporqueaaproximação linear do círculo está sempre do lado de fora do círculoverdadeiro. Consequentemente, o Turtle acaba ficando alguns píxeis dedistânciadodestinocorreto.Minhasoluçãomostraummododereduziroefeitodesteerro.Leiaocódigoevejasefazsentidoparavocê.Sedesenharumdiagrama,poderávercomofunciona.

Exercício4.2

Page 65: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

EscrevaumconjuntodefunçõesadequadamentegeralquepossadesenharflorescomoasdaFigura4.1.

Figura4.1–Floresdetartaruga.

Solução: http://thinkpython2.com/code/flower.py, também exigehttp://thinkpython2.com/code/polygon.py.

Exercício4.3

Escreva um conjunto de funções adequadamente geral que possa desenharformascomoasdaFigura4.2.

Figura4.2–Tortasdetartaruga.

Solução:http://thinkpython2.com/code/pie.py.

Exercício4.4

Asletrasdoalfabetopodemserconstruídasapartirdeumnúmeromoderadodeelementos básicos, como linhas verticais e horizontais e algumas curvas. Crie

Page 66: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

um alfabeto que possa ser desenhado com um número mínimo de elementosbásicoseentãoescrevafunçõesquedesenhemasletras.

Vocêdeveescreverumafunçãoparacadaletra,comosnomesdraw_a,draw_betc.,ecolocarsuasfunçõesemumarquivochamadoletters.py.Vocêpodebaixaruma “máquina de escrever de turtle” no sitehttp://thinkpython2.com/code/typewriter.pyparaajudaratestaroseucódigo.

Vocêpodeverumasoluçãonositehttp://thinkpython2.com/code/letters.py;elatambémexigehttp://thinkpython2.com/code/polygon.py.

Exercício4.5

Leia sobre espirais em https://pt.wikipedia.org/wiki/Espiral; então escreva umprogramaquedesenheumaespiraldeArquimedes(ouumdosoutrostipos).

[1] _turtle graphics_ ou gráficos de tartaruga é o sistema de desenhopopularizadopela linguagemLogo,ondeoscomandosmovimentamumcursortriangular pela tela, conhecido como turtle ou tartaruga.A tartaruga deixa umrastro à medida que é movimentada, e é com esses rastros que se forma umdesenho. Diferente dos sistemas usuais de desenho em computação gráfica, osistematurtlegraphicsnãoexigeousodecoordenadascartesianas.

Page 67: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo5:CondicionaiserecursividadeOtópicoprincipaldestecapítuloéainstruçãoif,queexecutacódigosdiferentesdependendodoestadodoprograma.Masprimeiroqueroapresentardoisnovosoperadores:divisãopelopisoemódulo.

5.1-Divisãopelopisoemódulo

Ooperadordedivisãopelopiso,//,dividedoisnúmerosearredondaoresultadopara um número inteiro para baixo. Por exemplo, suponha que o tempo deexecuçãodeumfilmesejade105minutos.Vocêpodequerersaberaquantoissocorresponde em horas. A divisão convencional devolve um número de pontoflutuante:

>>>minutes=105

>>>minutes/60

1.75

Mas não é comum escrever horas com pontos decimais. A divisão pelo pisodevolveonúmerointeirodehoras,ignorandoapartefracionária:

>>>minutes=105

>>>hours=minutes//60

>>>hours

1

Paraobteroresto,vocêpodesubtrairumahoraemminutos:

>>>remainder=minutes-hours*60

>>>remainder

45

Uma alternativa é usar o operador módulo, %, que divide dois números edevolveoresto:

>>>remainder=minutes%60

>>>remainder

Page 68: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

45

Ooperadormóduloémaisútildoqueparece.Porexemplo,épossívelverificarseumnúmeroédivisívelporoutro–sex%yforzero,entãoxédivisívelpory.

Alémdisso,vocêpodeextrairodígitooudígitosmaisàdireitadeumnúmero.Porexemplo,x%10produzodígitomaisàdireitadex(nabase10).Damesmaformax%100produzosdoisúltimosdígitos.

SeestiverusandooPython2,adivisãofuncionadeformadiferente.Ooperadordedivisão,/,executaadivisãopelopisoseambososoperandosforemnúmerosinteirosefazadivisãodepontoflutuantesepelomenosumdosoperandosfordotipofloat.

5.2-Expressõesbooleanas

Umaexpressãobooleanaéumaexpressãoquepodeserverdadeiraoufalsa.Osexemplosseguintesusamooperador==,quecomparadoisoperandoseproduzTrueseforemiguaiseFalsesenãoforem:

>>>5==5

True

>>>5==6

False

TrueeFalsesãovaloresespeciaisquepertencemaotipobool;nãosãostrings:

>>>type(True)

<class'bool'>

>>>type(False)

<class'bool'>

Ooperador==éumdosoperadoresrelacionais;osoutrossão:

x!=y#xnãoéigualay

x>y#xémaiorquey

x<y#xémenorquey

x>=y#xémaiorouigualay

x<=y#xémenorouigualay

Emboraessasoperaçõesprovavelmentesejamfamiliaresparavocê,ossímbolosdo Python são diferentes dos símbolos matemáticos. Um erro comum é usar

Page 69: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

apenasumsinaldeigual(=)emvezdeumsinalduplo(==).Lembre-sedeque=éumoperadordeatribuiçãoe==éumoperadorrelacional.Nãoexiste=<ou=>.

5.3-Operadoreslógicos

Há três operadores lógicos: and, or e not. A semântica (significado) destesoperadoresésemelhanteaoseusignificadoeminglês.Porexemplo,x>0andx<10sóéverdadesexformaiorque0emenorque10.

n%2==0orn%3==0éverdadeiroseumaouasduascondição(ões)for(em)verdadeira(s),istoé,seonúmerofordivisívelpor2ou3.

Finalmente, ooperadornot negaumaexpressãobooleana, entãonot (x>y) éverdadesex>yforfalso,istoé,sexformenorqueouigualay.

Falandoestritamente,osoperandosdosoperadoreslógicosdevemserexpressõesbooleanas,masoPythonnãoémuitoestrito.QualquernúmeroquenãosejazeroéinterpretadocomoTrue:

>>>42andTrue

True

Estaflexibilidadetemsuautilidade,masháalgumassutilezasrelativasaelaquepodemserconfusas.Assim,podeserumaboaideiaevitá-la(amenosquesaibaoqueestáfazendo).

5.4-Execuçãocondicional

Para escrever programas úteis, quase sempre precisamos da capacidade deverificarcondiçõesemudarocomportamentodoprogramadeacordocomelas.Instruções condicionais nos dão esta capacidade. A forma mais simples é ainstruçãoif:

ifx>0:

print('xispositive')

Aexpressãobooleanadepoisdoiféchamadadecondição.Seforverdadeira,ainstruçãoendentadaéexecutada.Senão,nadaacontece.

Page 70: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Instruções if têm a mesma estrutura que definições de função: um cabeçalhoseguido de um corpo endentado. Instruções como essa são chamadas deinstruçõescompostas.

Nãohá limiteparaonúmerode instruçõesquepodemaparecernocorpo,masdevehaverpelomenosuma.Ocasionalmente,éútilterumcorposeminstruções(normalmentecomoumespaçoreservadoparacódigoqueaindanãofoiescrito).Nestecaso,vocêpodeusarainstruçãopass,quenãofaznada.

ifx<0:

pass#AFAZER:lidarcomvaloresnegativos!

5.5-Execuçãoalternativa

Umasegundaformadainstruçãoiféa“execuçãoalternativa”,naqualháduaspossibilidades e a condiçãodeterminaqual será executada.A sintaxe pode seralgoassim:

ifx%2==0:

print('xiseven')

else:

print('xisodd')

Se o resto quando x for dividido por 2 for 0, então sabemos que x é par e oprograma exibe umamensagem adequada. Se a condição for falsa, o segundoconjunto de instruções é executado. Como a condição deve ser verdadeira oufalsa, exatamente uma das alternativas será executada. As alternativas sãochamadasderamos(branches),porquesãoramosnofluxodaexecução.

5.6-Condicionaisencadeadas

Àsvezes,hámaisdeduaspossibilidadeseprecisamosdemaisquedoisramos.Esta forma de expressar uma operação de computação é uma condicionalencadeada:

ifx<y:

print('xislessthany')

elifx>y:

print('xisgreaterthany')

else:

Page 71: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

print('xandyareequal')

elif é uma abreviatura de “else if”. Novamente, exatamente um ramo seráexecutado.Nãohánenhum limiteparaonúmerode instruçõeselif.Sehouverumacláusulaelse,eladeveestarnofim,masnãoéprecisohaveruma.

ifchoice=='a':

draw_a()

elifchoice=='b':

draw_b()

elifchoice=='c':

draw_c()

Cada condição é verificada em ordem. Se a primeira for falsa, a próxima éverificada, e assim por diante. Se uma delas for verdadeira, o ramocorrespondenteéexecutadoea instruçãoéencerrada.Mesmosemaisdeumacondiçãoforverdade,sóoprimeiroramoverdadeiroéexecutado.

5.7-Condicionaisaninhadas

Uma condicional também pode ser aninhada dentro de outra. Poderíamos terescritooexemplonaseçãoanteriordestaforma:

ifx==y:

print('xandyareequal')

else:

ifx<y:

print('xislessthany')

else:

print('xisgreaterthany')

A condicional exterior contém dois ramos. O primeiro ramo contém umainstrução simples. O segundo ramo contém outra instrução if, que tem outrosdoisramospróprios.Essesdoisramossãoinstruçõessimples,emborapudessemserinstruçõescondicionaistambém.

Embora a endentação das instruções evidencie a estrutura das condicionais,condicionaisaninhadassãodifíceisdelerrapidamente.Éumaboaideiaevitá-lasquandoforpossível.

Operadoreslógicosmuitasvezesoferecemumaformadesimplificarinstruções

Page 72: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

condicionais aninhadas. Por exemplo, podemos reescrever o seguinte códigousandoumaúnicacondicional:

if0<x:

ifx<10:

print('xisapositivesingle-digitnumber.')

A instrução print só é executada se a colocarmos depois de ambas ascondicionais,entãopodemosobteromesmoefeitocomooperadorand:

if0<xandx<10:

print('xisapositivesingle-digitnumber.')

Paraestetipodecondição,oPythonofereceumaopçãomaisconcisa:

if0<x<10:

print('xisapositivesingle-digitnumber.')

5.8-Recursividade

Élegalparaumafunçãochamaroutra;tambémélegalparaumafunçãochamarasiprópria.Podenãoseróbvioporqueissoéumacoisaboa,masnaverdadeéumadascoisasmaismágicasqueumprogramapodefazer.Porexemplo,vejaaseguintefunção:

defcountdown(n):

ifn<=0:

print('Blastoff!')

else:

print(n)

countdown(n-1)

Senfor0ounegativo,apalavra“Blastoff!”éexibida,senãoasaídaéneentãoafunçãocountdownéchamada–porsimesma–passandon-1comoargumento.

Oqueacontecesechamarmosestafunçãoassim?

>>>countdown(3)

Aexecuçãodecountdowniniciacomn=3ecomonémaiorque0,elaproduzovalor3eentãochamaasimesma...

Page 73: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Aexecuçãodecountdowniniciacomn=2ecomonémaiorque0,elaproduzovalor2eentãochamaasimesma...

Aexecuçãodecountdown iniciacomn=1ecomonémaiorque0,elaproduzovalor1eentãochamaasimesma...

Aexecuçãodecountdowniniciacomn=0ecomonnãoémaiorque0,elaproduzapalavra“Blastoff!”eentãoretorna.

Ocountdownquerecebeun=1retorna.

Ocountdownquerecebeun=2retorna.

Ocountdownquerecebeun=3retorna.

Eentãovocêestádevoltaao__main__.Entãoasaídacompletaseráassim:

3

2

1

Blastoff!

Umafunçãoquechamaasimesmaéditarecursiva;oprocessoparaexecutá-laéarecursividade.

Comoemoutroexemplo,podemosescreverumafunçãoqueexibaumastringnvezes:

defprint_n(s,n):

ifn<=0:

return

print(s)

print_n(s,n-1)

Sen<=0ainstruçãoreturncausaasaídadafunção.Ofluxodeexecuçãovoltaimediatamente a quem fez a chamada, e as linhas restantes da funçãonão sãoexecutadas.

Orestodafunçãoésimilaràcountdown:elamostraseentãochamaasimesmaparamostrarsmaisn-1vezes.Entãoonúmerodelinhasdasaídaé1+(n-1),atéchegaran.

Page 74: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Paraexemplossimplescomoesse,provavelmenteémaisfácilusarumloopfor.Maisadianteveremosexemplosquesãodifíceisdeescrevercomumloopforefáceisdeescrevercomrecursividade,entãoébomcomeçarcedo.

5.9-Diagramasdapilhaparafunçõesrecursivas

Em “Diagrama da pilha”, na página 55, usamos um diagrama da pilha pararepresentaroestadodeumprogramaduranteumachamadadefunção.Omesmotipodediagramapodeajudarainterpretarumafunçãorecursiva.

Cada vez que uma função é chamada, o Python cria um frame para conter asvariáveislocaiseparâmetrosdafunção.Paraumafunçãorecursiva,podehavermaisdeumframenapilhaaomesmotempo.

AFigura5.1mostraumdiagramadapilhaparacountdownchamadocomn=3.

Figura5.1–Diagramadapilha.

Comodehábito,otopodapilhaéoframede__main__.Estávazioporquenãocriamosnenhumavariávelem__main__nempassamosargumentosaela.

Os quatro frames do countdown têmvalores diferentes para o parâmetron. Ofundo da pilha, onden=0, é chamado caso-base. Ele não faz uma chamadarecursiva,entãonãohámaisframes.

Comoexercício,desenheumdiagramadapilhaparaprint_nchamadocoms='Hello'en=2.Entãoescrevaumafunçãochamadado_nquetomeumobjetodefunçãoeumnúmeroncomoargumentosequechamearespectivafunçãon

Page 75: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

vezes.

5.10-Recursividadeinfinita

Se a recursividade nunca atingir um caso-base, continua fazendo chamadasrecursivas para sempre, e o programa nunca termina. Isso é conhecido comorecursividadeinfinitaegeralmentenãoéumaboaideia.Aquiestáumprogramamínimocomrecursividadeinfinita:

defrecurse():

recurse()

Namaiorpartedosambientesdeprogramação,umprogramacomrecursividadeinfinitanãoérealmenteexecutadoparasempre.OPythonexibeumamensagemdeerroquandoaprofundidademáximaderecursividadeéatingida:

File"<stdin>",line2,inrecurse

File"<stdin>",line2,inrecurse

File"<stdin>",line2,inrecurse

.

.

.

File"<stdin>",line2,inrecurse

RuntimeError:Maximumrecursiondepthexceeded

Estetracebackéumpoucomaiorqueoquevimosnocapítuloanterior.Quandooerroocorre,hámilframesderecursenapilha!

Sevocêescreveremrecursividade infinitaporengano,confiraseasuafunçãotemumcaso-base quenão faz uma chamada recursiva.E se houver umcaso-base,verifiquesevocêvaimesmoatingi-lo.

5.11-Entradadeteclado

Osprogramasqueescrevemosatéagoranãoaceitamentradasdousuário.Elessemprefazemamesmacoisacadavez.

O Python fornece uma função integrada chamada input que interrompe oprogramaeesperaqueousuáriodigitealgo.QuandoousuáriopressionarReturnou Enter, o programa volta a ser executado e input retorna o que o usuário

Page 76: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

digitoucomoumastring.NoPython2,amesmafunçãoéchamadaraw_input.

>>>text=input()

Whatareyouwaitingfor?

>>>text

Whatareyouwaitingfor?

Antesdereceberentradasdousuário,éumaboaideiaexibirumpromptdizendoaousuáriooqueeledevedigitar.inputpodeterumpromptcomoargumento:

>>>name=input('What...isyourname?\\n')

What...isyourname?

Arthur,KingoftheBritons!

>>>name

Arthur,KingoftheBritons!

Asequência\nno finaldoprompt representaumnewline,queéumcaractereespecialdequebradelinha.Éporissoqueaentradadousuárioapareceabaixodoprompt.

Seesperarqueousuáriodigiteumnúmerointeiro,vocêpodetentarconverterovalorderetornoparaint:

>>>prompt='What...istheairspeedvelocityofanunladenswallow?

>>>speed=input(prompt)

What...istheairspeedvelocityofanunladenswallow?

42

>>>int(speed)

42

Masseousuáriodigitaralgoalémdeumasériededígitos,vocêrecebeumerro:

>>>speed=input(prompt)

What...istheairspeedvelocityofanunladenswallow?

Whatdoyoumean,anAfricanoraEuropeanswallow?

>>>int(speed)

ValueError:invalidliteralforint()withbase10

Veremoscomotratarestetipodeerromaisadiante.

5.12-Depuração

Quando um erro de sintaxe ou de tempo de execução ocorre, amensagem de

Page 77: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

erro contémmuita informação, às vezes, até demais.As partesmais úteis sãonormalmente:

quetipodeerrofoi;

ondeocorreu.

Erros de sintaxe são normalmente fáceis de encontrar, mas há algumaspegadinhas. Erros dewhitespace podem ser complicados porque os espaços etabulaçõessãoinvisíveiseestamosacostumadosaignorá-los.

>>>x=5

>>>y=6

File"<stdin>",line1

y=6

^

IndentationError:unexpectedindent

Nesteexemplo,oproblemaéqueasegundalinhaestáendentadaporumespaço.Mas a mensagem de erro aponta para y, o que pode ser capcioso. Em geral,mensagensdeerroindicamondeoproblemafoidescoberto,masoerrorealpodeestaremoutrapartedocódigo,àsvezes,emumalinhaanterior.

Omesmoacontececomerrosemtempodeexecução.Suponhaquevocêestejatentandocalcularaproporçãodesinalaruídoemdecibéis.AfórmulaéSNRdb=10log10(Psignal/Pnoise).NoPython,vocêpoderiaescreveralgoassim:

importmath

signal_power=9

noise_power=10

ratio=signal_power//noise_power

decibels=10*math.log10(ratio)

print(decibels)

Aoexecutaresteprograma,vocêrecebeumaexceção:

Traceback(mostrecentcalllast):

File"snr.py",line5,in?

decibels=10*math.log10(ratio)

ValueError:mathdomainerror

Amensagemdeerroindicaalinha5,masnãohánadadeerradocomestalinha.Umaopçãoparaencontraroverdadeiroerroéexibirovalorderatio,queacaba

Page 78: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

sendo 0. O problema está na linha 4, que usa a divisão pelo piso em vez dadivisãodepontoflutuante.

Éprecisolerasmensagensdeerrocomatenção,masnãoassumirquetudoquedizemestejacorreto.

5.13-Glossário

divisãopelopisoUm operador, denotado por //, que divide dois números e arredonda oresultadoparabaixo(emdireçãoaozero),aumnúmerointeiro.

operadormóduloUmoperador, denotado comum sinal de percentagem (%), que funcionacomnúmerosinteirosedevolveorestoquandoumnúmeroédivididoporoutro.

expressãobooleanaUmaexpressãocujovaloréTrue(verdadeiro)ouFalse(falso).

operadorrelacionalUmdestesoperadores,quecomparaseusoperandos:==,!=,>,<,>=e<=.

operadorlógicoUmdestesoperadores,quecombinaexpressõesbooleanas:and(e),or(ou)enot(não).

instruçãocondicionalUma instrução que controla o fluxo de execução, dependendo de algumacondição.

condiçãoA expressão booleana em uma instrução condicional que determina qualramodeveserexecutado.

instruçãocompostaUmainstruçãocompostadeumcabeçalhoeumcorpo.Ocabeçalhoterminaemdoispontos(:).Ocorpoéendentadoemrelaçãoaocabeçalho.

ramoUma das sequências alternativas de instruções em uma instruçãocondicional.

condicionalencadeadaUmainstruçãocondicionalcomumasériederamosalternativos.

condicionalaninhadaUma instrução condicional que aparece em um dos ramos de outra

Page 79: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

instruçãocondicional.instruçãoderetorno

Umainstruçãoquefazumafunçãoterminarimediatamenteevoltaraquemachamou.

recursividadeOprocessodechamarafunçãoqueestásendoexecutadanomomento.

caso-baseUmramocondicionalemumafunçãorecursivaquenãofazumachamadarecursiva.

recursividadeinfinitaRecursividade que não tem um caso-base, ou nunca o atinge. Arecursividadeinfinitaeventualmentecausaumerroemtempodeexecução.

5.14-Exercícios

Exercício5.1

Omódulotimeforneceumafunção,tambémchamadatime,quedevolveaHoraMédia de Greenwich na “época”, que é um momento arbitrário usado comopontodereferência.EmsistemasUNIX,aépocaéprimeirodejaneirode1970.

>>>importtime

>>>time.time()

1437746094.5735958

Escreva um script que leia a hora atual e a converta emum tempo emhoras,minutosesegundos,maisonúmerodediasdesdeaépoca.

Exercício5.2

OúltimoteoremadeFermatdizquenãoexistemnúmerosinteirosa,bectaisquea**n+b**n==c**nparaquaisquervaloresdenmaioresque2.

1. Escrevaumafunçãochamadacheck_fermatquerecebaquatroparâmetros–a,b,cen–everifiqueseoteoremadeFermatsemantém.Senformaiorque2ea**n+b**n==c**noprogramadeveimprimir,“Holysmokes,Fermat was wrong!” Senão o programa deve exibir “No, that doesn’twork.”

Page 80: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

2. Escrevaumafunçãoquepeçaaousuárioparadigitarvaloresparaa,b,cen, os converta em números inteiros e use check_fermat para verificar seviolamoteoremadeFermat.

Exercício5.3

Sevocêtivertrêsgravetos,podeserqueconsigaarranjá-losemumtriânguloounão. Por exemplo, se um dos gravetos tiver 12 polegadas de comprimento eoutrosdoistiveremumapolegadadecomprimento,nãoserápossívelfazercomqueosgravetoscurtosseencontremnomeio.Háumtestesimplesparaverseépossívelformarumtriânguloparaquaisquertrêscomprimentos:

Se algumdos três comprimentos formaior que a somados outros dois, entãovocê não pode formar um triângulo. Senão, você pode. (Se a soma de doiscomprimentos igualar o terceiro, eles formam um triângulo chamado“degenerado”.)

1. Escreva uma função chamada is_triangle que receba três númerosinteiroscomoargumentos,eque imprima“Yes”ou“No”,dependendodapossibilidade de formar ou não um triângulo de gravetos com oscomprimentosdados.

2. Escrevaumafunçãoquepeçaaousuárioparadigitartrêscomprimentosdegravetos,osconvertaemnúmerosinteiroseuseis_triangleparaverificarseosgravetoscomoscomprimentosdadospodemformarumtriângulo.

Exercício5.4

Qualéasaídadoseguinteprograma?Desenheumdiagramadapilhaquemostreoestadodoprogramaquandoexibiroresultado.

defrecurse(n,s):

ifn==0:

print(s)

else:

recurse(n-1,n+s)

recurse(3,0)

1. O que aconteceria se você chamasse esta função desta forma: recurse(-1,

Page 81: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

0)?

2. Escreva uma docstring que explique tudo o que alguém precisaria saberparausarestafunção(emaisnada).

Osseguintesexercíciosusamomóduloturtle,descritonoCapítulo4:

Exercício5.5

Leiaapróxima funçãoeveja seconseguecompreenderoqueela faz (vejaosexemplosnoCapítulo4).Entãoexecute-aevejaseacertou.

defdraw(t,length,n):

ifn==0:

return

angle=50

t.fd(length*n)

t.lt(angle)

draw(t,length,n-1)

t.rt(2*angle)

draw(t,length,n-1)

t.lt(angle)

t.bk(length*n)

Exercício5.6

Figura5.2–UmacurvadeKoch.

AcurvadeKochéum fractal queparece comodaFigura5.2.ParadesenharumacurvadeKochcomocomprimentox,tudooquevocêtemquefazeré:

1. DesenheumacurvadeKochcomocomprimentox/3.

Page 82: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

2. Vire60grausàesquerda.

3. DesenheumacurvadeKochcomocomprimentox/3.

4. Vire120grausàdireita.

5. DesenheumacurvadeKochcomocomprimentox/3.

6. Vire60grausàesquerda.

7. DesenheumacurvadeKochcomocomprimentox/3.

Aexceçãoésexformenorque3:nestecaso,vocêpodedesenharapenasumalinharetacomocomprimentox.

1. Escrevaumafunçãochamadakochquerecebaumturtleeumcomprimentocomoparâmetros,euseo turtleparadesenharumacurvadeKochcomocomprimentodado.

2. EscrevaumafunçãochamadasnowflakequedesenhetrêscurvasdeKochparafazerotraçadodeumflocodeneve.

Solução:http://thinkpython2.com/code/koch.py.

3. AcurvadeKochpodesergeneralizadadeváriosmodos.Vejaexemplosemhttp://en.wikipedia.org/wiki/Koch_snowflakeeimplementeoseufavorito.

Page 83: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo6:FunçõescomresultadoMuitas das funções do Python que usamos, como as matemáticas, produzemvalores de retorno.Mas as funçõesque escrevemos até agora são todasnulas:têmumefeito,comoexibirumvaloroumoverumatartaruga,masnãotêmumvalor de retorno. Neste capítulo você aprenderá a escrever funções comresultados.

6.1-Valoresderetorno

Achamadadefunçãogeraumvalorderetorno,quenormalmenteatribuímosaumavariávelouusamoscomopartedeumaexpressão.

e=math.exp(1.0)

height=radius*math.sin(radians)

As funções que descrevemos, por enquanto, são todas nulas. Resumindo, elasnãotêmvaloresderetorno;maisprecisamente,oseuvalorderetornoéNone.

Nestecapítuloveremos (finalmente)comoescrever funçõescomresultados.Oprimeiroexemploéarea,quedevolveaáreadeumcírculocomoraiodado:

defarea(radius):

a=math.pi*radius**2

returna

Jávimosa instrução return,masemumafunçãocomresultadoela incluiumaexpressão.Esta instrução significa: “Volte imediatamentedesta função e use aseguinteexpressãocomovalorderetorno”.Aexpressãopodeserarbitrariamentecomplicada,entãopoderíamosterescritoestafunçãodeformamaisconcisa:

defarea(radius):

returnmath.pi*radius**2

Poroutrolado,variáveistemporáriascomoa,tornamadepuraçãomaisfácil.

Às vezes, é útil ter várias instruções de retorno, uma em cada ramo de umacondicional:

Page 84: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

defabsolute_value(x):

ifx<0:

return-x

else:

returnx

Comoessasinstruçõesreturnestãoemumacondicionalalternativa,apenasumaéexecutada.

Logo que uma instrução de retorno seja executada, a função termina semexecutar nenhuma instrução subsequente.Qualquer código que apareça depoisdeuma instrução return, ou emqualquer outro lugar queo fluxoda execuçãonãoatinja,échamadodecódigomorto.

Em uma função com resultado, é uma boa ideia garantir que cada caminhopossívelpeloprogramaatinjaumainstruçãoreturn.Porexemplo:

defabsolute_value(x):

ifx<0:

return-x

ifx>0:

returnx

Essa função é incorreta porque se x for 0, nenhuma condição é verdade, e afunção termina sem chegar a uma instrução return. Se o fluxo de execuçãochegar ao fim de uma função, o valor de retorno é None, que não é o valorabsolutode0:

>>>absolute_value(0)

None

Apropósito,oPythonofereceuma função integradachamadaabs,quecalculavaloresabsolutos.

Comoexercício,escrevaumafunçãocomparequerecebadoisvalores,xey,eretorne1sex>y,0sex==ye-1sex<y.

6.2-Desenvolvimentoincremental

Conforme você escrever funções maiores, pode ser que passe mais tempo asdepurando.

Page 85: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Para lidar com programas cada vezmais complexos, você pode querer tentarusar um processo chamado de desenvolvimento incremental. A meta dodesenvolvimento incremental é evitar longas sessões de depuração,acrescentandoetestandopequenaspartesdocódigodecadavez.

Como um exemplo, vamos supor que você queira encontrar a distância entredois pontos dados pelas coordenadas (x1, y1) e(x2, y2). Pelo teorema dePitágoras,adistânciaé:

Fórmula–Distânciaentredoispontos.

OprimeiropassoépensarcomoumafunçãodistancedeveriasernoPython.Emoutras palavras, quais são as entradas (parâmetros) e qual é a saída (valor deretorno)?

Nessecaso,asentradassãodoispontosquevocêpoderepresentarusandoquatronúmeros.Ovalorde retornoé adistância representadaporumvalordepontoflutuante.

Imediatamente,épossívelescreverumrascunhodafunção:

defdistance(x1,y1,x2,y2):

return0.0

Claro que esta versão não calcula distâncias; sempre retorna zero. Mas estásintaticamentecorreta,epodeserexecutada,oquesignificaquevocêpodetestá-laantesdetorná-lamaiscomplicada.

Paratestaranovafunção,chame-acomargumentosdeamostra:

>>>distance(1,2,4,6)

0.0

Escolhiessesvaloresparaqueadistânciahorizontalseja3eadistânciavertical,4;assim,oresultadofinalé5,ahipotenusadeumtriângulo3-4-5.Aotestarumafunção,éútilsaberarespostacerta.

Nestepontoconfirmamosquea funçãoestá sintaticamentecorreta, epodemoscomeçaraacrescentarcódigoaocorpo.Umpróximopassorazoáveléencontrar

Page 86: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

as diferenças x2 − x1 e y2 − y1. A próxima versão guarda esses valores emvariáveistemporáriaseosexibe:

defdistance(x1,y1,x2,y2):

dx=x2-x1

dy=y2-y1

print('dxis',dx)

print('dyis',dy)

return0.0

Se a função estiver funcionando, deve exibir dx is 3 e dy is 4. Nesse casosabemos que a função está recebendo os argumentos corretos e executando oprimeirocálculoacertadamente.Senão,hápoucaslinhasparaverificar.

Depoiscalculamosasomadosquadradosdedxedy:

defdistance(x1,y1,x2,y2):

dx=x2-x1

dy=y2-y1

dsquared=dx**2+dy**2

print('dsquaredis:',dsquared)

return0.0

Nestaetapavocêexecutariaoprogramamaisumavezeverificariaasaída(quedeve ser 25). Finalmente, pode usar math.sqrt para calcular e devolver oresultado:

defdistance(x1,y1,x2,y2):

dx=x2-x1

dy=y2-y1

dsquared=dx**2+dy**2

result=math.sqrt(dsquared)

returnresult

Sefuncionarcorretamente,pronto.Senão,umaideiaéexibirovalorresultantesdainstruçãoderetorno.

A versão final da função não exibe nada ao ser executada; apenas retorna umvalor.As instruçõesprintqueescrevemossãoúteisparadepuração,masassimque conferir se a função está funcionando você deve retirá-las.Códigos dessetipo são chamados de scaffolding (andaime) porque são úteis para construir oprograma,masnãosãopartedoprodutofinal.

Page 87: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Aocomeçar, vocêdeveria acrescentar apenasuma linhaouduasde códigodecada vez. Conforme adquira mais experiência, poderá escrever e depurarparcelas maiores. De qualquer forma, o desenvolvimento incremental podeeconomizarmuitotempodedepuração.

Osprincipaisaspectosdoprocessosão:

1. Comece com um programa que funcione e faça pequenas alteraçõesincrementais. Se houver um erro emqualquer ponto, será bemmais fácilencontrá-lo.

2. Usevariáveisparaguardarvaloresintermediários,assimpoderáexibi-loseverificá-los.

3. Uma vez que o programa esteja funcionando, você pode querer removeruma parte do scaffolding ou consolidar várias instruções em expressõescompostas,masapenasseissonãotornaroprogramadifícildeler.

Comoexercício,useodesenvolvimento incrementalparaescreveruma funçãochamadahypotenuse,quedevolvaocomprimentodahipotenusadeumtriânguloretângulo dados os comprimentos dos outros dois lados como argumentos.Registrecadaetapadoprocessodedesenvolvimentonodecorrerdoprocesso.

6.3-Composição

Comovocê já deveria esperar a essa altura, é possível chamar uma funçãodedentro de outra. Como exemplo, escreveremos uma função que recebe doispontos, o centro do círculo e um ponto no perímetro, para calcular a área docírculo.

Suponhaqueopontodocentrosejaguardadonasvariáveisxceyceopontodeperímetroestáemxpeyp.Oprimeiropassodeveserencontraroraiodocírculo,que é a distância entre os dois pontos. Acabamos de escrever uma função,distance,quefazisto:

radius=distance(xc,yc,xp,yp)

O próximo passo deve ser encontrar a área de um círculo com aquele raio;acabamosdeescreverissotambém:

Page 88: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

result=area(radius)

Encapsulandoessespassosemumafunção,temos:

defcircle_area(xc,yc,xp,yp):

radius=distance(xc,yc,xp,yp)

result=area(radius)

returnresult

As variáveis temporárias radius e result são úteis para desenvolvimento edepuração,eumavezqueoprogramaestejafuncionandopodemostorná-lomaisconcisocompondochamadasdefunção:

defcircle_area(xc,yc,xp,yp):

returnarea(distance(xc,yc,xp,yp))

6.4-Funçõesbooleanas

Asfunçõespodemretornarbooleans,oquepodeserconvenienteparaescondertestescomplicadosdentrodefunções.Porexemplo:

defis_divisible(x,y):

ifx%y==0:

returnTrue

else:

returnFalse

É comum dar nomes de funções booleanas que pareçam perguntas de sim ounão;is_divisibleretornaTrueouFalseparaindicarsexédivisívelpory.

Aquiestáumexemplo:

>>>is_divisible(6,4)

False

>>>is_divisible(6,3)

True

Oresultadodooperador==éumbooleano,entãopodemosescreverafunçãodeformamaisconcisa,retornando-odiretamente:

defis_divisible(x,y):

returnx%y==0

Page 89: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Asfunçõesbooleanasmuitasvezessãousadaseminstruçõescondicionais:

ifis_divisible(x,y):

print('xisdivisiblebyy')

Podesertentadorescreveralgoassim:

ifis_divisible(x,y)==True:

print('xisdivisiblebyy')

Masacomparaçãoextraédesnecessária.

Como um exercício, escreva uma função is_between(x, y, z) que retorneTrue,sex≤y≤z,ouFalse,senãoforocaso.

6.5-Maisrecursividade

CobrimosapenasumpequenosubconjuntodoPython,mastalvezsejabomvocêsaberqueestesubconjuntoéumalinguagemdeprogramaçãocompleta,ouseja,qualquer coisa que possa ser calculada pode ser expressa nesta linguagem.Qualquerprogramaquejáfoiescritopodeserreescritoapenascomosrecursosda linguagem que você aprendeu até agora (na verdade, seria preciso algunscomandos para dispositivos de controle como mouse, discos etc., mas isso étudo).

Comprovar esta declaração é umexercícionada trivial realizadopela primeiravezporAlanTuring,umdosprimeiroscientistasdacomputação(algunsdiriamque ele foi matemático, mas muitos dos primeiros cientistas da computaçãocomeçaram como matemáticos). Assim, é conhecida como a Tese de Turing.Para uma exposiçãomais completa (e exata) daTese deTuring, recomendo olivrodeMichaelSipser,IntroductiontotheTheoryofComputation(Introduçãoàteoriadacomputação,CourseTechnology,2012).

Paradarumaideiadoquepodemosfazercomasferramentasqueaprendeuatéagora,avaliaremosalgumasfunçõesmatemáticasdefinidasrecursivamente.Umadefinição recursivaé semelhanteaumadefiniçãocircular,nosentidodequeadefinição contém uma referência à coisa que é definida. Uma definiçãorealmentecircularnãoémuitoútil:

vorpal

Page 90: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Adjetivousadoparadescreveralgoqueévorpal.

Ver uma definição assim no dicionário pode ser irritante. Por outro lado, seprocuraradefiniçãodafunçãodefatorial,denotadapelosímbolo!,vocêpodeencontraralgoassim:

0!=1

n!=n·(n−1)!

Estadefiniçãodizqueofatorialde0é1,eofatorialdequalqueroutrovalor,n,énmultiplicadopelofatorialden-1.

Então3!é3vezes2!,queé2vezes1!,queé1vez0!.Juntandotudo,3!éiguala3vezes2vezes1vezes1,queé6.

Se puder escrever uma definição recursiva de algo, você poderá escrever umprograma em Python que a avalie. O primeiro passo deve ser decidir quaisparâmetros ela deve ter. Neste caso, deve estar claro que factorial recebe umnúmerointeiro:

deffactorial(n):

Seoargumentofor0,tudoquetemosdefazeréretornar1:

deffactorial(n):

ifn==0:

return1

Senão,eaíéqueficainteressante,temosquefazerumachamadarecursivaparaencontrarofatorialden-1eentãomultiplicá-loporn:

deffactorial(n):

ifn==0:

return1

else:

recurse=factorial(n-1)

result=n*recurse

returnresult

O fluxode execuçãodeste programa é semelhante ao fluxode countdownem“Recursividade”,napágina81.Sechamarmosfactorialcomovalor3:

Page 91: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Como3nãoé0,tomamososegundoramoecalculamosofatorialden-1...

Como2nãoé0,tomamososegundoramoecalculamosofatorialden-1...

Como1nãoé0,tomamososegundoramoecalculamosofatorialden-1...

Como0éiguala0,tomamosoprimeiroramoedevolvemos1semfazermaischamadasrecursivas.

O valor de retorno, 1, é multiplicado por n, que é 1, e o resultado édevolvido.

Ovalorderetorno,1,émultiplicadoporn,queé2,eoresultadoédevolvido.

Ovalordevolvido(2)émultiplicadoporn,queé3,eoresultado,6,torna-seovalordevolvidopelachamadadefunçãoquecomeçouoprocessointeiro.

A Figura 6.1 mostra como é o diagrama da pilha para esta sequência dechamadasdefunção.

Figura6.1–Diagramadapilhaparafactorial.

Osvaloresdevolvidos sãomostradosao serempassadosdevoltaatéoaltodapilha.Emcadaframe,ovalordevolvidoéovalorderesult,queéoprodutodenerecurse.

Noúltimoframe,asvariáveislocaisrecurseeresultnãoexistem,porqueoramoqueoscrianãoéexecutado.

Page 92: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

6.6-Saltodefé

Seguir o fluxo da execução é uma forma de ler programas, mas poderá sertrabalhoso demais. Uma alternativa é o que chamo de “salto de fé” (leap offaith). Ao chegar a uma chamada de função, em vez de seguir o fluxo deexecução suponha que a função esteja funcionando corretamente e que estáretornandooresultadocerto.

Na verdade, você já está praticando este salto de fé quando usa funçõesintegradas. Quando chama math.cos ou math.exp, você não examina o corpodessas funções. Apenas supõe que funcionem porque as pessoas que asescreveramerambonsprogramadores.

Omesmoaconteceaochamarumadassuasprópriasfunções.Porexemplo,em“Funções booleanas”, na página 97, escrevemos uma função chamadais_divisible que determina se um número é divisível por outro. Uma vez queestejamosconvencidosdequeestafunçãoestácorreta–examinandoocódigoetestando–podemosusarafunçãosemverocorponovamente.

O mesmo é verdade para programas recursivos. Quando chega à chamadarecursiva, em vez de seguir o fluxo de execução, você deveria supor que achamadarecursivafuncione(devolvaoresultadocorreto)eentãoperguntar-se:“Supondoqueeupossaencontrarofatorialden-1,possocalcularofatorialden?”.Éclaroquepode,multiplicandoporn.

Naturalmente, éumpoucoestranho suporque a função funcione corretamentequandoaindanãoterminoudeescrevê-la,maséporissoquesechamaumsaltodefé!

6.7-Maisumexemplo

Depoisdofactorial,oexemplomaiscomumdeumafunçãomatemáticadefinidarecursivamente é fibonacci, que tem a seguinte definição (verhttp://en.wikipedia.org/wiki/Fibonacci_number):

fibonacci(0)=0

fibonacci(1)=1

fibonacci(n)=fibonacci(n−1)+fibonacci(n−2)

Page 93: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

TraduzidaparaPython,elaficaassim:

deffibonacci(n):

ifn==0:

return0

elifn==1:

return1

else:

returnfibonacci(n-1)+fibonacci(n-2)

Se tentar seguir o fluxo de execução aqui, até para valores razoavelmentepequenosden,suacabeçaexplode.Porém,seguindoosaltodefé,supondoqueas duas chamadas recursivas funcionem corretamente, então é claro que vaireceberoresultadocorretoadicionando-asjuntas.

6.8-Verificaçãodetipos

Oqueacontecesechamarmosfactorialeusarmos1.5comoargumento?

>>>factorial(1.5)

RuntimeError:Maximumrecursiondepthexceeded

Pareceumarecursividadeinfinita.Noentanto,porqueissoacontece?Afunçãotemumcaso-base–quandon==0.Massennãoéumnúmerointeiro,podemosperderocaso-baseerecorrerparasempre.

Na primeira chamada recursiva, o valor de n é 0.5. No seguinte, é -0.5. Daí,torna-semenor(maisnegativo),masnuncaserá0.

Temos duas escolhas. Podemos tentar generalizar a função factorial paratrabalharcomnúmerosdepontoflutuante,oupodemosfazerfactorialcontrolaro tipo de argumento que recebe.A primeira opção chama-se função gamma eestáumpoucoalémdoalcancedestelivro.Entãousaremosasegundaopção.

Podemosusarafunçãointegradaisinstanceparaverificarotipodeargumento.Evamosaproveitarparaverificartambémseoargumentoépositivo:

deffactorial(n):

ifnotisinstance(n,int):

print('Factorialisonlydefinedforintegers.')

returnNone

elifn<0:

Page 94: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

print('Factorialisnotdefinedfornegativeintegers.')

returnNone

elifn==0:

return1

else:

returnn*factorial(n-1)

Oprimeirocaso-base lidacomnúmerosnãointeiros;osegundo,comnúmerosinteirosnegativos.EmambososcasosoprogramaexibeumamensagemdeerroeretornaNoneparaindicarquealgodeuerrado:

>>>factorial('fred')

Factorialisonlydefinedforintegers.

None

>>>factorial(-2)

Factorialisnotdefinedfornegativeintegers.

None

Sepassarmosporambasasverificações,sabemosquenépositivoouzero,entãopodemoscomprovarquearecursividadetermina.

Esse programa demonstra um padrão às vezes chamado de guardião.As duasprimeirascondicionaisatuamcomoguardiãs,protegendoocódigoqueseguedevalores que poderiam causar um erro. As guardiãs permitem comprovar acorreçãodocódigo.

Na“Buscareversa”,napágina165,veremosumaalternativamaisflexívelparaaexibiçãodeumamensagemdeerro:olevantamentodeexceções.

6.9-Depuração

Quebrar um grande programa em funções menores cria controles naturais dadepuração. Se uma função não estiver funcionando, há três possibilidades aconsiderar:

Há algo errado com os argumentos que a função está recebendo; umaprecondiçãoestásendoviolada.

Háalgoerradocomafunção;umapós-condiçãofoiviolada.

Háalgoerradocomovalorderetornoouaformanaqualestásendousado.

Page 95: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Paraexcluiraprimeirapossibilidade,vocêpodeacrescentarumainstruçãoprintno iníciodafunçãoeexibirosvaloresdosparâmetros(e talvezosseus tipos).Ouescrevercódigoqueverifiqueasprecondiçõesexplicitamente.

Seosparâmetrosparecerembons,acrescenteumainstruçãoprintantesdecadainstruçãoreturneexibaovalorderetorno.Sepossível,verifiqueoresultadoàmão.Umapossibilidadeéchamarafunçãocomvaloresfacilitemaverificaçãodoresultado(comono“Desenvolvimentoincremental”,dapágina94).

Seafunçãoparecerfuncionar,vejaachamadadafunçãoparatercertezadequeo valor de retorno está sendo usado corretamente (ou se está sendo usadomesmo!).

Acrescentar instruções de exibição no começo e no fim de uma função podeajudar a tornar o fluxo de execuçãomais visível. Por exemplo, aqui está umaversãodefactorialcominstruçõesdeexibição:

deffactorial(n):

space=''*(4*n)

print(space,'factorial',n)

ifn==0:

print(space,'returning1')

return1

else:

recurse=factorial(n-1)

result=n*recurse

print(space,'returning',result)

returnresult

spaceéumastringdecaracteresespeciaisquecontrolaaendentaçãoda saída.Aquiestáoresultadodefactorial(4):

factorial4

factorial3

factorial2

factorial1

factorial0

returning1

returning1

returning2

returning6

returning24

Page 96: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Seofluxodeexecuçãoparecerconfusoavocê,estetipodesaídapodeserútil.Leva um tempo para desenvolver um scaffolding eficaz, mas um pouco delepodeeconomizarmuitadepuração.

6.10-Glossário

variáveltemporáriaUma variável usada para guardar um valor intermediário em um cálculocomplexo.

códigomortoA parte de um programa que nunca pode ser executada, muitas vezesporqueaparecedepoisdeumainstruçãoreturn.

desenvolvimentoincrementalUm plano de desenvolvimento de programa para evitar a depuração, queacrescentaetestapoucaslinhasdecódigodecadavez.

scaffolding(andaime)Ocódigoqueseusaduranteodesenvolvimentodeprograma,masquenãofazpartedaversãofinal.

guardiãoUm padrão de programação que usa uma instrução condicional paraverificarelidarcomcircunstânciasquepossamcausarerros.

6.11-Exercícios

Exercício6.1

Desenheumdiagramadapilhadoseguinteprograma.Oqueoprogramaexibe?

defb(z):

prod=a(z,z)

print(z,prod)

returnprod

defa(x,y):

x=x+1

returnx*y

defc(x,y,z):

total=x+y+z

square=b(total)**2

Page 97: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

returnsquare

x=1

y=x+1

print(c(x,y+3,x+y))

Exercício6.2

AfunçãodeAckermann,A(m,n),édefinidaassim:

Fórmula–FunçãodeAckermann.

Veja http://en.wikipedia.org/wiki/Ackermann_function. Escreva uma funçãodenominada ack que avalie a função de Ackermann. Use a sua função paraavaliar ack(3, 4), cujo resultado deve ser 125. O que acontece para valoresmaioresdemen?

Solução:http://thinkpython2.com/code/ackermann.py.

Exercício6.3

Umpalíndromoéumapalavraquesesoletradamesmaformanosdoissentidos,como “osso” e “reviver”.Recursivamente, umapalavra é umpalíndromo se aprimeiraeúltimaletrasforemiguaiseomeioforumpalíndromo.

Asfunçõesseguintesrecebemumastringcomoargumentoeretornamasletrasiniciais,finaisedomeiodaspalavras:

deffirst(word):

returnword[0]

deflast(word):

returnword[-1]

defmiddle(word):

returnword[1:-1]

VeremoscomofuncionamnoCapítulo8.

1. Digiteessasfunçõesemumarquivochamadopalindrome.pye teste-as.O

Page 98: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

queacontecesechamarmiddlecomumastringdeduasletras?Umaletra?Eseastringestivervazia,escritacom''enãocontivernenhumaletra?

2. Escrevaumafunçãochamadais_palindromequerecebaumastringcomoargumentoeretorneTrueseforumpalíndromoeFalsesenãofor.Lembre-se de que você pode usar a função integrada len para verificar ocomprimentodeumastring.

Solução:http://thinkpython2.com/code/palindrome_soln.py.

Exercício6.4

Umnúmeroaéumapotênciadebsefordivisívelporbea/bforumapotênciadeb.Escrevaumafunçãochamadais_powerquerecebaosparâmetrosaeberetorneTrueseaforumapotênciadeb.Dica:pensenocaso-base.

Exercício6.5

Omaiordivisorcomum(MDC,ouGCDeminglês)deaebéomaiornúmeroquedivideambossemsobrarresto.

Ummodo de encontrar oMDC de dois números é observar qual é o resto rquando a é dividido por b, verificando que gcd(a, b) = gcd(b, r).Como caso-base,podemosusargcd(a,0)=a.

Escrevaumafunçãochamadagcdque recebaosparâmetrosaebedevolvaomaiordivisorcomum.

Crédito: Este exercício é baseado em um exemplo do livro de Abelson eSussman, Structure and Interpretation of Computer Programs (Estrutura einterpretaçãodeprogramasdecomputador,MITPress,1996).

Page 99: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo7:IteraçãoEstecapítuloésobreaiteração,acapacidadedeexecutarumblocodeinstruçõesrepetidamente. Vimos um tipo de iteração, usando a recursividade, em“Recursividade”, na página 81. Vimos outro tipo, usando um loop for, em“Repetição simples”, na página 65. Neste capítulo veremos ainda outro tipo,usandoa instruçãowhile.Porém,primeiroquero falar umpoucomais sobre aatribuiçãodevariáveis.

7.1-Reatribuição

Pode ser que você já tenha descoberto que é permitido fazer mais de umaatribuição para a mesma variável. Uma nova atribuição faz uma variávelexistentereferir-seaumnovovalor(edeixardereferir-seaovaloranterior).

>>>x=5

>>>x

5

>>>x=7

>>>x

7

Aprimeiravezqueexibimosx,seuvaloré5;nasegundavez,seuvaloré7.

AFigura7.1mostraqueareatribuiçãopareceumdiagramadeestado.

Nestepontoquerotratardeumafontecomumdeconfusão.ComooPythonusaosinaldeigual(=)paraatribuição,étentadorinterpretarumaafirmaçãocomoa=bcomoumaproposiçãomatemáticadeigualdade;istoé,adeclaraçãodequeaebsãoiguais.Masestaéumainterpretaçãoequivocada.

Emprimeirolugar,aigualdadeéumarelaçãosimétricaeaatribuiçãonãoé.Porexemplo,namatemática,sea=7então7=a.MasnoPython,ainstruçãoa=7élegale7=anãoé.

Alémdisso,namatemática,umaproposiçãodeigualdadeéverdadeiraoufalsapara sempre. Se a=b agora, então a sempre será igual a b. No Python, umainstruçãodeatribuiçãopodetornarduasvariáveisiguais,maselasnãoprecisam

Page 100: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

semanterassim:

>>>a=5

>>>b=a#aebagorasãoiguais

>>>a=3#aebnãosãomaisiguais

>>>b

5

Aterceiralinhamodificaovalordea,masnãomudaovalordeb,entãoelasjánãosãoiguais.

A reatribuição de variáveis muitas vezes é útil, mas você deve usá-la comprudência. Se os valores das variáveis mudarem frequentemente, isso podedificultaraleituraedepuraçãodocódigo.

Figura7.1–Diagramadeestado.

Figura7.1–Diagramadeestadodavariávelx.

7.2-Atualizaçãodevariáveis

Um tipo comum de reatribuição é uma atualização, onde o novo valor davariáveldependedovelho.

>>>x=x+1

Issosignifica“pegueovaloratualdex,acrescenteum,eentãoatualizexparaonovovalor”.

Sevocê tentaratualizarumavariávelquenãoexiste, recebeumerroporqueoPythonavaliaoladodireitoantesdeatribuirumvalorax:

>>>x=x+1

NameError:name'x'isnotdefined

Antesdepoderatualizarumavariáveléprecisoinicializá-la,normalmentecomumaatribuiçãosimples:

Page 101: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>x=0

>>>x=x+1

Atualizarumavariávelacrescentando1chama-seincremento;subtrair1chama-sedecremento.

7.3-Instruçãowhile

Oscomputadoresmuitasvezessãousadosparaautomatizartarefasrepetitivas.Arepetição de tarefas idênticas ou semelhantes sem fazer erros é algo que oscomputadoresfazembemeaspessoasnão.Emumprogramadecomputador,arepetiçãotambéméchamadadeiteração.

Já vimos duas funções, countdown e print_n, que se repetem usandorecursividade. Como a iteração é bem comum, o Python fornece recursos delinguagemparafacilitá-la.Umdeleséainstruçãoforquevimosem“Repetiçãosimples”,napágina65.Voltaremosaissomaisadiante.

Outra é a instrução while. Aqui está uma versão de countdown que usa ainstruçãowhile:

defcountdown(n):

whilen>0:

print(n)

n=n-1

print('Blastoff!')

Você até pode ler a instrução while como se fosse uma tradução do inglês.Significa“Enquantonformaiorque0,mostreovalordeneentãodecrementen.Quandochegara0,mostreapalavraBlastoff!”

Maisformalmente,aquiestáofluxodeexecuçãoparaumainstruçãowhile:

1. Determineseacondiçãoéverdadeiraoufalsa.

2. Se for falsa, saia da instrução while e continue a execução da próximainstrução.

3. Seacondiçãoforverdadeira,executeocorpoeentãovolteaopasso1.

Estetipodefluxochama-seloop(laço),porqueoterceiropassofazumloopde

Page 102: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

voltaaotopo.

Ocorpodoloopdevemudarovalordeumaoumaisvariáveisparaque,acertaaltura,acondiçãofiquefalsaeolooptermine.Senãooloopvaiserepetirparasempre,oqueéchamadodeloopinfinito.Umafonteinfindáveldedivertimentopara cientistas da computação é a observação das instruções no xampu, “Façaespuma,enxágue,repita”,quesãopartedeumloopinfinito.

No caso de countdown, podemos provar que o loop termina: sen for zero ounegativo,oloopnuncaéexecutado.Senão,nficacadavezmenoraopassarpeloloop,atéeventualmentechegara0.

Paraalgunsoutrosloops,nãoétãofácilperceberisso.Porexemplo:

defsequence(n):

whilen!=1:

print(n)

ifn%2==0:#népar

n=n/2

else:#néímpar

n=n*3+1

Acondiçãodesteloopén!=1,entãooloopcontinuaráatéquenseja1,oquetornaacondiçãofalsa.

Cadavezquepassapeloloop,oprogramaproduzovalordeneentãoverificaseé par ou ímpar. Se for par, n é dividido por 2. Se for ímpar, o valor de n ésubstituídoporn*3+1.Porexemplo,seoargumentopassadoasequencefor3,osvaloresresultantesdensão3,10,5,16,8,4,2,1.

Comonàsvezesaumentaeàsvezesdiminui,nãohánenhumaprovaóbviadeque n chegará eventualmente a 1, ou que o programa terminará. Para algunsvaloresden,podemosprovarotérmino.Porexemplo,seovalorinicialforumapotênciadedois,nseráparcadavezquepassarpeloloopatéquecheguea1.Oexemploanteriorterminacomumasequênciaassim,queiniciacom16.

Aquestãodifícilésepodemosprovarqueesteprogramaterminaparatodososvalorespositivosden.Porenquanto,ninguémfoicapazdecomprovarourefutarisso!(Vejahttp://en.wikipedia.org/wiki/Collatz_conjecture.)

Comoumexercício, reescrevaa funçãoprint_nde“Recursividade”,napágina

Page 103: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

81,usandoaiteraçãoemvezdarecursividade.

7.4-break

Àsvezesvocênãosabequeestánahoradeterminarumloopatéquejáestejanametadedocorpo.Nestecasopodeusarainstruçãobreakparasairdoloop.

Porexemplo,suponhaquevocêquerreceberumaentradadousuárioatéqueestedigitedone.Vocêpodeescrever:

whileTrue:

line=input('>')

ifline=='done':

break

print(line)

print('Done!')

A condição do loop éTrue, que sempre é verdade, então o loop roda até quechegueàinstruçãodeinterrupção.

Cada vez que passa pelo loop, o programa apresenta ao usuário um colcheteangular. Se o usuário digitar done, a instrução break sai do loop. Senão, oprogramaecoaoquequerqueousuáriodigiteevoltaaotopodoloop.Aquiestáumaamostradeexecução:

>notdone

notdone

>done

Done!

Esta forma de escrever loops while é comum porque podemos verificar acondiçãoemqualquerlugardoloop(nãosomentenotopo)epodemosexprimiracondiçãodeparadaafirmativamente(“parequandoistoacontecer”)emvezdenegativamente(“continueaseguiratéqueistoaconteça”).

7.5-Raízesquadradas

Loops muitas vezes são usados em programas que calculam resultadosnuméricos, começando com uma resposta aproximada e melhorando-aiterativamente.

Page 104: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Por exemplo, uma formade calcular raízes quadradas é ométododeNewton.Suponha que você queira saber a raiz quadrada de a. Se começar com quasequalquerestimativa,x,épossívelcalcularumaestimativamelhorcomaseguintefórmula:

Fórmula–RaizquadradapelométododeNewton.

Porexemplo,seafor4exfor3:

>>>a=4

>>>x=3

>>>y=(x+a/x)/2

>>>y

2.16666666667

Oresultadoémaispróximoàrespostacorreta( =2).Serepetirmosoprocessocomanovaestimativa,chegamosaindamaisperto:

>>>x=y

>>>y=(x+a/x)/2

>>>y

2.00641025641

Depoisdealgumasatualizações,aestimativaéquaseexata:

>>>x=y

>>>y=(x+a/x)/2

>>>y

2.00001024003

>>>x=y

>>>y=(x+a/x)/2

>>>y

2.00000000003

Emgeral, não sabemos comantecedência quantos passos sãonecessários parachegaràrespostacorreta,massabemosquandochegamosláporqueaestimativaparademudar:

>>>x=y

>>>y=(x+a/x)/2

>>>y

2.0

Page 105: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>x=y

>>>y=(x+a/x)/2

>>>y

2.0

Quando y == x, podemos parar. Aqui está um loop que começa com umaestimativainicial,x,eamelhoraatéquedeixedemudar:

whileTrue:

print(x)

y=(x+a/x)/2

ify==x:

break

x=y

Paraamaiorpartedevaloresdeafuncionabem,maspodeserperigosotestaraigualdade de um float. Os valores de ponto flutuante são aproximadamentecorretos: a maioria dos números racionais, como 1/3, e números irracionais,como ,nãopodemserrepresentadosexatamentecomumfloat.

Emvezdeverificarsexeysãoexatamenteiguais,émaissegurousarafunçãointegrada abs para calcular o valor absoluto ou magnitude da diferença entreeles:

ifabs(y-x)<epsilon:

break

Onde epsilon tem um valor como 0.0000001, que determina a proximidadedesejadaentrexey.

7.6-Algoritmos

OmétododeNewton é umexemplodeumalgoritmo: umprocessomecânicopararesolverumacategoriadeproblemas(nestecaso,calcularraízesquadradas).

Paraentenderoqueéumalgoritmo,podeserútilcomeçarcomalgoquenãoéum algoritmo. Quando aprendeu a multiplicar números de um dígito, vocêprovavelmentememorizou a tabuada. Ou seja, vocêmemorizou 100 soluçõesespecíficas.Estetipodeconhecimentonãoéalgorítmico.

Noentanto,sevocêfoi“preguiçoso”,poderiateraprendidoalgunstruques.Por

Page 106: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

exemplo,paraencontraroprodutodene9,podeescrevern-1comooprimeirodígito e 10-n como o segundo dígito. Este truque é uma solução geral paramultiplicarqualquernúmerodedígitoúnicopor9.Istoéumalgoritmo!

Deformasemelhante,astécnicasqueaprendeu,comootransportenaadição,oempréstimo na subtração e a divisão longa são todos algoritmos. Uma dascaracterísticas de algoritmos é que eles não exigem inteligência para seremexecutados. São processosmecânicos, nos quais cada passo segue a partir doúltimo,deacordocomumconjuntoderegrassimples.

A execução de algoritmos é maçante, mas projetá-los é interessante,intelectualmentedesafiadoreumapartecentraldaCiênciadaComputação.

Algumas coisas que as pessoas fazem naturalmente, sem dificuldade oupensamentoconsciente,sãoasmaisdifíceisparaexprimiralgoritmicamente.Acompreensãode linguagemnatural é umbomexemplo.Todos nós o fazemos,masporenquantoninguémfoicapazdeexplicarcomoofazemos,pelomenosnãonaformadeumalgoritmo.

7.7-Depuração

Aocomeçaraescreverprogramasmaiores,podeserquevocêpassemaistempodepurando.Maiscódigosignificamaispossibilidadesfazererrosemaislugaresparaesconderdefeitos.

Uma forma de cortar o tempo de depuração é “depurar por bisseção”. Porexemplo,sehá100linhasnoseuprogramaevocêasverificaumaauma,seriam100passosatomar.

Em vez disso, tente quebrar o problema pela metade. Olhe para o meio doprograma, ou perto disso, para um valor intermediário que possa verificar.Acrescenteumainstruçãoprint(ououtracoisaquetenhaumefeitoverificável)eexecuteoprograma.

Se a verificação do ponto central for incorreta, deve haver um problema naprimeira metade do programa. Se for correta, o problema está na segundametade.

Cada vez que executar uma verificação assim, divida ao meio o número de

Page 107: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

linhas a seremverificadas.Depois de seis passos (que émenos de 100), vocêteria menos de uma ou duas linhas do código para verificar, pelo menos emteoria.

Naprática,nemsempreéclarooquerepresentao“meiodoprograma”enemsempreépossívelverificá-lo.Nãofazsentidocontarlinhaseencontraropontocentralexato.Emvezdisso,penseemlugaresnoprogramaondepoderiahavererrose lugaresondeé fácil inserirumpontodeverificação.Entãoescolhaumlugarondeaspossibilidadessãobasicamenteasmesmasdequeodefeitoestejaantesoudepoisdaverificação.

7.8-Glossário

reatribuiçãoAtribuirumnovovaloraumavariávelquejáexiste.

atualizaçãoUmaatribuiçãoondeonovovalordavariáveldependadovelho.

inicializaçãoUmaatribuiçãoquedáumvalorinicialaumavariávelqueseráatualizada.

incrementoUma atualização que aumenta o valor de uma variável (normalmente porumaunidade).

decrementoUmaatualizaçãoquereduzovalordeumavariável.

iteraçãoExecução repetida de um grupo de instruções, usando uma chamada dafunçãorecursivaouumloop.

loopinfinitoUmloopnoqualacondiçãodetérminonuncaésatisfeita.

algoritmoUmprocessogeralpararesolverumacategoriadeproblemas.

7.9-Exercícios

Exercício7.1

Copie o loop de “Raízes quadradas”, na página 111, e encapsule-o em umafunção chamada mysqrt que receba a como parâmetro, escolha um valor

Page 108: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

razoáveldexedevolvaumaestimativadaraizquadradadea.

Paratestar,escrevaumafunçãodenominadatest_square_root,queexibeumatabelacomoesta:

amysqrt(a)math.sqrt(a)diff

--------------------------

1.01.01.00.0

2.01.414213562371.414213562372.22044604925e-16

3.01.732050807571.732050807570.0

4.02.02.00.0

5.02.23606797752.23606797750.0

6.02.449489742782.449489742780.0

7.02.645751311062.645751311060.0

8.02.828427124752.828427124754.4408920985e-16

9.03.03.00.0

A primeira coluna é um número, a; a segunda coluna é a raiz quadrada de acalculada com mysqrt; a terceira coluna é a raiz quadrada calculada pormath.sqrt; a quarta coluna é o valor absoluto da diferença entre as duasestimativas.

Exercício7.2

Afunçãointegradaeval tomaumastringeaavalia,usandoo interpretadordoPython.Porexemplo:

>>>eval('1+2*3')

7

>>>importmath

>>>eval('math.sqrt(5)')

2.2360679774997898

>>>eval('type(math.pi)')

<class'float'>

Escrevauma funçãochamadaeval_loop que iterativamente peça uma entradaaousuário,aavalieusandoevaleexibaoresultado.

Eladevecontinuaratéqueousuáriodigitedone;entãodeveráexibirovalordaúltimaexpressãoavaliada.

Exercício7.3

Page 109: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

OmatemáticoSrinivasaRamanujan encontrou uma série infinita que pode serusadaparagerarumaaproximaçãonuméricade1/π:

Fórmula–AproximaçãodeπpelasériedeRamanujan.

Escrevaumafunçãochamadaestimate_piqueuseestafórmulaparacomputaredevolverumaestimativadeπ.Vocêdeveusaro loopwhile para calcularostermosdaadiçãoatéqueoúltimotermosejamenorque1e-15(queéanotaçãodoPythonpara10**15).Vocêpodeverificaroresultadocomparando-ocommath.pi.

Page 110: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo8:StringsStringsnãosãocomonúmeros inteiros,deponto flutuanteoubooleanos.Umastringéumasequência,ouseja,umacoleçãoordenadadeoutrosvalores.Nestecapítulo você verá como acessar os caracteres que compõem uma string eaprenderáalgunsmétodosqueasstringsoferecem.

8.1-Umastringéumasequência

Umastringéumasequênciadecaracteres.Vocêpodeacessarumcaracteredecadavezcomooperadordecolchete:

>>>fruit='banana'

>>>letter=fruit[1]

Asegundainstruçãoselecionaocaracterenúmero1defruiteoatribuialetter.

Aexpressãoentrecolcheteschama-seíndice.Oíndiceapontaqualcaracteredasequênciavocêquer(daíonome).

Maspodeserquevocênãoobtenhaoqueespera:

>>>letter

'a'

Paraamaiorpartedaspessoas,aprimeiraletrade'banana'éb,nãoa.Masparaoscientistasdacomputação,oíndiceéumareferênciadocomeçodastring,eareferênciadaprimeiraletraézero.

>>>letter=fruit[0]

>>>letter

'b'

Entãobéa0ª(“zerésima”)letrade'banana',aéa1ª(primeira)letraenéa2ª(segunda)letra.

Vocêpodeusarumaexpressãoquecontenhavariáveiseoperadorescomoíndice:

>>>i=1

>>>fruit[i]

Page 111: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

'a'

>>>fruit[i+1]

'n'

Porém,ovalordoíndicetemqueserumnúmerointeiro.Senãofor,éissoqueaparece:

>>>letter=fruit[1.5]

TypeError:stringindicesmustbeintegers

8.2-len

lenéumafunçãointegradaquedevolveonúmerodecaracteresemumastring:

>>>fruit='banana'

>>>len(fruit)

6

Paraobteraúltimaletradeumastring,podeparecerumaboaideiatentaralgoassim:

>>>length=len(fruit)

>>>last=fruit[length]

IndexError:stringindexoutofrange

ArazãodehaverumIndexErroraquiéquenãohánenhuma letraem 'banana'comoíndice6.Comoacontageminicianozero,asseisletrassãonumeradasde0a5.Paraobteroúltimocaractere,vocêdevesubtrair1delength:

>>>last=fruit[length-1]

>>>last

'a'

Ouvocêpodeusaríndicesnegativos,quecontamdetrásparaafrenteapartirdofimdastring.Aexpressãofruit[-1]apresentaaúltimaletra,fruit[-2]apresentaasegundaletradetrásparaafrente,eassimpordiante.

8.3-Travessiacomloopfor

Muitos cálculos implicam o processamento de um caractere por vez em umastring.Muitasvezescomeçamnoinício,selecionamumcaractereporvez,fazem

Page 112: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

algoecontinuamatéofim.Estemodelodoprocessamentochama-setravessia.Ummododeescreverumatravessiaécomoloopwhile:

index=0

whileindex<len(fruit):

letter=fruit[index]

print(letter)

index=index+1

Esteloopatravessaastringeexibecadaletrasozinhaemumalinha.Acondiçãodo loop é index <len (fruit), então quando index é igual ao comprimento dastring, a condição é falsa e o corpo do loop não émais executado. O últimocaractereacessadoéaquelecomoíndicelen(fruit)-1,queéoúltimocaracterenastring.

Comoexercício,escrevaumafunçãoquerecebaumastringcomoargumentoeexibaasletrasdetrásparaafrente,umaporlinha.

Outraformadeescreverumatravessiaécomumloopfor:

forletterinfruit:

print(letter)

Cada vez que o programa passar pelo loop, o caractere seguinte na string éatribuídoàvariávelletter.Oloopcontinuaatéquenãosobrenenhumcaractere.

Opróximoexemplomostracomousaraconcatenação(adiçãodestrings)eumloopforparagerarumasérieabecedária(istoé,emordemalfabética).Nolivrode Robert McCloskey, Make Way for Ducklings (Abram caminho para ospatinhos), os nomes dos patinhos são Jack, Kack, Lack,Mack, Nack, Ouack,PackeQuack.Esteloopproduzestesnomesemordem:

prefixes='JKLMNOPQ'

suffix='ack'

forletterinprefixes:

print(letter+suffix)

Asaídaé:

Jack

Kack

Lack

Mack

Nack

Oack

Page 113: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Pack

Qack

Claro que não está exatamente certo porque “Ouack” e “Quack” foram malsoletrados.Comoexercício,altereoprogramaparacorrigiresteerro.

8.4-Fatiamentodestrings

Umsegmentodeuma string é chamadode fatia.Selecionaruma fatia é comoselecionarumcaractere:

>>>s='MontyPython'

>>>s[0:5]

'Monty'

>>>s[6:12]

'Python'

Ooperador[n:m]retornaapartedastringdo“enésimo”caractereao“emésimo”caractere,incluindooprimeiro,masexcluindooúltimo.Estecomportamentoécontraintuitivo, porém pode ajudar a imaginar os índices que indicam a parteentreoscaracteres,comonaFigura8.1.

Figura8.1–Índicesdefatias.

Sevocêomitiroprimeiroíndice(antesdosdoispontos),afatiacomeçanoiníciodastring.Seomitirosegundoíndice,afatiavaiaofimdastring:

>>>fruit='banana'

>>>fruit[:3]

'ban'

>>>fruit[3:]

'ana'

Se o primeiro índice formaior ou igual ao segundo, o resultado é uma stringvazia,representadaporduasaspas:

>>>fruit='banana'

Page 114: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>fruit[3:3]

''

Uma string vazia não contém nenhum caractere e tem o comprimento 0, foraisso,éigualaqualqueroutrastring.

Continuando este exemplo, o que você acha que fruit[:] significa? Teste eveja.

8.5-Stringssãoimutáveis

É tentador usar o operador [] no lado esquerdo de uma atribuição, com aintençãodealterarumcaractereemumastring.Porexemplo:

>>>greeting='Hello,world!'

>>>greeting[0]='J'

TypeError:'str'objectdoesnotsupportitemassignment

O“objeto”nestecasoéastringeo“item”éocaracterequevocêtentouatribuir.Porenquanto,umobjetoéamesmacoisaqueumvalor,mas refinaremosestadefiniçãomaisadiante(Objetosevalores,nocapítulo10).

Arazãodoerroéqueasstringssãoimutáveis,oquesignificaquevocênãopodealterarumastringexistente.Omelhorquevocêpodefazerécriarumastringquesejaumavariaçãodaoriginal:

>>>greeting='Hello,world!'

>>>new_greeting='J'+greeting[1:]

>>>new_greeting

'Jello,world!'

Esseexemploconcatenaumanovaprimeiraletraaumafatiadegreeting.Nãotemefeitosobreastringoriginal.

8.6-BuscandoOquefazaseguintefunção?

deffind(word,letter):

index=0

whileindex<len(word):

ifword[index]==letter:

Page 115: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

returnindex

index=index+1

return-1

Decertomodo,findéoinversodooperador[].Emvezdetomarumíndiceeextrair o caractere correspondente, ele toma um caractere e encontra o índiceonde aquele caractere aparece. Se o caractere não for encontrado, a funçãoretorna-1.

Esse é o primeiro exemplo que vimos de uma instruçãoreturn dentro de umloop.Seword[index]==letter,afunçãosaidolooperetornaimediatamente.

Se o caractere não aparecer na string, o programa sai do loop normalmente edevolve-1.

Este modelo de cálculo – atravessar uma sequência e retornar quandoencontramosoqueestamosprocurando–chama-sebusca.

Comoexercício,alterefindparaquetenhaumterceiroparâmetro:oíndiceemwordondedevecomeçarabusca.

8.7-Loopecontagem

O seguinte programa conta o número de vezes que a letra a aparece em umastring:

word='banana'

count=0

forletterinword:

ifletter=='a':

count=count+1

print(count)

Este programa demonstra outro padrão de computação chamado contador. Avariávelcounté inicializadacom0eentãoincrementadacadavezqueumaéencontrado.Aosairdoloop,countcontémoresultado–onúmerototaldeletras'a'.

Como exercício, encapsule este código em uma função denominada count egeneralize-oparaqueaceiteastringealetracomoargumentos.

Page 116: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Então reescreva a função para que, em vez de atravessar a string, ela use aversãodetrêsparâmetrosdofinddaseçãoanterior.

8.8-Métodosdestrings

Asstringsoferecemmétodosqueexecutamváriasoperaçõesúteis.Ummétodoésemelhante a uma função – toma argumentos e devolve um valor –, mas asintaxeédiferente.Porexemplo,ométodoupper recebeumastringedevolveumanovastringcomtodasasletrasmaiúsculas.

Em vez da sintaxe de função upper(word), ela usa a sintaxe de métodoword.upper():

>>>word='banana'

>>>new_word=word.upper()

>>>new_word

'BANANA'

Estaformadenotaçãodepontoespecificaonomedométodo,uppereonomedastring,word,àqualométodoseráaplicado.Osparêntesesvaziosindicamqueestemétodonãotomanenhumargumento.

Uma chamada de método denomina-se invocação; neste caso, diríamos queestamosinvocandoupperemword.

E,naverdade,háummétodode stringdenominadofind, que é notavelmentesemelhanteàfunçãoqueescrevemos:

>>>word='banana'

>>>index=word.find('a')

>>>index

1

Neste exemplo, invocamos find em word e passamos a letra que estamosprocurandocomoumparâmetro.

Naverdade,ométodofindémaisgeralqueanossafunção;elepodeencontrarsubstrings,nãoapenascaracteres:

>>>word.find('na')

2

Page 117: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Por padrão, find inicia no começo da string, mas pode receber um segundoargumento,oíndiceondedevecomeçar:

>>>word.find('na',3)

4

Esteéumexemplodeumargumentoopcional.find tambémpodereceberumterceiroargumento,oíndiceparaondedeveparar:

>>>name='bob'

>>>name.find('b',1,2)

-1

Esta busca falhaporque'b' não aparece no intervalo do índice de 1 a 2, nãoincluindo2.Fazerbuscasaté(masnãoincluindo)osegundoíndice tornafindsimilaraooperadordefatiamento.

8.9-Operadorin

ApalavrainéumoperadorbooleanoquerecebeduasstringseretornaTrueseaprimeiraaparecercomoumasubstringdasegunda:

>>>'a'in'banana'

True

>>>'seed'in'banana'

False

Porexemplo, a seguinte função imprime todasas letrasdeword1 que tambémaparecememword2:

defin_both(word1,word2):

forletterinword1:

ifletterinword2:

print(letter)

Comnomesdevariáveisbemescolhidos,oPythonàsvezespodeserlidocomoumtextoeminglês.Vocêpodeleresteloop,“para(cada)letraem(aprimeira)palavra,se(a)letra(aparecer)em(asegunda)palavra,exiba(a)letra”.

Vejaoqueéapresentadoaosecompararmaçãselaranjas:

>>>in_both('apples','oranges')

Page 118: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

a

e

s

8.10-Comparaçãodestrings

Os operadores relacionais funcionam em strings. Para ver se duas strings sãoiguais:

ifword=='banana':

print('Allright,bananas.')

Outras operações relacionais são úteis para colocar palavras em ordemalfabética:

ifword<'banana':

print('Yourword,'+word+',comesbeforebanana.')

elifword>'banana':

print('Yourword,'+word+',comesafterbanana.')

else:

print('Allright,bananas.')

OPythonnão lidacom letrasmaiúsculaseminúsculasdomesmo jeitoqueaspessoas. Todas as letras maiúsculas vêm antes de todas as letras minúsculas,portanto:

Yourword,Pineapple,comesbeforebanana.

Uma forma comum de lidar com este problema é converter strings em umformato padrão, como letras minúsculas, antes de executar a comparação.Lembre-se disso caso tenha que se defender de um homem armado com umabacaxi.

8.11-Depuração

Ao usar índices para atravessar os valores em uma sequência, é complicadoacertarocomeçoeofimdatravessia.AquiestáumafunçãoquesupostamentecomparaduaspalavraseretornaTrueseumadaspalavrasfororeversodaoutra,mascontémdoiserros:

defis_reverse(word1,word2):

Page 119: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

iflen(word1)!=len(word2):

returnFalse

i=0

j=len(word2)

whilej>0:

ifword1[i]!=word2[j]:

returnFalse

i=i+1

j=j-1

returnTrue

Aprimeira instrução if verifica se as palavras têm omesmo comprimento. Senãoforocaso,podemosretornarFalseimediatamente.Docontrário,paraorestodafunção,podemossuporqueaspalavrastenhamomesmocomprimento.Esteéumexemplodomodelodeguardiãoem“Verificaçãodetipos”,napágina101.

iejsãoíndices:iatravessaword1paraafrente,enquantojatravessaword2paratrás. Se encontrarmos duas letras que não combinam, podemos retornar Falseimediatamente.Seterminarmosoloopinteiroetodasasletrascorresponderem,retornamosTrue.

Setestarmosestafunçãocomaspalavras“pots”e“stop”,esperamosovalorderetornoTrue,masrecebemosumIndexError:

>>>is_reverse('pots','stop')

...

File"reverse.py",line15,inis_reverse

ifword1[i]!=word2[j]:

IndexError:stringindexoutofrange

Para depurar este tipo de erro, minha primeira ação é exibir os valores dosíndicesimediatamenteantesdalinhaondeoerroaparece.

whilej>0:

print(i,j)#exibiraqui

ifword1[i]!=word2[j]:

returnFalse

i=i+1

j=j-1

Agoraquandoexecutooprogramanovamente,recebomaisinformação:

>>>is_reverse('pots','stop')

04

Page 120: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

...

IndexError:stringindexoutofrange

Naprimeiravezqueoprogramapassarpeloloop,ovalordejé4,queestáforado intervalo da string 'pots'. O índice do último caractere é 3, então o valorinicialdejdeveserlen(word2)-1.

Secorrigiresseerroeexecutaroprogramanovamente,recebo:

>>>is_reverse('pots','stop')

03

12

21

True

Destavez,recebemosarespostacerta,masparecequeoloopsófoiexecutadotrêsvezes,oqueésuspeito.Paraterumaideiamelhordoqueestáacontecendo,éútildesenharumdiagramadeestado.Duranteaprimeiraiteração,oframedeis_reverseémostradonaFigura8.2.

8.2–Diagramadeestadodeis_reverse.

Tomei a liberdade de arrumar as variáveis no frame e acrescentei linhaspontilhadasparamostrarqueosvaloresdeiejindicamcaracteresemword1eword2.

Começando com este diagrama, execute o programa em papel, alterando osvalores de i e j durante cada iteração.Encontre e corrija o segundo errodestafunção.

8.12-Glossário

objetoAlgo a que uma variável pode se referir. Por enquanto, você pode usar“objeto”e“valor”deformaintercambiável.

sequência

Page 121: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Uma coleção ordenada de valores onde cada valor é identificado por umíndicedenúmerointeiro.

itemUmdosvaloresemumasequência.

índiceUmvalor inteirousadoparaselecionarumitememumasequência,comoumcaractereemumastring.NoPython,osíndicescomeçamem0.

fatiaPartedeumastringespecificadaporumintervalodeíndices.

stringvaziaUma string sem caracteres e de comprimento 0, representada por duasaspas.

imutávelApropriedadedeumasequênciacujositensnãopodemseralterados.

atravessarRepetiros itensemumasequência, executandoumaoperaçãosemelhanteemcadaum.

buscaUmmodelo de travessia que é interrompido quando encontra o que estáprocurando.

contadorUmavariávelusadaparacontaralgo,normalmenteinicializadacomzeroeentãoincrementada.

invocaçãoUmainstruçãoquechamaummétodo.

argumentoopcionalUmargumentodefunçãooumétodoquenãoénecessário.

8.13-Exercícios

Exercício8.1

Leia a documentação dos métodos de strings emhttp://docs.python.org/3/library/stdtypes.html#string-methods.Podeserumaboaideiaexperimentaralgunsdelesparaentendercomofuncionam.stripereplacesãoespecialmenteúteis.

A documentação usa uma sintaxe que pode ser confusa. Por exemplo, em

Page 122: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

find(sub[, start[, end]]), os colchetes indicam argumentos opcionais.Entãosubéexigido,masstartéopcional,esevocêincluirstart,entãoendéopcional.

Exercício8.2

Háummétododestringchamadocount,queésemelhanteàfunçãoem“Loopecontagem”, na página 123. Leia a documentação destemétodo e escreva umainvocaçãoqueconteonúmerodeletras'a'em'banana'.

Exercício8.3

Umafatiadestringpodereceberumterceiroíndicequeespecifiqueo“tamanhodopasso”;istoé,onúmerodeespaçosentrecaracteressucessivos.Umtamanhodepasso2significatomarumcaractereeoutronão;3significatomarumedoisnãoetc.

>>>fruit='banana'

>>>fruit[0:5:2]

'bnn'

Umtamanhodepasso-1atravessaapalavradetrásparaafrente,entãoafatia[::-1]geraumastringinvertida.

Useissoparaescreverumaversãodeumalinhadeis_palindromedoExercício6.3.

Exercício8.4

As seguintes funções pretendem verificar se uma string contém alguma letraminúscula,masalgumasdelasestãoerradas.Paracada função,descrevaoqueelafaz(assumindoqueoparâmetrosejaumastring).

defany_lowercase1(s):

forcins:

ifc.islower():

returnTrue

else:

returnFalse

defany_lowercase2(s):

Page 123: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

forcins:

if'c'.islower():

return'True'

else:

return'False'

defany_lowercase3(s):

forcins:

flag=c.islower()

returnflag

defany_lowercase4(s):

flag=False

forcins:

flag=flagorc.islower()

returnflag

defany_lowercase5(s):

forcins:

ifnotc.islower():

returnFalse

returnTrue

Exercício8.5

UmacifradeCésaréumaformafracadecriptografiaqueimplica“rotacionar”cada letra por um número fixo de lugares. Rotacionar uma letra significadeslocá-lo pelo alfabeto, voltando ao início se for necessário, portanto ‘A’rotacionadopor3é‘D’e‘Z’rotacionadopor1é‘A’.

Pararotacionarumapalavra,façacadaletrasemoverpelamesmaquantidadedeposições. Por exemplo, “cheer” rotacionado por 7 é “jolly” e “melon”rotacionado por -10 é “cubed”. No filme 2001: Uma odisseia no espaço, ocomputadordanavechama-seHAL,queéIBMrotacionadopor-1.

Escrevaumafunçãochamadarotate_wordquerecebaumastringeumnúmerointeiro como parâmetros, e retorne uma nova string que contém as letras dastringoriginalrotacionadaspelonúmerodado.

Vocêpodeusarafunçãointegradaord,queconverteumcaractereemumcódigonumérico e chr, que converte códigos numéricos em caracteres. As letras doalfabetosãocodificadasemordemalfabética,então,porexemplo:

Page 124: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>ord('c')-ord('a')

2

Porque 'c' é a “segunda” letra do alfabeto. Mas tenha cuidado: os códigosnuméricosdeletrasmaiúsculassãodiferentes.

PiadaspotencialmenteofensivasnainternetàsvezessãocodificadasemROT13,queéumacifradeCésarcomrotação13.Senãoseofenderfacilmente,encontreedecifrealgumasdelas.

Page 125: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo9:Estudodecaso:jogosdepalavrasEstecapítuloapresentaosegundoestudodecasoqueenvolvesolucionarquebra-cabeçasusandopalavrascomcertaspropriedades.Porexemplo,encontraremosos palíndromos mais longos em inglês e procuraremos palavras cujas letrasapareçamemordemalfabética.Eapresentareioutroplanodedesenvolvimentodeprograma:areduçãoaumproblemaresolvidoanteriormente.

9.1-Leituradelistasdepalavras

Paraosexercíciosdestecapítulovamosusarumalistadepalavraseminglês.Hámuitas listas de palavras disponíveis na internet, mas a mais conveniente aonosso propósito é uma das listas de palavras disponibilizadas em domíniopúblico por Grady Ward como parte do projeto lexical Moby (verhttp://wikipedia.org/wiki/Moby_Project). É uma lista de 113.809 palavrascruzadas oficiais; isto é, as palavras que se consideram válidas em quebra-cabeças de palavras cruzadas e outros jogos de palavras.Na coleçãoMoby, onome do arquivo é 113809of.fic; você pode baixar uma cópia, com um nomemaissimplescomowords.txt,dehttp://thinkpython2.com/code/words.txt.

Estearquivoestáem texto simples, entãovocêpodeabri-locomumeditordetexto, mas também pode lê-lo no Python. A função integrada open recebe onomedoarquivocomoumparâmetroeretornaumobjetodearquivoquevocêpodeusarparaleroarquivo.

>>>fin=open('words.txt')

fin é umnome comumde objeto de arquivo usado para entrada de dados.Oobjeto de arquivo oferece váriosmétodos de leitura, inclusive readline, que lêcaracteres no arquivo até chegar a um comando de nova linha, devolvendo oresultadocomoumastring:

>>>fin.readline()

'aa\r\n'

Page 126: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

A primeira palavra nesta lista específica é “aa”, uma espécie de lava. Asequência'\r\n'representadoiscaracteresquerepresentamespaçosembranco(whitespace),umretornodecarroeumanovalinha,queseparaestapalavradaseguinte.

O objeto de arquivo grava a posição em que está no arquivo, então se vocêchamarreadlinemaisumavez,receberáaseguintepalavra:

>>>fin.readline()

'aah\r\n'

Apalavra seguinte é “aah”,umapalavraperfeitamente legítima, entãoparedeolharparamimdessejeito.Ou,seéowhitespacequeestáincomodandovocê,podemosnoslivrardelecomométododestringstrip:

>>>line=fin.readline()

>>>word=line.strip()

>>>word

'aahed'

Vocêtambémpodeusarumobjetodearquivocomopartedeumloopfor.Esteprogramalêwords.txteimprimecadapalavra,umaporlinha:

fin=open('words.txt')

forlineinfin:

word=line.strip()

print(word)

9.2-Exercícios

Hásoluçõesparaestesexercíciosnapróximaseção.Masébomvocêtentarfazercadaumantesdeverassoluções.

Exercício9.1

Escrevaumprogramaqueleiawords.txteimprimaapenasaspalavrascommaisde20caracteres(semcontarwhitespace).

Exercício9.2

Page 127: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Em 1939, Ernest Vincent Wright publicou uma novela de 50.000 palavras,chamadaGadsby,quenãocontémaletra“e”.Comoo“e”éaletramaiscomumeminglês,issonãoéalgofácildefazer.

Na verdade, é difícil até construir um único pensamento sem usar o símbolomaiscomumdoidioma.Noinícioélento,mascomprudênciaehorasdetreino,vaificandocadavezmaisfácil.

Muitobem,agoraeuvouparar.

Escrevaumafunçãochamadahas_no_equeretorneTrueseapalavradadanãotiveraletra“e”nela.

Altereseuprogramanaseçãoanteriorparaimprimirapenasaspalavrasquenãotêm“e”ecalculeaporcentagemdepalavrasnalistaquenãotêm“e”.

Exercício9.3

Escreva uma função chamada avoids que receba uma palavra e uma série deletras proibidas, e retorne True se a palavra não usar nenhuma das letrasproibidas.

Altere o código para que o usuário digite uma série de letras proibidas e oprogramaimprimaonúmerodepalavrasquenãocontêmnenhumadelas.Vocêpode encontrar umacombinaçãode cinco letrasproibidasque excluaomenornúmeropossíveldepalavras?

Exercício9.4

Escrevaumafunçãochamadauses_onlyquerecebaumapalavraeumasériedeletraseretorneTrue,seapalavrasócontiverletrasdalista.Vocêpodefazerumafraseusandosóasletrasacefhlo?Quenãoseja“Hoealfalfa?”

Exercício9.5

Escrevaumafunçãochamadauses_allquerecebaumapalavraeumasériedeletras obrigatórias e retorneTrue se a palavra usar todas as letras obrigatóriaspelomenosumavez.Quantaspalavrasusamtodasasvogais(aeiou)?Equetalaeiouy?

Page 128: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Exercício9.6

Escreva uma função chamada is_abecedarian que retorne True se as letrasnuma palavra aparecerem em ordem alfabética (tudo bem se houver letrasduplas).Quantaspalavrasemordemalfabéticaexistem?

9.3-Busca

Todos os exercícios na seção anterior têm algo em comum; eles podem serresolvidoscomomodelodebuscaquevimosem“Buscando”,napágina123.Oexemplomaissimplesé:

defhas_no_e(word):

forletterinword:

ifletter=='e':

returnFalse

returnTrue

O loop for atravessa os caracteres em word. Se encontrarmos a letra “e”,podemos retornarFalse imediatamente; senão foro caso, temosque ir à letraseguinte.Sesairmosdoloopnormalmente,issoquerdizerquenãoencontramosum“e”,entãoretornamosTrue.

Você pode escrever esta função de formamais concisa usando o operador in,mas comecei com esta versão porque ela demonstra a lógica do modelo debusca.

avoidséumaversãomaisgeraldehas_no_e,mastemamesmaestrutura:

defavoids(word,forbidden):

forletterinword:

ifletterinforbidden:

returnFalse

returnTrue

Podemos retornar False logo que encontrarmos uma letra proibida; sechegarmosaofimdoloop,retornamosTrue.

uses_onlyésemelhante,excetopelosentidodacondição,queseinverte:

defuses_only(word,available):

Page 129: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

forletterinword:

ifletternotinavailable:

returnFalse

returnTrue

Emvezdeumalistadeletrasproibidas,temosumalistadeletrasdisponíveis.Seencontrarmosumaletraemwordquenãoestáemavailable,podemosretornarFalse.

uses_allésemelhante,masinvertemosafunçãodapalavraeastringdeletras:

defuses_all(word,required):

forletterinrequired:

ifletternotinword:

returnFalse

returnTrue

Emvezdeatravessarasletrasemword,o loopatravessaas letrasobrigatórias.Se alguma das letras obrigatórias não aparecer na palavra, podemos retornarFalse.

Sevocê realmente estivessepensandocomoumcientistada computação, teriareconhecido que uses_all foi um exemplo de um problema resolvidoanteriormenteeescreveria:

defuses_all(word,required):

returnuses_only(required,word)

Esse é um exemplo de um plano de desenvolvimento de programa chamadoreduçãoaumproblemaresolvidoanteriormente,ou seja,você reconheceoproblema no qual está trabalhando como um exemplo de um problema járesolvidoeaplicaumasoluçãoexistente.

9.4-Loopcomíndices

Escreviasfunçõesnaseçãoanteriorcomloopsforporqueeusóprecisavadoscaracteresnasstrings;nãoprecisavafazernadacomosíndices.

Parais_abecedarian temosquecomparar letrasadjacentes,oqueéumpoucocomplicadoparaoloopfor:

Page 130: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

defis_abecedarian(word):

previous=word[0]

forcinword:

ifc<previous:

returnFalse

previous=c

returnTrue

Umaalternativaéusararecursividade:

defis_abecedarian(word):

iflen(word)<=1:

returnTrue

ifword[0]>word[1]:

returnFalse

returnis_abecedarian(word[1:])

Outraopçãoéusarumloopwhile:

defis_abecedarian(word):

i=0

whilei<len(word)-1:

ifword[i+1]<word[i]:

returnFalse

i=i+1

returnTrue

Oloopcomeçacomi==0eterminaquandoi==len(word)-1.Cadavezquepassa pelo loop, o programa compara o “i-ésimo” caractere (que você podeconsiderar o caractere atual) com o caractere de posição i+1 (que pode serconsideradoocaractereseguinte).

Seopróximocaracterefordeumaposiçãoanterior(alfabeticamenteanterior)àatual, então descobrimos uma quebra na tendência alfabética, e retornamosFalse.

Sechegarmosaofimdoloopsemencontrarumaquebra,entãoapalavrapassano teste.Para convencer-sedequeo loop terminacorretamente, considereumexemplo como 'flossy'. O comprimento da palavra é 6, então o loop éexecutado pela última vez quando i for igual a 4, que é o índice do segundocaractere de trás para frente. Na última iteração, o programa compara openúltimocaracterecomoúltimo,queéoquequeremos.

Page 131: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Aqui está uma versão de is_palindrome (veja o Exercício 6.3) que usa doisíndices:umcomeçanoinícioeaumenta;ooutrocomeçanofinalediminui.

defis_palindrome(word):

i=0

j=len(word)-1

whilei<j:

ifword[i]!=word[j]:

returnFalse

i=i+1

j=j-1

returnTrue

Oupodemosreduziraumproblemaresolvidoanteriormenteeescrever:

defis_palindrome(word):

returnis_reverse(word,word)

Usandois_reversedaseção8.11.

9.5-Depuração

Testar programas é difícil. As funções neste capítulo são relativamente fáceisparatestarporqueépossívelverificarosresultadosàmão.Aindaassim,podeserdifícilouatéimpossívelescolherumgrupodepalavrasquetestetodososerrospossíveis.

Tomando has_no_e como exemplo, há dois casos óbvios para verificar: aspalavrasquetêmum‘e’devemretornarFalse,easpalavrasquenãotêmdevemretornarTrue.Nãodeveráserumproblemapensaremumexemplodecadauma.

Dentrode cada caso, há alguns subcasosmenosóbvios.Entre as palavras quetêm um “e”, você deve testar palavras com um “e” no começo, no fim e emalgum lugar no meio. Você deve testar palavras longas, palavras curtas epalavrasmuitocurtas,comoastringvazia.Astringvaziaéumexemplodeumcasoespecial,nãoóbvio,ondeerrosmuitasvezesespreitam.

Alémdoscasosdetestequevocêgerar, tambémpodeserumaboaideiatestarseu programa comuma lista de palavras comowords.txt.Ao analisar a saída,podeserqueoserrosapareçam,mastenhacuidado:vocêpodepegarumtipodeerro(palavrasquenãodeveriamserincluídas,masforam)enãooutro(palavras

Page 132: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

quedeveriamserincluídas,masnãoforam).

Emgeral,o testepodeajudaraencontrarbugs,masnãoé fácilgerarumbomconjuntodecasosde teste,e,mesmoseconseguir,nãohácomotercertezadequeoprogramaestácorreto.Segundoumlendáriocientistadacomputação:

Testar programas pode ser usado paramostrar a presença de bugs,mas nuncaparamostraraausênciadeles!–EdsgerW.Dijkstra

9.6-Glossário

objetodearquivoUmvalorquerepresentaumarquivoaberto.

reduçãoaumproblemaresolvidoanteriormenteUmmododeresolverumproblemaexpressando-ocomoumainstânciadeumproblemaresolvidoanteriormente.

casoespecialUmcasodetestequeéatípicoounãoéóbvio(ecomprobabilidademenordesertratadocorretamente).

9.7-Exercícios

Exercício9.7

Esta pergunta é baseada emumquebra-cabeça veiculado emumprograma derádiochamadoCarTalk(http://www.cartalk.com/content/puzzlers):

Dê uma palavra com três letras duplas consecutivas. Vou dar exemplos depalavras que quase cumprem a condição,mas não chegam lá. Por exemplo, apalavracommittee,c-o-m-m-i-t-t-e-e.Seriaperfeitasenãofosseaquele‘i’quesemeteualinomeio.OuMississippi:M-i-s-s-i-s-s-i-p-p-i.Sepudessetiraraqueles‘is’,dariacerto.Masháumapalavraquetemtrêsparesconsecutivosdeletrase,que eu saiba, pode ser a única palavra que existe. É claro que provavelmentehajamaisumas500,massóconsigopensarnessa.Qualéapalavra?

Escrevaumprogramaqueaencontre.

Solução:http://thinkpython2.com/code/cartalk1.py.

Page 133: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Exercício9.8

Aqui está outro quebra-cabeça do programa Car Talk(http://www.cartalk.com/content/puzzlers):

“Estavadirigindooutrodia epercebi algonohodômetroquechamouaminhaatenção.Comoamaiorpartedoshodômetros,elemostraseisdígitos,apenasemmilhasinteiras.Porexemplo,seomeucarrotivesse300.000milhas,euveria3-0-0-0-0-0.

“Agora, o que vi naquele dia foi muito interessante. Notei que os últimos 4dígitoseramumpalíndromo;istoé,podiamserlidosdamesmaformanosentidocorretoenosentido inverso.Porexemplo,5-4-4-5éumpalíndromo,entãonomeuhodômetropoderiaser3-1-5-4-4-5.

“Uma milha depois, os últimos 5 números formaram um palíndromo. Porexemplo, poderia ser 3-6-5-4-5-6. Uma milha depois disso, os 4 números domeio,dentrodos6,formavamumpalíndromo.Eadivinhesó?Ummilhadepois,todosos6formavamumpalíndromo!

“Aperguntaé:oqueestavanohodômetroquandoolheiprimeiro?”

Escreva um programa Python que teste todos os números de seis dígitos eimprimaqualquernúmeroquesatisfaçaessascondições.

Solução:http://thinkpython2.com/code/cartalk2.py.

Exercício9.9

AquiestáoutroproblemadoCarTalkquevocêpode resolvercomumabusca(http://www.cartalk.com/content/puzzlers):

“Há pouco tempo recebi uma visita daminhamãe e percebemos que os doisdígitosquecompõemaminhaidade,quandoinvertidos,representavamaidadedela.Porexemplo,seela tem73anos,eu tenho37anos.Ficamos imaginandocomquefrequênciaistoaconteceunosanosanteriores,masacabamosmudandodeassuntoenãochegamosaumaresposta.

“Quando cheguei em casa, cheguei à conclusão de que os dígitos das nossas

Page 134: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

idades tinham sido reversíveis seis vezes até então. Também percebi que, setivéssemossorte, issoacontecerianovamentedaliaalgunsanos,esefôssemosmuito sortudos, aconteceria mais uma vez depois disso. Em outras palavras,aconteceria8vezesnototal.Entãoaperguntaé:quantosanostenhoagora?”

EscrevaumprogramaemPythonquebusquesoluçõesparaesseproblema.Dica:podeserumaboaideiausarométododestringzfill.

Page 135: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo10:ListasEste capítulo apresenta um dos tipos integrados mais úteis do Python: listas.Você também aprenderámais sobre objetos e o que pode acontecer quando omesmoobjetotemmaisdeumnome.

10.1-Umalistaéumasequência

Como uma string, uma lista é uma sequência de valores. Em uma string, osvaloressãocaracteres;emumalista,elespodemserdequalquertipo.Osvaloresemumalistasãochamadosdeelementos,ou,algumasvezes,deitens.

Há várias formas para criar uma lista; amais simples é colocar os elementosentrecolchetes([e]):

[10,20,30,40]

['crunchyfrog','rambladder','larkvomit']

Oprimeiroexemploéuma listadequatronúmeros inteiros.Osegundoéumalistadetrêsstrings.Oselementosdeumalistanãoprecisamserdomesmotipo.Alistaseguintecontémumastring,umnúmerodepontoflutuante,umnúmerointeiroe(olhesó!)outralista:

['spam',2.0,5,[10,20]]

Umalistadentrodeoutralistaéumalistaaninhada.

Umalistaquenãocontémelementoséchamadadelistavazia;vocêpodecriarumacomcolchetesvazios[].

Comojásepoderiaesperar,podemosatribuirumalistadevaloresavariáveis:

>>>cheeses=['Cheddar','Edam','Gouda']

>>>numbers=[42,123]

>>>empty=[]

>>>print(cheeses,numbers,empty)

['Cheddar','Edam','Gouda'][42,123][]

Page 136: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

10.2-Listassãomutáveis

Asintaxeparaacessaroselementosdeumalistaéamesmaqueparaacessaroscaracteres de uma string: o operador de colchete. A expressão dentro doscolchetesespecificaoíndice.Lembre-sedequeosíndicescomeçamem0:

>>>cheeses[0]

'Cheddar'

Diferente das strings, listas são mutáveis. Quando o operador de colcheteaparecedo lado esquerdodeumaatribuição, ele identificao elementoda listaqueseráatribuído:

>>>numbers=[42,123]

>>>numbers[1]=5

>>>numbers

[42,5]

Oprimeiroelementodenumbers,quecostumavaser123,agoraé5.

AFigura10.1mostraodiagramadeestadoparacheeses,numberseempty.

Figura10.1–Diagramadeestadodetrêslistas.

As listas são representadas pelas caixas com a palavra “lista” fora delas e oselementosdalistadentrodelas.cheesesrefere-seaumalistacomtrêselementosindexadoscomo0,1e2.numberscontémdoiselementoseodiagramamostraqueovalordosegundoelementofoireatribuídode123para5.emptyrefere-seaumalistasemelementos.

Page 137: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Índicesdelistasfuncionamdamesmaformaqueosíndicesdestrings:

Qualquerexpressãodenúmerosinteirospodeserusadacomoíndice.

Se tentar ler ou escrever um elemento que não existe, você recebe umIndexError.

Seumíndicetiverumvalornegativo,elecontadetrásparaafrente,apartirdofinaldalista.

Ooperadorintambémfuncionacomlistas:

>>>cheeses=['Cheddar','Edam','Gouda']

>>>'Edam'incheeses

True

>>>'Brie'incheeses

False

10.3-Percorrendoumalista

Aformamaiscomumdepercorreroselementosemumalistaécomumloopfor.Asintaxeéamesmaqueadasstrings:

forcheeseincheeses:

print(cheese)

Issofuncionabemsevocêprecisaapenasleroselementosdalista.Massevocêquer escrever ou atualizar os elementos, você precisa dos índices.Uma formacomumdefazerissoécombinarasfunçõesintegradasrangeelen:

foriinrange(len(numbers)):

numbers[i]=numbers[i]*2

Este loop percorre a lista e atualiza cada elemento. len retorna o número deelementosnalista.rangeretornaumalistadeíndicesde0an-1,emquenéocomprimento da lista. Cada vez que passa pelo loop, i recebe o índice dopróximo elemento. A instrução de atribuição no corpo usa i para ler o valorantigodoelementoeatribuironovovalor.

Umloopforquepasseporumalistavazianuncaexecutaocorpo:

Page 138: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

forxin[]:

print('Thisneverhappens.')

Apesardeumalistapoderconteroutralista,alistaaninhadaaindacontacomoumúnicoelemento.Ocomprimentodestalistaéquatro:

['spam',1,['Brie','Roquefort','PolleVeq'],[1,2,3]]

10.4-Operaçõescomlistas

Ooperador+concatenalistas:

>>>a=[1,2,3]

>>>b=[4,5,6]

>>>c=a+b

>>>c

[1,2,3,4,5,6]

Ooperador*repetealistaumdadonúmerodevezes:

>>>[0]*4

[0,0,0,0]

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

[1,2,3,1,2,3,1,2,3]

Oprimeiroexemplorepete[0]quatrovezes.Osegundoexemplorepetealista[1,2,3]trêsvezes.

10.5-Fatiasdelistas

Ooperadordefatiamentotambémfuncionacomlistas:

>>>t=['a','b','c','d','e','f']

>>>t[1:3]

['b','c']

>>>t[:4]

['a','b','c','d']

>>>t[3:]

['d','e','f']

Se você omitir o primeiro índice, a fatia começa no início. Se você omitir osegundo,afatiavaiatéofinal.Sevocêomitirambos,afatiaéumacópiadalista

Page 139: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

inteira.

>>>t[:]

['a','b','c','d','e','f']

Como as listas sãomutáveis, pode ser útil fazer uma cópia antes de executaroperaçõesqueasalterem.

Um operador de fatia à esquerda de uma atribuição pode atualizar várioselementos:

>>>t=['a','b','c','d','e','f']

>>>t[1:3]=['x','y']

>>>t

['a','x','y','d','e','f']

10.6-Métodosdelistas

OPythonoferecemétodosqueoperamemlistas.Porexemplo,appendadicionaumnovoelementoaofimdeumalista:

>>>t=['a','b','c']

>>>t.append('d')

>>>t

['a','b','c','d']

extendtomaumalistacomoargumentoeadicionatodososelementos:

>>>t1=['a','b','c']

>>>t2=['d','e']

>>>t1.extend(t2)

>>>t1

['a','b','c','d','e']

Esteexemplodeixat2intocado.

sortclassificaoselementosdalistaemordemascendente:

>>>t=['d','c','e','b','a']

>>>t.sort()

>>>t

['a','b','c','d','e']

Page 140: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Amaiorpartedosmétodosde listas sãonulos; eles alterama lista e retornamNone. Se você escrever t = t.sort() por acidente, ficará desapontado com oresultado.

10.7-Mapeamento,filtragemeredução

Parasomaro totalde todososnúmerosemumalista,vocêpodeusarumloopcomoesse:

defadd_all(t):

total=0

forxint:

total+=x

returntotal

totaléinicializadocom0.Cadavezqueoprogramapassapeloloop,xrecebeumelementodalista.Ooperador+=ofereceumaformacurtadeatualizarumavariável.Estainstruçãodeatribuiçãoaumentada,

total+=x

éequivalentea

total=total+x

Nodecorrerda execuçãodo loop,total acumula a somados elementos; umavariávelusadadestaformaàsvezeséchamadadeacumuladora.

SomartodoselementosdeumalistaéumaoperaçãotãocomumqueoPythonaoferececomoumafunçãointegrada,sum:

>>>t=[1,2,3]

>>>sum(t)

6

Uma operação como essa, que combina uma sequência de elementos em umúnicovalor,àsvezeséchamadaderedução.

Algumasvezesvocêquerpercorrerumalistaenquantocriaoutra.Porexemplo,a função seguinte recebe uma lista de strings e retorna uma nova lista quecontémstringscomletrasmaiúsculas:

Page 141: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

defcapitalize_all(t):

res=[]

forsint:

res.append(s.capitalize())

returnres

reséinicializadocomumalistavazia;cadavezqueoprogramapassapeloloop,acrescentamosopróximoelemento.Entãoreséoutrotipodeacumulador.

Uma operação como capitalize_all às vezes é chamada de mapeamentoporqueela“mapeia”umafunção(nessecasoométodocapitalize)sobrecadaumdoselementosemumasequência.

Outraoperaçãocomuméselecionaralgunsdoselementosdeumalistaeretornaruma sublista. Por exemplo, a função seguinte recebe uma lista de strings eretornaumalistaquecontémapenasstringsemletramaiúscula:

defonly_upper(t):

res=[]

forsint:

ifs.isupper():

res.append(s)

returnres

isupper é ummétodo de string que retorna True se a string contiver apenasletrasmaiúsculas.

Uma operação como only_upper é chamada de filtragem porque filtra algunsdoselementosedesconsideraoutros.

Asoperaçõesdelistamaiscomunspodemserexpressascomoumacombinaçãodemapeamento,filtragemeredução.

10.8-Comoexcluirelementos

Há várias formas de excluir elementos de uma lista. Se souber o índice doelementoqueprocura,vocêpodeusarpop:

>>>t=['a','b','c']

>>>x=t.pop(1)

>>>t

['a','c']

Page 142: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>x

'b'

popalteraalistaeretornaoelementoquefoiexcluído.Sevocênãoincluirumíndice,eleexcluieretornaoúltimoelemento.

Senãoprecisardovalorremovido,vocêpodeusarainstruçãodel:

>>>t=['a','b','c']

>>>delt[1]

>>>t

['a','c']

Se souber o elemento que quer excluir (mas não o índice), você pode usarremove:

>>>t=['a','b','c']

>>>t.remove('b')

>>>t

['a','c']

OvalordevolvidoporremoveéNone.

Pararemovermaisdeumelemento,vocêpodeusardelcomumíndicedefatia:

>>>t=['a','b','c','d','e','f']

>>>delt[1:5]

>>>t

['a','f']

Como sempre, a fatia seleciona todos os elementos até,mas não incluindo, osegundoíndice.

10.9-Listasestrings

Uma string é uma sequência de caracteres e uma lista é uma sequência devalores,masumalistadecaracteresnãoéamesmacoisaqueumastring.Paraconverterumastringemumalistadecaracteres,vocêpodeusarlist:

>>>s='spam'

>>>t=list(s)

>>>t

['s','p','a','m']

Page 143: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Comolist é o nomede uma função integrada, você deve evitar usá-lo comonomedevariável.Tambémevitousarlporqueparecedemaiscom1.Éporissoqueusot.

Afunçãolistquebraumastringemletrasindividuais.Sevocêquiserquebrarumastringempalavras,vocêpodeusarométodosplit:

>>>s='piningforthefjords'

>>>t=s.split()

>>>t

['pining','for','the','fjords']

Um argumento opcional chamado delimiter especifica quais caracteres podemserusadosparademonstraroslimitesdaspalavras.Oexemploseguinteusaumhífencomodelimitador:

>>>s='spam-spam-spam'

>>>delimiter='-'

>>>t=s.split(delimiter)

>>>t

['spam','spam','spam']

join é o contrário de split. Ele toma uma lista de strings e concatena oselementos.joinéummétododestring,entãoéprecisoinvocá-lonodelimitadorepassaralistacomoparâmetro:

>>>t=['pining','for','the','fjords']

>>>delimiter=''

>>>s=delimiter.join(t)

>>>s

'piningforthefjords'

Nesse caso, o delimitador é um caractere de espaço, então join coloca umespaçoentreaspalavras.Paraconcatenarstringssemespaços,vocêpodeusarastringvazia'',comodelimitador.

##10.10-Objetosevalores

Seexecutarmosessasinstruçõesdeatribuição:

a='banana'

b='banana'

Page 144: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Sabemosqueaebsereferemaumastring,masnãosabemosseelassereferemàmesmastring.Hádoisestadospossíveis,mostradosnaFigura10.2.

Figura10.2–Diagramasdeestadopossíveiscomduasvariáveis.

Emumcaso,aebsereferemadoisobjetosdiferentesquetêmomesmovalor.Nosegundocaso,elassereferemaomesmoobjeto.

Paraverificarseduasvariáveisse referemaomesmoobjeto,vocêpodeusarooperadoris:

>>>a='banana'

>>>b='banana'

>>>aisb

True

Nesseexemplo,oPythoncriouapenasumobjetodestringetantoaquantobsereferemaele.Masquandovocêcriaduaslistas,vocêtemdoisobjetos:

>>>a=[1,2,3]

>>>b=[1,2,3]

>>>aisb

False

EntãoodiagramadeestadoficaigualaodaFigura10.3.

Figura10.3–Diagramadeestadocomvariáveisassociadasa listasdistintas,demesmovalor.

Nesse caso, diríamos que as duas listas são equivalentes, porque elas têm osmesmoselementos,masnãoidênticas,porqueelasnãosãoomesmoobjeto.Sedoisobjetos forem idênticos,eles tambémsãoequivalentes,masseeles foremequivalentes,nãosãonecessariamenteidênticos.

Atéagora,temosusado“objeto”e“valor”deformaintercambiável,masémaisexatodizerqueumobjetotemumvalor.Seavaliar[1,2,3],vocêtemumobjeto

Page 145: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

de lista cujovalor é uma sequência denúmeros inteiros.Seoutra lista temosmesmoselementos,dizemosquetemomesmovalor,masnãoéomesmoobjeto.

10.11-Alias

Se a se refere a um objeto e você atribui b = a, então ambas as variáveis sereferemaomesmoobjeto.

>>>a=[1,2,3]

>>>b=a

>>>bisa

True

OdiagramadeestadoficaráigualàFigura10.4.

Figura 10.4 – Diagrama de estado com duas variáveis associadas à mesmalista.

A associação de uma variável com um objeto é chamada de referência.Nesteexemplo,háduasreferênciasaomesmoobjeto.

Umobjetocommaisdeumareferência temmaisdeumnome,entãodizemosqueoobjetotemumalias.

Seoobjeto comalias émutável, alterações feitas emumalias afetamooutrotambém.

>>>b[0]=42

>>>a

[42,2,3]

Apesardeessecomportamentopoderserútil,eleépassíveldeerros.Emgeral,émaisseguroevitarusaraliasaotrabalharcomobjetosmutáveis.

Paraobjetos imutáveiscomostrings,usaraliasnãoéumproblematãogrande.Nesteexemplo:

a='banana'

Page 146: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

b='banana'

Quasenuncafazdiferençaseaebsereferemàmesmastringounão.

10.12-Argumentosdelistas

Aopassarumalistaaumafunção,afunçãorecebeumareferênciaàlista.Seafunção alterar a lista, quem faz a chamada vê a mudança. Por exemplo,delete_headremoveoprimeiroelementodeumalista:

defdelete_head(t):

delt[0]

Elaéusadaassim:

>>>letters=['a','b','c']

>>>delete_head(letters)

>>>letters

['b','c']

Oparâmetroteavariávelletterssãoaliasparaomesmoobjeto.OdiagramadapilhaficaigualaodaFigura10.5.

Figura 10.5 – Diagrama da pilha: __main__ e delete_head compartilhamreferênciasàmesmalista.

Comoalistaécompartilhadapordoisframes,desenhei-aentreeles.

Éimportantedistinguirentreoperaçõesquealteramlistaseoperaçõesquecriamnovaslistas.Porexemplo,ométodoappendalteraalista,masooperador+criaumanovalista:

>>>t1=[1,2]

>>>t2=t1.append(3)

>>>t1

[1,2,3]

>>>t2

None

Page 147: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

NotequeappendalteraalistaeretornaNone(narealidade,oconsoledoPythonomiteoNonedasaída,masvocêpodeconferirusandot2isNone).

>>>t3=t1+[4]

>>>t1

[1,2,3]

>>>t3

[1,2,3,4]

>>>t1

Ooperador+criaumanovalistaedeixaalistaoriginalinalterada.

Essa diferença é importante quando você escreve funções que devem alterarlistas.Porexemplo,estafunçãonãoremoveacabeçadeumalista:

defbad_delete_head(t):

t=t[1:]#ERRADO!

Ooperadordefatiacriaumanovalistaeaatribuiçãofaztsereferiraela,masissonãoafetaquemfazchamada.

>>>t4=[1,2,3]

>>>bad_delete_head(t4)

>>>t4

[1,2,3]

No iníciodebad_delete_head, t e t4 se referemàmesma lista.No final, t serefereaumanovalista,mast4aindaserefereàlistaoriginal,inalterada.

Umaalternativa é escrever uma funçãoque crie e retorneumanova lista. Porexemplo,tailretornatudo,excetooprimeiroelementodeumalista:

deftail(t):

returnt[1:]

Estafunçãodeixaalistaoriginalinalterada.Elaéusadaassim:

>>>letters=['a','b','c']

>>>rest=tail(letters)

>>>rest

['b','c']

10.13-Depuração

Page 148: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Ousodescuidadode listas (e deoutrosobjetosmutáveis) pode levar a longashorasdedepuração.Aquiestãoalgumasarmadilhascomunseformasdeevitá-las:

1. AmaiorpartedosmétodosdelistasalteramoargumentoeretornamNone.Isto é o oposto dosmétodos de strings, que retornam uma nova string edeixamaoriginalintocada.

Sevocêestáacostumadoaescrevercódigodestringsdestaforma:

word=word.strip()

Étentadorescrevercódigodelistascomoeste:

t=t.sort()#ERRADO!

Como sort retornaNone, a próximaoperaçãoque você executar com tprovavelmentevaifalhar.

Antesdeusarmétodoseoperadoresdelistas,vocêdeveleradocumentaçãocomcuidadoetestá-losnomodointerativo.

2. Escolhaotermoefiquecomele.

Partedoproblemacomlistaséquehámuitasformasdefazercoisascomelas.Porexemplo,pararemoverumelementodeumalistavocêpodeusarpop,remove,delouatéumaatribuiçãodefatia.

Paraadicionarumelementovocêpodeusarométodoappendouooperador+.Assumindoquetéumalistaexéumelementodalista,istoestácorreto:

t.append(x)

t=t+[x]

t+=[x]

Eistoestáerrado:

t.append([x])#ERRADO!

t=t.append(x)#ERRADO!

t+[x]#ERRADO!

t=t+x#ERRADO!

Experimentecadaumdessesexemplosnomodointerativoparaconferirsevocêentendeuoquefazem.Notequeapenasoúltimocausaumerrodetempo

Page 149: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

deexecução;osoutrostrêssãolegais,maselesfazemacoisaerrada.

3. Façacópiasparaevitarousodealias.

Sequiserusarummétodocomosort,quealteraoargumento,masprecisamanteralistaoriginal,vocêpodefazerumacópia:

>>>t=[3,1,2]

>>>t2=t[:]

>>>t2.sort()

>>>t

[3,1,2]

>>>t2

[1,2,3]

Nesteexemplovocêpoderiausartambémafunçãointegradasorted,queretornaumanovalistaclassificadaedeixaaoriginalintocada.

>>>t2=sorted(t)

>>>t

[3,1,2]

>>>t2

[1,2,3]

10.14-Glossário

listaUmasequênciadevalores.

elementoUm dos valores em uma lista (ou outra sequência), também chamado deitem.

listaaninhadaUmalistaqueéumelementodeoutralista.

acumuladoraVariávelusadaemumloopparaadicionarouacumularumresultado.

atribuiçãoaumentadaInstruçãoqueatualizaovalordeumavariávelusandoumoperadorcomo+=.

reduçãoPadrão de processamento que atravessa uma sequência e acumula oselementosemumúnicoresultado.

Page 150: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

mapeamentoPadrão de processamento que atravessa uma sequência e executa umaoperaçãoemcadaelemento.

filtragemPadrãodeprocessamentoqueatravessaumalistaeselecionaoselementosquesatisfazemalgumcritério.

objetoAlgoaqueumavariávelpodesereferir.Umobjetotemumtipoeumvalor.

equivalenteTeromesmovalor.

idênticoSeromesmoobjeto(oqueimplicaequivalência).

referênciaAssociaçãoentreumavariáveleseuvalor.

aliasUma circunstância onde duas ou mais variáveis se referem ao mesmoobjeto.

delimitadorUmcaractere ou uma string usada para indicar onde uma string deve serdividida.

10.15-Exercícios

Você pode baixar as soluções para estes exercícios emhttp://thinkpython2.com/code/list_exercises.py.

Exercício10.1

Escreva uma função chamada nested_sum que receba uma lista de listas denúmeros inteiros e adicione os elementos de todas as listas aninhadas. Porexemplo:

>>>t=[[1,2],[3],[4,5,6]]

>>>nested_sum(t)

21

Exercício10.2

Escreva uma função chamada cumsum que receba uma lista de números e

Page 151: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

retorneasomacumulativa; istoé,umanova listaondeo i-ésimoelementoéasomadosprimeirosi+1elementosdalistaoriginal.Porexemplo:

>>>t=[1,2,3]

>>>cumsum(t)

[1,3,6]

Exercício10.3

Escrevaumafunçãochamadamiddlequerecebaumalistaeretorneumanovalista com todos os elementos originais, exceto os primeiros e os últimoselementos.Porexemplo:

>>>t=[1,2,3,4]

>>>middle(t)

[2,3]

Exercício10.4

Escrevaumafunçãochamadachopquetomeumalistaalterando-apararemoveroprimeiroeoúltimoelementos,eretorneNone.Porexemplo:

>>>t=[1,2,3,4]

>>>chop(t)

>>>t

[2,3]

Exercício10.5

Escrevauma função chamada is_sorted que tomeuma lista comoparâmetro eretorneTruesealistaestiverclassificadaemordemascendente,eFalsesenãoforocaso.Porexemplo:

>>>is_sorted([1,2,2])

True

>>>is_sorted(['b','a'])

False

Exercício10.6

Duaspalavrassãoanagramassevocêpudersoletrarumarearranjandoasletras

Page 152: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

da outra. Escreva uma função chamada is_anagram que tome duas strings eretorneTrueseforemanagramas.

Exercício10.7

Escrevaumafunçãochamadahas_duplicatesquetomeumalistaeretorneTruesehouveralgumelementoqueapareçamaisdeumavez.Elanãodevemodificaralistaoriginal.

Exercício10.8

EsteexercíciopertenceaoassimchamadoParadoxodeaniversário,sobreoqualvocêpodeleremhttp://en.wikipedia.org/wiki/Birthday_paradox.

Se há 23 alunos na sua sala, quais são as chances de dois deles fazeremaniversário no mesmo dia? Você pode estimar esta probabilidade gerandoamostrasaleatóriasde23diasdeaniversárioeverificandoascorrespondências.Dica:vocêpodegeraraniversáriosaleatórioscoma função randintnomódulorandom.

Se quiser, você pode baixar minha solução emhttp://thinkpython2.com/code/birthday.py.

Exercício10.9

Escrevaumafunçãoqueleiaoarquivowords.txteconstruaumalistacomumelementoporpalavra.Escrevaduasversõesdestafunção,umausandoométodoappendeoutrausandoaexpressãot=t+[x].Quallevamaistempoparaserexecutada?Porquê?

Solução:http://thinkpython2.com/code/wordlist.py.

Exercício10.10

Paraverificarseumapalavraestánalistadepalavras,vocêpodeusarooperadorin,masissoserialentoporquepesquisariaaspalavrasemordem.

Comoas palavras estão emordemalfabética, podemos acelerar as coisas comuma busca por bisseção (também conhecida como pesquisa binária), que é

Page 153: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

semelhante ao que você faz quando procura uma palavra no dicionário. Vocêcomeçanomeioeverificaseapalavraqueestáprocurandovemantesdapalavranomeio da lista. Se for o caso, procura na primeirametade da lista. Se não,procuranasegundametade.

Dequalquerforma,vocêcortaoespaçodebuscarestantepelametade.Sealistade palavras tiver 113.809 palavras, o programa seguirá uns 17 passos paraencontrarapalavraouconcluirquenãoestálá.

Escreva uma função chamada in_bisect que receba uma lista ordenada, umvalor-alvoedevolvaoíndicedovalornalistaseeleestiverlá,ouNonesenãoestiver.

Ouvocêpodeleradocumentaçãodomódulobisecteusá-lo!

Solução:http://thinkpython2.com/code/inlist.py.

Exercício10.11

Duaspalavrassãoum“parinverso”seumaforocontráriodaoutra.Escrevaumprogramaqueencontretodososparesinversosnalistadepalavras.

Solução:http://thinkpython2.com/code/reverse_pair.py.

Exercício10.12

Duas palavras “interligam-se” quando, ao tomarmos letras alternadas de cadauma,formamosumapalavranova.Porexemplo,“shoe”e“cold” interligam-separaformar“schooled”.

Solução: http://thinkpython2.com/code/interlock.py. Crédito: este exercício foiinspiradoporumexemploemhttp://puzzlers.org.

1. Escreva um programa que encontre todos os pares de palavras que seinterligam.Dica:nãoenumeretodosospares!

2. Vocêpodeencontrarpalavrasquesejaminterligadasdetrêsemtrês;istoé,cadaterceiraletraformaumapalavra,começandodaprimeira,segundaouterceira?

Page 154: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo11:DicionáriosEstecapítuloapresentaoutrotipointegradochamadodicionário.Dicionáriossãoumdosmelhores recursos doPython; eles sãoos blocos demontar demuitosalgoritmoseficienteseelegantes.

11.1-Umdicionárioéummapeamento

Um dicionário se parece com uma lista, mas é mais geral. Em uma lista, osíndices têm que ser números inteiros; em um dicionário, eles podem ser de(quase)qualquertipo.

Umdicionário contémuma coleção de índices, que se chamam chaves e umacoleçãodevalores.Cadachaveéassociadacomumúnicovalor.Aassociaçãodeumachaveeumvalorchama-separchave-valorouitem.

Emlinguagemmatemática,umdicionáriorepresentaummapeamentodechavesavalores,paraquevocêpossadizerquecadachave“mostraomapaa”umvalor.Comoexemplo,vamosconstruirumdicionárioque fazomapadepalavrasdoinglêsaoespanhol,portantoaschaveseosvaloressãotodosstrings.

Afunçãodictcriaumnovodicionáriosemitens.Comodictéonomedeumafunçãointegrada,vocêdeveevitarusá-locomonomedevariável.

>>>eng2sp=dict()

>>>eng2sp

{}

As chaves {} representam um dicionário vazio. Para acrescentar itens aodicionário,vocêpodeusarcolchetes:

>>>eng2sp['one']='uno'

Esta linha cria um item que mapeia da chave 'one' ao valor 'uno'. Seimprimirmos o dicionário novamente, vemos um par chave-valor com doispontosentreachaveeovalor:

>>>eng2sp

Page 155: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

{'one':'uno'}

Esteformatodesaídatambéméumformatodeentrada.Porexemplo,vocêpodecriarumdicionáriocomtrêsitens:

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

Porém,seexibireng2sp,podesesurpreender:

>>>eng2sp

{'one':'uno','three':'tres','two':'dos'}

Aordemdospareschave-valorpodenãoseramesma.Sevocêdigitaromesmoexemplono seucomputador,pode receberum resultadodiferente.Emgeral, aordemdositensemumdicionárioéimprevisível.

No entanto, isso não é um problema porque os elementos de um dicionárionuncasãoindexadoscomíndicesdenúmerosinteiros.Emvezdisso,vocêusaaschavesparaprocurarosvalorescorrespondentes:

>>>eng2sp['two']

'dos'

A chave 'two' sempre mapeia ao valor 'dos', assim a ordem dos itens nãoimporta.

Seachavenãoestivernodicionário,vocêrecebeumaexceção:

>>>eng2sp['four']

KeyError:'four'

A função len é compatível com dicionários; ela devolve o número de pareschave-valor:

>>>len(eng2sp)

3

Ooperadorinfuncionaemdicionáriostambém;eleacusasealgoaparececomochavenodicionário(aparecercomovalornãoéosuficiente).

>>>'one'ineng2sp

True

>>>'uno'ineng2sp

Page 156: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

False

Para ver se algo aparece como umvalor em umdicionário, você pode usar ométodovalues,quedevolveumacoleçãodevalores,eentãousarooperadorin:

>>>vals=eng2sp.values()

>>>'uno'invals

True

Ooperadorinusaalgoritmosdiferentesparalistasedicionários.Paralistas,eleprocuraoselementosdalistaemordem,comodescritoem“Busca”,napágina123. Conforme a lista torna-se mais longa, o tempo de busca também ficaproporcionalmentemaislongo.

Para dicionários, o Python usa um algoritmo chamado hashtable (tabela dedispersão),quetemumapropriedadenotável:ooperadorinlevapraticamenteomesmo tempo na busca, não importa quantos itens estejam no dicionário. Euexplicocomoissoépossívelem“Hashtables”,napágina302,masaexplicaçãopodenãofazersentidoatéquevocêtenhalidomaisalgunscapítulos.

11.2-Umdicionáriocomoumacoleçãodecontadores

Suponha que você receba uma string e queira contar quantas vezes cada letraaparecenela.Háváriosmodosdefazerisso:

1. Vocêpodecriar26variáveis,umaparacadaletradoalfabeto.Entãopodeatravessar a string e, para cada caractere, incrementar o contadorcorrespondente,provavelmenteusandoumacondicionalencadeada.

2. Você pode criar uma lista com 26 elementos. Então pode converter cadacaractereemumnúmero(comafunçãointegradaord),usaronúmerocomoíndicenalistaeincrementarorespectivocontador.

3. Você pode criar um dicionário com caracteres como chaves e contadorescomo valores correspondentes. Na primeira vez que visse um caractere,você acrescentaria um item ao dicionário. Depois disso, incrementaria ovalordeumitemexistente.

Cadaumadessasopçõesexecutaomesmocálculo,masoimplementadeformadiferente.

Page 157: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Uma implementação é um modo de executar um cálculo; algumasimplementações são melhores que outras. Por exemplo, uma vantagem daimplementação de dicionários é que não precisamos saber de antemão quaisletrasaparecemnastringesóéprecisocriarespaçoparaasletrasquerealmentevenhamaaparecer.

Ocódigopoderiaserassim:

defhistogram(s):

d=dict()

forcins:

ifcnotind:

d[c]=1

else:

d[c]+=1

returnd

O nome da função é histogram, um termo estatístico para uma coleção decontadores(oufrequências).

A primeira linha da função cria um dicionário vazio. O loop for atravessa astring.Cadavezquepassapeloloop,seocaracterecnãoestivernodicionário,criamosumitemcomachaveceovalorinicial1(poisjávimosestaletraumavez).Seocjáestivernodicionário,incrementamosd[c].

Funcionaassim:

>>>h=histogram('brontosaurus')

>>>h

{'a':1,'b':1,'o':2,'n':1,'s':2,'r':2,'u':2,'t':1}

Ohistograma indica que as letras 'a' e 'b' aparecemumavez; 'o' aparece duasvezes,eassimpordiante.

Osdicionários têmummétodochamadoget,que tomaumachaveeumvalorpadrão.Seachaveaparecernodicionário,getretornaovalorcorrespondente;senãoforocaso,eleretornaovalorpadrão.Porexemplo:

>>>h=histogram('a')

>>>h

{'a':1}

>>>h.get('a',0)

1

Page 158: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>h.get('b',0)

0

Como exercício, use o get para escrever a função histogram de forma maisconcisa.Tenteeliminarainstruçãoif.

11.3-Loopedicionários

Se usar um dicionário em uma instrução for, ela percorre as chaves dodicionário.Porexemplo,print_histexibecadachaveeovalorcorrespondente:

defprint_hist(h):

forcinh:

print(c,h[c])

Issoéoqueaparece:

>>>h=histogram('parrot')

>>>print_hist(h)

a1

p1

r2

t1

o1

Novamente, as chaves não estão em nenhuma ordem determinada. Paraatravessar as chaves emordemascendente, você podeusar a função integradasorted:

>>>forkeyinsorted(h):

...print(key,h[key])

a1

o1

p1

r2

t1

11.4-Buscareversa

Considerando um dicionário d e uma chave k, é fácil encontrar o valorcorrespondentev=d[k].Estaoperaçãochama-sebusca.

Page 159: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Mas e se você tiver v e quiser encontrar k? Você tem dois problemas: emprimeiro lugar,podehavermaisdeumachavequeestejamapeadaaovalorv.Dependendodaaplicação,quemsabevocêpodeescolherum,outalveztenhadefazer uma lista que contenha todos eles. Em segundo lugar, não há sintaxesimplesparafazerumabuscareversa;éprecisoprocurar.

Aquiestáumafunçãoquerecebeumvaloreretornaaprimeirachavemapeadaaovalordado:

defreverse_lookup(d,v):

forkind:

ifd[k]==v:

returnk

raiseLookupError()

Essa funçãoémaisumexemplodopadrãodebusca,masusaum recursoqueaindanão tínhamosvisto:raise.A instruçãoraise causauma exceção; nestecaso,causaumLookupError,queéumaexceção integrada,usadapara indicarqueumaoperaçãodebuscafalhou.

Sechegarmosaofimdoloopsignificaquevnãoaparecenodicionáriocomoumvalor,portantoapresentaremosumaexceção.

Aquiestáumexemplodeumabuscareversabemsucedida:

>>>h=histogram('parrot')

>>>k=reverse_lookup(h,2)

>>>k

'r'

Eumamalsucedida:

>>>k=reverse_lookup(h,3)

Traceback(mostrecentcalllast):

File"<stdin>",line1,in<module>

File"<stdin>",line5,inreverse_lookup

LookupError

Oefeitocausadoporvocêaoapresentarumaexceçãoé igualaocausadopeloPythonquandofazomesmo:eleexibeumtracebackeumamensagemdeerro.

A instrução raise pode receber uma mensagem de erro detalhada como

Page 160: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

argumentoopcional.Porexemplo:

>>>raiseLookupError('valuedoesnotappearinthedictionary')

Traceback(mostrecentcalllast):

File"<stdin>",line1,in?

LookupError:valuedoesnotappearinthedictionary

Umabuscareversaémuitomaislentaqueumabuscanosentidonormal;seforpreciso fazê-lo muitas vezes, ou se o dicionário ficar muito grande, odesempenhodoseuprogramaseráprejudicado.

11.5-Dicionárioselistas

Aslistaspodemaparecercomovaloresemumdicionário.Porexemplo,sevocêreceberumdicionárioquemapeieletrasefrequências,éumaboaideiainvertê-lo; isto é, crie um dicionário quemapeie de frequências a letras. Como podehaverváriasletrascomamesmafrequência,cadavalornodicionárioinvertidodeveserumalistadeletras.

Aquiestáumafunçãoqueinverteumdicionário:

definvert_dict(d):

inverse=dict()

forkeyind:

val=d[key]

ifvalnotininverse:

inverse[val]=[key]

else:

inverse[val].append(key)

returninverse

Cadavezqueoprogramapassarpeloloop,akeyrecebeumachavededevalrecebeovalorcorrespondente.Sevalnãoestivereminversesignificaquenãofoivistaantes,entãocriamosumitemeoinicializamoscomumitemavulso(eminglês,singleton,umalistaquecontémumúnicoelemento).Senãoforocasoéporque vimos esse valor antes, então acrescentamos a chave correspondente àlista.

Aquiestáumexemplo:

>>>hist=histogram('parrot')

>>>hist

Page 161: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

{'a':1,'p':1,'r':2,'t':1,'o':1}

>>>inverse=invert_dict(hist)

>>>inverse

{1:['a','p','t','o'],2:['r']}

AFigura11.1éumdiagramadeestadomostrandohisteinverse.Umdicionárioé representado como uma caixa como tipo dict acima dela e os pares chave-valor no interior. Se os valores foremnúmeros inteiros, de ponto flutuante oustrings,desenho-osdentrodacaixa,masnormalmenteprefirodesenharlistasdoladodefora,paramanterodiagramasimples.

Figura11.1–Diagramadeestadodeumdicionárioeseuinverso.

Aslistaspodemservaloresemumdicionário,comomostraesteexemplo,masnãopodemserchaves.Issoéoqueacontecesevocêtentar:

>>>t=[1,2,3]

>>>d=dict()

>>>d[t]='oops'

Traceback(mostrecentcalllast):

File"<stdin>",line1,in?

TypeError:listobjectsareunhashable

Jámencionei que umdicionário é implementado usando umahashtable e issosignifica que é preciso que as chaves possam ser hashable (que seja possívelcomputarseuhash,equeestevalordehashsejaimutável).

hashéumafunçãoquerecebeumvalor(dequalquertipo)edevolveumnúmerointeiro.Dicionáriosusamessesnúmeros inteiros, chamadosvaloreshash,paraguardarebuscarpareschave-valor.

Page 162: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Estesistemafuncionaperfeitamenteseaschavesforemimutáveis.Porém,seaschavessãomutáveis,comolistas,coisasruinsacontecem.Porexemplo,quandovocê cria um par chave-valor, o Python guarda a chave na posiçãocorrespondente.Sevocêmodificarachaveeentãoguardá-lanovamente,elairiapara umaposiçãodiferente.Nesse caso, vocêpoderia ter duas entradaspara amesmachave,oupodenãoconseguirencontrarumachave.Dequalquerforma,odicionárionãofuncionariacorretamente.

Éporissoqueaschavestêmdeserhashable,etiposmutáveiscomolistas,nãosão.A formamais simples de resolver esta limitação é usar tuplas, que serãovistasnopróximocapítulo.

Comoosdicionáriossãomutáveis,elesnãopodemserusadoscomochaves,maspodemserusadoscomovalores.

11.6-Memos

Seusouafunçãodefibonacciem“Maisumexemplo”,napágina101,podeternotadoquequantomaioroargumentodadomais tempoafunçãolevaparaserexecutada.Alémdisso,otempodeexecuçãoaumentarapidamente.

Paraentenderporque,considereaFigura11.2,quemostraográficodechamadadefibonaccicomn=4.

Page 163: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Figura11.2–Gráficodechamadaparafibonacci.

Umgráficode chamadamostraumconjuntode framesde função, com linhasqueunemcadaframeaosframesdasfunçõesquechama.Napartedecimadográfico, fibonacci com n=4 chama fibonacci com n=3 e n=2. Por sua vez,fibonaccicomn=3chamafibonaccicomn=2en=1.Eassimpordiante.

Contequantasvezesfibonacci(0)efibonacci(1)sãochamadas.Essaéumasolução ineficiente para o problema, e piora conforme o argumento se tornamaior.

Uma solução é acompanhar os valores que já foram calculados, guardando-osemumdicionário.Umvalorcalculadoanteriormentequeéguardadoparausoposterioréchamadodememo.Aquiestáumaversãocommemosdefibonacci:

known={0:0,1:1}

deffibonacci(n):

ifninknown:

returnknown[n]

res=fibonacci(n-1)+fibonacci(n-2)

known[n]=res

returnres

known é um dicionário que monitora os números de Fibonacci que já

Page 164: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

conhecemos.Começacomdoisitens:0mapeiaa0e1mapeiaa1.

Semprequefibonacciéchamada,elaverificaknown.Seoresultadojáestiverlá,podevoltarimediatamente.Senãoforocaso,éprecisocalcularonovovalor,acrescentá-loaodicionárioedevolvê-lo.

Se você executar essa versão de fibonacci e a comparar com a original,descobriráqueémuitomaisrápida.

11.7-Variáveisglobais

Noexemplo anterior, known é criada fora da função, então pertence ao frameespecialchamado__main__.Asvariáveisem__main__àsvezessãochamadasdeglobais,porquepodemseracessadasdequalquerfunção.Emcontrastecomas variáveis locais, que desaparecem quando sua função termina, as variáveisglobaispersistemdeumachamadadafunçãoàseguinte.

É comum usar variáveis globais para flags; isto é, variáveis booleanas queindicam(“flag”)seumacondiçãoéverdadeira.Porexemplo,algunsprogramasusamumflagdenominadoverboseparacontrolaroníveldedetalhedasaída:

verbose=True

defexample1():

ifverbose:

print('Runningexample1')

Se tentar reatribuir umavariável global, vocêpode se surpreender.Opróximoexemplomostracomoacompanharseafunçãofoichamada:

been_called=False

defexample2():

been_called=True#ERRADO

Porém, se executá-la, você verá que o valor de been_called não se altera.Oproblemaéqueexample2criaumanovavariávellocalchamadabeen_called.Avariável localsomequandoa função terminaenão temefeitosobreavariávelglobal.

Para reatribuir uma variável global dentro de uma função é preciso declarar avariávelcomoglobalantesdeusá-la:

Page 165: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

been_called=False

defexample2():

globalbeen_called

been_called=True

Ainstruçãoglobaldizaointerpretadoralgocomo“Nestafunção,quandodigobeen_called,estoufalandodavariávelglobal;nãocrieumalocal”.

Aquiestáumexemploquetentaatualizarumavariávelglobal:

count=0

defexample3():

count=count+1#ERRADO

Seexecutá-la,vocêrecebe:

UnboundLocalError:localvariable'count'referencedbeforeassignment

OPythonsupõequecount seja local,edentrodestasuposição,avariávelestásendolidaantesdeserescrita.Asolução,maisumavez,édeclararcountcomoglobal:

defexample3():

globalcount

count+=1

Seumavariávelglobalsereferiraumvalormutável,vocêpodealterarovalorsemdeclararavariável:

known={0:0,1:1}

defexample4():

known[2]=1

Entãovocêpodeadicionar,retiraresubstituirelementosdeumalistaglobaloudicionário,massequiserreatribuiravariável,precisadeclará-la:

defexample5():

globalknown

known=dict()

Asvariáveisglobaispodemserúteis,massevocêtivermuitasdelasealterá-lascomfrequência,issopoderádificultaradepuraçãodoprograma.

Page 166: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

11.8-Depuração

Aotrabalharcomconjuntosdedadosmaiores,depurarexibindoeverificandoasaída à mão pode ser trabalhoso. Aqui estão algumas sugestões para depurargrandesconjuntosdedados:

ReduzaaentradaSeforpossível,reduzaotamanhodoconjuntodedados.Porexemplo,seoprograma lê um arquivo de texto, comece com apenas as 10 primeiraslinhas,oucomomenorexemploquepuderencontrar.Vocêpodeeditarospróprios arquivos ou alterar o programa para que leia só as primeiras nlinhas(émelhor).Se houver um erro, você pode reduzir n aomenor valor quemanifeste oerro,eentãoaumentá-logradativamenteatéencontrarecorrigiroerro.

VerifiqueosresumosetiposEmvezdeimprimireverificaroconjuntodedadosinteiro,penseemexibirresumosdosdados:porexemplo,onúmerodeitensemumdicionárioouototaldeumalistadenúmeros.Uma causa comum de erros em tempo de execução são valores de tipoincompatível.Paradepuraressaespéciedeerro,muitasvezesbastaexibirotipodeumvalor.

CrieautoverificaçõesÉ possível escrever o código para verificar erros automaticamente. Porexemplo,seestivercalculandoamédiadeumalistadenúmeros,vocêpodeverificar se o resultadonão émais alto queomaior elementoda lista oumais baixo que o menor. Isso é chamado de “verificação de sanidade”porquedescobreresultados“insanos”.Outrotipodeverificaçãocomparaosresultadosdedoiscálculosdiferentespara ver se são consistentes. Isso é chamado de “verificação deconsistência”.

FormateasaídaA formatação da saída para depuração pode facilitar a busca de erros.Vimos um exemplo em “Depuração”, na página 172. O módulo pprintapresenta uma função pprint que exibe tipos integrados em um formatomais legívelparahumanos (pprint é a abreviaçãode “prettyprint” (belaexibição)).

Reforçando, o tempo que você passar construindo o scaffolding (o andaime)

Page 167: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

podereduzirotempodedepuração.

11.9-Glossário

mapeamentoRelaçãonaqualcadaelementodeumconjuntocorrespondeaumelementodeoutroconjunto.

dicionárioMapeamentodechavesaosseusvalorescorrespondentes.

parchave-valorRepresentaçãodomapeamentodeumachaveaumvalor.

itemEmumdicionário,outronomeparaumparchave-valor.

chaveObjeto que aparece em um dicionário como a primeira parte de um parchave-valor.

valorObjeto que aparece em um dicionário como a segunda parte de um parchave-valor. Isso é mais específico que o nosso uso anterior da palavra“valor”.

implementaçãoUmaformadeexecutarumcálculo.

hashtableAlgoritmousadoparaimplementardicionáriosdePython.

funçãohashFunçãousadaporumahashtableparacalcularaposiçãodeumachave.

hashableUmtipoquetemumafunçãohash.Tiposimutáveiscomonúmerosinteiros,de ponto flutuante e strings são hashable; tipos mutáveis, como listas edicionários,nãosão.

buscaOperação de dicionário que recebe uma chave e encontra o valorcorrespondente.

buscareversaOperação de dicionário que recebe um valor e encontra uma ou váriaschavesqueomapeiem.

instruçãoraiseInstruçãoque(deliberadamente)causaumaexceção.

Page 168: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

itemavulso(singleton)Umalista(ououtrasequência)comumúnicoelemento.

gráficodechamadaUm diagrama que mostra cada frame criado durante a execução de umprograma,comumaflechaapontandoquemchamaaqueméchamado.

memoValor já calculado, guardado para não ter que fazer omesmo cálculo nofuturo.

variávelglobalVariável definida fora de uma função. As variáveis globais podem seracessadasdequalquerfunção.

instruçãoglobalInstruçãoquedeclaraumnomedevariávelglobal.

flagVariávelbooleanausadaparaindicarseumacondiçãoéverdadeira.

declaraçãoInstruçãotalcomoglobal,quedizaointerpretadoralgoarespeitodeumavariável.

11.10-Exercícios

Exercício11.1

Escrevaumafunçãoqueleiaaspalavrasemwords.txteguarde-ascomochavesem um dicionário.Não importa quais são os valores. Então você pode usar ooperadorincomoumaformarápidadeverificarseumastringestánodicionário.

SefezoExercício10.10,vocêpodecompararavelocidadedestaimplementaçãocomooperadorindelistaseabuscaporbisseção.

Exercício11.2

Leiaadocumentaçãodométododedicionário setdefaulteuse-oparaescreverumaversãomaisconcisadeinvert_dict.

Solução:http://thinkpython2.com/code/invert_dict.py.

Exercício11.3

Page 169: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Memorize a função deAckermann do Exercício 6.2 e veja se amemorizaçãopermiteavaliarafunçãocomargumentosmaiores.Dica:não.

Solução:http://thinkpython2.com/code/ackermann_memo.py.

Exercício11.4

SefezoExercício10.7,você já temumafunçãochamadahas_duplicates,querecebe uma lista como parâmetro e retorna True se houver algum objeto queaparecemaisdeumaveznalista.

Use um dicionário para escrever uma versão mais rápida e simples dehas_duplicates.

Solução:http://thinkpython2.com/code/has_duplicates.py.

Exercício11.5

Duas palavras são “pares rotacionados” se for possível rotacionar um deles echegaraooutro(verrotate_wordnoExercício8.5).

Escrevaumprogramaque leiauma listadepalavraseencontre todososparesrotacionados.

Solução:http://thinkpython2.com/code/rotate_pairs.py.

Exercício11.6

Aqui está outro quebra-cabeça do programa Car Talk(http://www.cartalk.com/content/puzzlers):

ElefoienviadoporDanO’Leary.Dandescobriuumapalavracomum,comumasílaba e cinco letras que tem a seguinte propriedade única.Ao removermos aprimeiraletra,asletrasrestantesformamumhomófonodapalavraoriginal,queéumapalavraquesoaexatamentedamesmaforma.Substituaaprimeiraletra,isto é, coloque-a de volta, retire a segunda letra e o resultado é um outrohomófonodapalavraoriginal.Eaperguntaé,qualéapalavra?

Agora vou dar um exemplo que não funciona.Vamos usar a palavra de cinco

Page 170: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

letras, ‘wrack’(mover,eliminar).W-R-A-C-K,comonaexpressão‘wrackwithpain’(secontorcerdedor).Seeuretiraraprimeiraletra,sobraumapalavradequatroletras,‘R-A-C-K’(galhada).Comonafrase,‘Holycow,didyouseetherackonthatbuck!Itmusthavebeenanine-pointer!’(‘Minhanossa,vocêviuagalhada daquele cervo!Deve ter nove pontas!’). É um homófono perfeito. Sepusero‘w’devoltaeretiraro‘r’emvezdisso,sobraapalavra‘wack’,queéumapalavradeverdade,masnãoéumhomófonodasoutrasduaspalavras.

Mas há pelomenos uma palavra queDan e eu conhecemos, que produz doishomófonossevocêretirarqualquerumadasduasprimeirasletras,eduasnovaspalavrasdequatroletrassãoformadas.Aperguntaé,qualéapalavra?

VocêpodeusarodicionáriodoExercício11.1paraverificarseumastringestánalistadepalavras.

Paraverificarseduaspalavrassãohomófonas,vocêpodeusaroDicionáriodepronúncia CMU. Ele pode ser baixado em http://www.speech.cs.cmu.edu/cgi-bin/cmudict ou em http://thinkpython2.com/code/c06d. Você também podebaixar http://thinkpy thon2.com/code/pronounce.py, que tem uma funçãochamada read_dictionary, que lê o dicionário de pronúncia e retorna umdicionário de Python quemapeia cada palavra a uma string que descreve suapronúnciaprimária.

Escrevaumprogramaquelistetodasaspalavrasqueresolvemoquebra-cabeça.

Solução:http://thinkpython2.com/code/homophone.py.

Page 171: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo12:TuplasEste capítulo apresenta mais um tipo integrado, a tupla, e descreve como aslistas, os dicionários e as tuplas trabalham juntos. Além disso, apresento umrecurso útil para listas de argumentos de comprimento variável: os operadoresgatherescatter.

Umaobservação:nãoháconsensosobrecomopronunciar“tuple” (em inglês).Algumaspessoasdizem“tuhple”,querimacom“supple”.Porém,nocontextodaprogramação,amaioriadaspessoasdiz“too-ple”,querimacom“quadruple”.

12.1-Tuplassãoimutáveis

Umatuplaéumasequênciadevalores.Osvalorespodemserdequalquertipo,epodemserindexadospornúmerosinteiros,portanto,nessesentido,astuplassãomuito parecidas com as listas. A diferença importante é que as tuplas sãoimutáveis.

Sintaticamente,umatuplaéumalistadevaloresseparadosporvírgulas:

>>>t='a','b','c','d','e'

Emboranãosejasemprenecessário,écomumcolocartuplasentreparênteses:

>>>t=('a','b','c','d','e')

Paracriarumatuplacomumúnicoelemento,éprecisoincluirumavírgulafinal:

>>>t1='a',

>>>type(t1)

<class'tuple'>

Umúnicovalorentreparêntesesnãoéumatupla:

>>>t2=('a')

>>>type(t2)

<class'str'>

Page 172: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Outra forma de criar uma tupla é com a função integrada tuple. Semargumentos,criaumatuplavazia:

>>>t=tuple()

>>>t

()

Seosargumentosforemumasequência(string,listaoutupla),oresultadoéumatuplacomoselementosdasequência:

>>>t=tuple('lupins')

>>>t

('l','u','p','i','n','s')

Comotupleéonomedeumafunçãointegrada,vocêdeveevitarusá-locomonomedevariável.

Amaiorpartedosoperadoresdelistatambémfuncionaemtuplas.Ooperadordecolchetesindexaumelemento:

>>>t=('a','b','c','d','e')

>>>t[0]

'a'

Eooperadordefatiaselecionavárioselementos:

>>>t[1:3]

('b','c')

Entretanto,setentaralterarumdoselementosdatupla,vaireceberumerro:

>>>t[0]='A'

TypeError:objectdoesn'tsupportitemassignment

Como tuplas são imutáveis, você não pode alterar os elementos, mas podesubstituirumatuplaporoutra:

>>>t=('A',)+t[1:]

>>>t

('A','b','c','d','e')

Essainstruçãofazumanovatuplaeentãoaatribuiat.

Page 173: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Osoperadoresrelacionaisfuncionamcomtuplaseoutrassequências;oPythoncomeça comparando o primeiro elemento de cada sequência. Se forem iguais,vaiparaospróximoselementos,eassimpordiante,atéqueencontreelementosquesejamdiferentes.Oselementossubsequentesnãosãoconsiderados(mesmoseforemmuitograndes).

>>>(0,1,2)<(0,3,4)

True

>>>(0,1,2000000)<(0,3,4)

True

12.2-Atribuiçãodetuplas

Muitas vezes, é útil trocar os valores de duas variáveis. Com a atribuiçãoconvencional,éprecisousarumavariáveltemporária.Porexemplo,trocaraeb.

>>>temp=a

>>>a=b

>>>b=temp

Essasoluçãoétrabalhosa;aatribuiçãodetuplasémaiselegante:

>>>a,b=b,a

O lado esquerdo é uma tupla de variáveis; o lado direito é uma tupla deexpressões.Cadavaloréatribuídoàsuarespectivavariável.Todasasexpressõesnoladodireitosãoavaliadasantesdetodasasatribuições.

Onúmerodevariáveisàesquerdaeonúmerodevaloresàdireitaprecisamseriguais:

>>>a,b=1,2,3

ValueError:toomanyvaluestounpack

Deformageral,oladodireitopodeterqualquertipodesequência(string, listaou tupla). Por exemplo, para dividir um endereço de email em um nome deusuárioeumdomínio,vocêpoderiaescrever:

>>>addr='[email protected]'

>>>uname,domain=addr.split('@')

O valor de retorno do split é uma lista com dois elementos; o primeiro

Page 174: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

elementoéatribuídoauname,osegundoadomain:

>>>uname

'monty'

>>>domain

'python.org'

12.3-Tuplascomovaloresderetorno

Falandoestritamente,umafunçãosópoderetornarumvalor,masseovalorforumatupla,oefeitoéomesmoqueretornarvaloresmúltiplos.Porexemplo,sevocêquiser dividir dois números inteiros e calcular oquociente e resto, não éeficientecalcularx/yedepoisx%y.Émelhorcalcularambosaomesmotempo.

Afunçãointegradadivmodtomadoisargumentosedevolveumatupladedoisvalores:oquocienteeoresto.Vocêpodeguardaroresultadocomoumatupla:

>>>t=divmod(7,3)

>>>t

(2,1)

Ouusaraatribuiçãodetuplasparaguardaroselementosseparadamente:

>>>quot,rem=divmod(7,3)

>>>quot

2

>>>rem

1

Aquiestáumexemplodefunçãoqueretornaumatupla:

defmin_max(t):

returnmin(t),max(t)

maxeminsãofunçõesintegradasqueencontramosmaioresemenoreselementosdeumasequência.min_maxcalculaamboseretornaumatupladedoisvalores.

12.4-Tuplascomargumentosdecomprimentovariável

As funções podem receber um número variável de argumentos. Um nome de

Page 175: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

parâmetro que comece com * reúne vários argumentos em uma tupla. Porexemplo,printallrecebequalquernúmerodeargumentoseosexibe:

defprintall(*args):

print(args)

Oparâmetrocomoprefixo*podeterqualquernomequevocêgoste,masargséoconvencional.Éassimqueafunçãofunciona:

>>>printall(1,2.0,'3')

(1,2.0,'3')

Ocomplementodereuniréespalhar.Sevocêtiverumasequênciadevaloresequiserpassá-laaumafunçãocomoargumentosmúltiplos,podeusarooperador*.Porexemplo,odivmodrecebeexatamentedoisargumentos;elenãofuncionacomumatupla:

>>>t=(7,3)

>>>divmod(t)

TypeError:divmodexpected2arguments,got1

Noentanto,sevocêespalharatupla,aífunciona:

>>>divmod(*t)

(2,1)

Muitas das funções integradas usam tuplas com argumentos de comprimentovariável. Por exemplo, max e min podem receber qualquer número deargumentos:

>>>max(1,2,3)

3

Massum,não:

>>>sum(1,2,3)

TypeError:sumexpectedatmost2arguments,got3

Como exercício, escreva uma função chamada sumall que receba qualquernúmerodeargumentoseretorneasomadeles.

12.5-Listasetuplas

Page 176: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

zipéumafunçãointegradaquerecebeduasoumaissequênciasedevolveumalistadetuplasondecadatuplacontémumelementodecadasequência.Onomedafunçãotemavercomozíper,quesejuntaeencaixaduascarreirasdedentes.

Esteexemploencaixaumastringeumalista:

>>>s='abc'

>>>t=[0,1,2]

>>>zip(s,t)

<zipobjectat0x7f7d0a9e7c48>

O resultado é um objeto zip que sabe como percorrer os pares. O uso maiscomumdezipéemumloopfor:

>>>forpairinzip(s,t):

...print(pair)

...

('a',0)

('b',1)

('c',2)

Umobjetozipéumtipode iterador,ouseja,qualquerobjetoquepercorreouitera sobre uma sequência. Iteradores são semelhantes a listas em algunsaspectos, mas, ao contrário de listas, não é possível usar um índice paraselecionarumelementodeumiterador.

Sequiserusaroperadoresemétodosdelista,vocêpodeusarumobjetozipparafazerumalista:

>>>list(zip(s,t))

[('a',0),('b',1),('c',2)]

Oresultadoéumalistadetuplas;nesteexemplo,cadatuplacontémumcaracteredastringeoelementocorrespondentedalista.

Se as sequências não forem do mesmo comprimento, o resultado tem ocomprimentodamaiscurta:

>>>list(zip('Anne','Elk'))

[('A','E'),('n','l'),('n','k')]

Vocêpodeusaraatribuiçãodetuplasemumloopforparaatravessarumalistadetuplas:

Page 177: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

t=[('a',0),('b',1),('c',2)]

forletter,numberint:

print(number,letter)

Cadavezqueoprogramapassapeloloop,oPythonselecionaapróximatuplanalistaeatribuioselementosletterenumber.Asaídadesteloopé:

0a

1b

2c

Secombinarzip,foreatribuiçãodetuplas,vocêpodefazerumaexpressãoútilpara percorrer duas (ou mais) sequências ao mesmo tempo. Por exemplo,has_matchrecebeduassequências,t1et2eretornaTruesehouverumíndiceitalquet1[i]==t2[i]:

defhas_match(t1,t2):

forx,yinzip(t1,t2):

ifx==y:

returnTrue

returnFalse

Seprecisaratravessaroselementosdeumasequênciaeseusíndices,vocêpodeusarafunçãointegradaenumerate:

forindex,elementinenumerate('abc'):

print(index,element)

Oresultadodeenumerateéumobjetoenumerate,queiterasobreumasequênciade pares; cada par contém um índice (começando de 0) e um elemento dasequênciadada.Nesteexemplo,asaídaé

0a

1b

2c

Denovo.

12.6-Dicionáriosetuplas

Osdicionários têmummétodochamadoitemsquedevolveumasequênciade

Page 178: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

tuplas,ondecadatuplaéumparchave-valor:

>>>d={'a':0,'b':1,'c':2}

>>>t=d.items()

>>>t

dict_items([('c',2),('a',0),('b',1)])

Oresultadoéumobjetodict_items, que é um iterador quepercorre os pareschave-valor.Vocêpodeusá-loemumloopfor,destaforma:

>>>forkey,valueind.items():

...print(key,value)

...

c2

a0

b1

Como se poderia esperar de um dicionário, os itens não estão em nenhumaordememparticular.

Indo emoutra direção, você pode usar uma lista de tuplas para inicializar umnovodicionário:

>>>t=[('a',0),('c',2),('b',1)]

>>>d=dict(t)

>>>d

{'a':0,'c':2,'b':1}

Combinardictcomzipproduzumaformaconcisadecriarumdicionário:

>>>d=dict(zip('abc',range(3)))

>>>d

{'a':0,'c':2,'b':1}

Ométododedicionárioupdatetambémrecebeumalistadetuplaseasadiciona,comopareschave-valor,aumdicionárioexistente.

Écomumusartuplascomochavesemdicionários(principalmenteporquevocênãopodeusarlistas).Porexemplo,umalistatelefônicapoderiamapearparesdesobrenome e primeiro nome a números de telefone. Supondo que tenhamosdefinidolast,firstenumber,podemosescrever:

directory[last,first]=number

Page 179: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Aexpressãoentrechaveséuma tupla.Podemosusaratribuiçãode tuplasparaatravessarestedicionário:

forlast,firstindirectory:

print(first,last,directory[last,first])

Este loop atravessa as chaves em directory, que são tuplas. Ele atribui oselementosdecadatuplaparalastefirst,eentãoexibeonomeenúmerodetelefonecorrespondente.

Háduasformasderepresentartuplasemumdiagramadeestado.Aversãomaisdetalhada mostra os índices e elementos como aparecem em uma lista. Porexemplo,atupla('Cleese','John')apareceriacomonaFigura12.1.

Figura12.1–Diagramadeestadodeumatupla.

No entanto, em umdiagramamaior, você pode querer omitir os detalhes. Porexemplo,umdiagramadalistatelefônicapoderiasercomoodaFigura12.2.

Figura12.2–Diagramadeestadodeumdicionáriocomchavesdotipotupla.

Aqui as tuplas são mostradas usando a sintaxe do Python para simplificar ográfico.Onúmerode telefonenodiagramaé a linhade reclamaçõesdaBBC,então,porfavor,nãoligueparalá.

Page 180: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

12.7-Sequênciasdesequências

Eu me concentrei em listas de tuplas, mas quase todos os exemplos nestecapítulo também funcionam com listas de listas, tuplas de tuplas e tuplas delistas.Paraevitarenumerarascombinaçõespossíveis,àsvezesémaisfácilfalarsobresequênciasdesequências.

Emmuitoscontextos,os tiposdiferentesdesequências(strings, listase tuplas)podemserusadosde forma intercambiável.Então,comoescolherumaemvezdaoutra?

Paracomeçarcomoóbvio,asstringssãomaislimitadasqueoutrassequênciasporqueoselementos têmdesercaracteres.Tambémsãoimutáveis.Seprecisardacapacidadedealterarcaracteresemumastring(emvezdecriaroutrastring)vocêpodequererusarumalistadecaracteres.

As listas sãomais comunsque as tuplas, principalmenteporque sãomutáveis.Masháalgunscasosemquevocêpodepreferirtuplas:

1. Em alguns contextos, como em uma instrução return, é sintaticamentemaissimplescriarumatuplaqueumalista.

2. Sequiserusarumasequênciacomoumachavededicionário,éprecisousarumtipoimutávelcomoumatuplaoustring.

3. Seestiverpassandoumasequênciacomoumargumentoaumafunção,usartuplasreduzopotencialdecomportamentoinesperadodevidoaalias.

Comotuplassão imutáveis,elasnãofornecemmétodoscomosortereverse,que alteram listas existentes. Porém, o Python fornece a função integradasorted,querecebequalquersequênciaeretornaumanovalistacomosmesmoselementos ordenados, e reversed, que recebe uma sequência e retorna umiteradorquepercorrealistaemordemreversa.

12.8-Depuração

Aslistas,osdicionárioseas tuplassãoexemplosdeestruturasdedados;nestecapítuloestamoscomeçandoaverestruturasdedadoscompostas,comoaslistasde tuplasoudicionáriosquecontêmtuplascomochavese listascomovalores.

Page 181: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Asestruturasdedadoscompostassãoúteis,massãopropensasaoquechamodeerrosdeforma;istoé,erroscausadosquandoumaestruturadedadostemotipo,tamanho ou estrutura incorretos. Por exemplo, se você estiver esperando umalista com um número inteiro e eu der apenas o número inteiro (não em umalista),nãovaifuncionar.

Para ajudar a depurar esses tipos de erro, escrevi um módulo chamadostructshape, que fornece uma função, também chamada structshape, querecebequalquertipodeestruturadedadoscomoargumentoeretornaumastring,que resume sua forma. Você pode baixá-la emhttp://thinkpython2.com/code/structshape.py.

Aquiestáoresultadodeumalistasimples:

>>>fromstructshapeimportstructshape

>>>t=[1,2,3]

>>>structshape(t)

'listof3int'

Umprogramamais sofisticadopodeescrever “list of3 ints”,mas émais fácilnãolidarcomplurais.Aquiestáumalistadelistas:

>>>t2=[[1,2],[3,4],[5,6]]

>>>structshape(t2)

'listof3listof2int'

Seoselementosdalistanãoforemdomesmotipo,structshapeosagrupa,naordem,portipo:

>>>t3=[1,2,3,4.0,'5','6',[7],[8],9]

>>>structshape(t3)

'listof(3int,float,2str,2listofint,int)'

Aquiestáumalistadetuplas:

>>>s='abc'

>>>lt=list(zip(t,s))

>>>structshape(lt)

'listof3tupleof(int,str)'

Eaquiestáumdicionáriocomtrêsitensquemapeianúmerosinteirosastrings:

>>>d=dict(lt)

Page 182: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>structshape(d)

'dictof3int->str'

Se estiver com problemas para monitorar suas estruturas de dados, ostructshapepodeajudar.

12.9-Glossário

tuplaSequênciaimutáveldeelementos.

atribuiçãodetuplaAtribuiçãocomumasequênciano ladodireitoeuma tupladevariáveisàesquerda.Oladodireitoéavaliadoeentãoseuselementossãoatribuídosàsvariáveisàesquerda.

gatherOperaçãoparamontarumatuplacomargumentodecomprimentovariável.

scatterOperaçãoparatratarumasequênciacomoumalistadeargumentos.

objetozipOresultadodechamarumafunçãointegradazip;umobjetoqueserepeteporumasequênciadetuplas.

iteradorObjeto que pode se repetir por uma sequência, mas que não ofereceoperadoresdelistaemétodos.

estruturadedadosColeção de valores relacionados, muitas vezes organizados em listas,dicionários,tuplasetc.

errodeformaErro causado pelo fato de o valor ter a forma incorreta; isto é, tipo outamanhoincorreto.

12.10-Exercícios

Exercício12.1

Escrevaumafunçãochamadamost_frequentquerecebaumastringeexibaasletrasemordemdecrescentedefrequência.Encontreamostrasdetextodeváriosidiomas diferentes e veja como a frequência das letras varia entre os idiomas.

Page 183: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Compare seus resultados com as tabelas emhttp://en.wikipedia.org/wiki/Letter_frequencies.

Solução:http://thinkpython2.com/code/most_frequent.py.

Exercício12.2

Maisanagramas!

1. Escrevaumprogramaque leiauma listadepalavrasdeumarquivo (veja“Leitura de listas de palavras”, na página 133) e imprima todos osconjuntosdepalavrasquesãoanagramas.

Aquiestáumexemplodecomoasaídapodeparecer:

['deltas','desalt','lasted','salted','slated','staled']

['retainers','ternaries']

['generating','greatening']

['resmelts','smelters','termless']

Dica:vocêpodequererconstruirumdicionárioquemapeieumacoleçãodeletras a uma lista de palavras que podem ser soletradas com essas letras. Aperguntaé:comorepresentaracoleçãode letrasdeformaquepossaserusadacomoumachave?

2. Altereoprogramaanteriorparaqueexibaalistamaislongadeanagramasprimeiro,seguidopelasegundamaislonga,eassimpordiante.

3. NoScrabble, um “bingo” é quando você joga todas as sete peças na suaestante,juntocomumapeçanotabuleiro,paraformarumapalavradeoitoletras.Quecoleçãodeoitoletrasformaomaiornúmeropossíveldebingos?Dica:hásete.

Solução:http://thinkpython2.com/code/anagram_sets.py.

Exercício12.3

Duaspalavrasformamum“pardemetátese”sevocêpudertransformarumanaoutra trocandoduas letras,por exemplo, “converse”e “conserve”.Escrevaumprogramaquedescubratodososparesdemetátesenodicionário.Dica:nãoteste

Page 184: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

todososparesdepalavrasenãotestetodasastrocaspossíveis.

Solução:http://thinkpython2.com/code/metathesis.py.Crédito:esteexercíciofoiinspiradoporumexemploemhttp://puzzlers.org.

Exercício12.4

Aqui está outro quebra-cabeça do programa Car Talk(http://www.cartalk.com/content/puzzlers):

Qualéapalavrainglesamaislonga,quepermaneceumapalavrainglesaválida,conformevairemovendosuasletras,umaapósaoutra?

Agora, as letras podem ser retiradas do fim ou do meio, mas você não podereajustarnenhumadelas.Cadavezqueremoveumaletra,vocêacabacomoutrapalavrainglesa.Sefizeristo,eventualmentevocêacabarácomumaletraeissotambém será uma palavra inglesa; uma encontrada no dicionário.Quero saberqualéapalavramaislongaequantasletrastem?

Voudarumpequenoexemplomodesto:Sprite.Ok?Vocêcomeçacomsprite,tirauma letrado interiordapalavra, tirao r, e ficamoscomapalavra spite, entãotiramosoedofim,ficamoscomspit,tiramosos,ficamoscompit,iteI.

Escrevaumprogramaqueencontre todasaspalavrasquepodemser reduzidasdestaforma,eentãoencontreamaislonga.

Este exercício é um pouco mais desafiador que a maioria, então aqui estãoalgumassugestões:

1. Você pode querer escrever uma função que receba uma palavra e calculeumalistadetodasaspalavrasquepodemserformadasretirandoumaletra.Essessãoos“filhos”dapalavra.

2. Recursivamente, uma palavra é redutível se algum de seus filhos forredutível.Comocasobase,vocêpodeconsiderarastringvaziaredutível.

3. Alistadepalavrasqueforneci,words.txt,nãocontémpalavrasdeumaletrasó.Portanto,vocêpodequereracrescentar“I”,“a”,eastringvazia.

4. Para melhorar o desempenho do seu programa, você pode querer

Page 185: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

memorizaraspalavrasconhecidasporseremredutíveis.

Solução:http://thinkpython2.com/code/reducible.py.

Page 186: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo13:Estudodecaso:seleçãodeestruturadedadosNestepontovocêjáaprendeusobreasprincipaisestruturasdedadosdoPython,e viu alguns algoritmos que as usam. Se quiser saber mais sobre algoritmos,pode leroCapítulo21.Mas issonãoénecessárioparacontinuar,pode lê-loaqualquermomentoemquetenhainteresse.

Este capítulo apresenta um estudo de caso com exercícios que fazem pensarsobreaescolhadeestruturasdedadosepráticasdeusodelas.

13.1-Análisedefrequênciadepalavras

Comodehábito,vocêdevepelomenostentarfazerosexercíciosantesdelerasminhassoluções.

Exercício13.1

Escreva um programa que leia um arquivo, quebre cada linha em palavras,removaosespaçosembrancoeapontuaçãodaspalavras,easconvertaemletrasminúsculas.

Dica:Omódulostring ofereceuma string chamadawhitespace, que contémespaço, tab, newline etc., e punctuation, que contém os caracteres depontuação.VamosverseconseguimosfazeroPythonfalarpalavrões:

>>>importstring

>>>string.punctuation

'!"#$%&\'()*+,-./:;<=>?@[\]^_`{|}~'

Alémdisso,vocêpodeusarosmétodosdestring,strip,replaceetranslate.

Exercício13.2

AcesseoProjetoGutenberg(http://gutenberg.org)ebaixeseulivrofavoritoem

Page 187: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

domíniopúblicoemformatodetextosimples.

Altere seu programa do exercício anterior para ler o livro que você baixou,pulandoasinformaçõesdocabeçalhonoiníciodoarquivoeprocessandoorestodaspalavrascomoantes.

Então altere o programa para contar o número total de palavras no livro e onúmerodevezesquecadapalavraéusada.

Exiba o número de palavras diferentes usadas no livro. Compare livrosdiferentes de autores diferentes, escritos em eras diferentes. Que autor usa ovocabuláriomaisextenso?

Exercício13.3

Altere o programa do exercício anterior para exibir as 20 palavras maisfrequentesdolivro.

Exercício13.4

Altereoprogramaanteriorparalerumalistadepalavras(ver“Leituradelistasdepalavras”, napágina133) e então exiba todas as palavras do livroquenãoestãona listadepalavras.Quantasdelas sãoerrosortográficos?Quantasdelassãopalavrascomunsquedeveriamestarnalistadepalavras,equantassãomuitoobscuras?

13.2-Númerosaleatórios

Comasmesmasentradas,amaiorpartedosprogramasgeraasmesmassaídasacadavez,entãoelessãochamadosdedeterministas.Determinismonormalmenteé uma coisa boa, já que esperamos que o mesmo cálculo produza o mesmoresultado.Paraalgumasaplicações,entretanto,queremosqueocomputadorsejaimprevisível.Osjogossãoumexemploóbvio,masháoutros.

Fazerumprogramanãodeterministadeverdadeédifícil;masháformasde,pelomenos, fazê-los parecer que não são.Uma delas é usar algoritmos que geramnúmeros pseudoaleatórios. Os números pseudoaleatórios não são aleatóriosmesmoporquesãogeradosporumcálculodeterminista,maséquaseimpossível

Page 188: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

distingui-losdosaleatóriossóolhandoparaosnúmeros.

Omódulo random fornece funções que geram números pseudoaleatórios (quechamareiapenasde“aleatórios”daquiemdiante).

A função random retorna um número de ponto flutuante entre 0,0 e 1,0(incluindo0,0,masnão1,0).Cadavezque randomé chamada,você recebeopróximonúmeroemumalongasérie.Paraverumaamostra,executeesteloop:

importrandom

foriinrange(10):

x=random.random()

print(x)

Afunçãorandintrecebeosparâmetroslowehigheretornaumnúmerointeiroentrelowehigh(inclusiveambos):

>>>random.randint(5,10)

5

>>>random.randint(5,10)

9

Para escolher aleatoriamente um elemento de uma sequência, você pode usarchoice:

>>>t=[1,2,3]

>>>random.choice(t)

2

>>>random.choice(t)

3

O módulo random também fornece funções para gerar valores aleatórios dedistribuições contínuas, incluindo gaussianas, exponenciais, gamma e algumasoutras.

Exercício13.5

Escreva uma função chamada choose_from_hist que receba um histogramacomodefinidoem“Umdicionáriocomoumacoleçãodecontadores”,napágina163,eretorneumvaloraleatóriodohistograma,escolhidoporprobabilidadeemproporçãoàfrequência.Porexemplo,paraestehistograma:

Page 189: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>t=['a','a','b']

>>>hist=histogram(t)

>>>hist

{'a':2,'b':1}

suafunçãodeveretornar'a'comaprobabilidadede2/3e'b'comaprobabilidade1/3.

13.3-Histogramadepalavras

Éuma boa ideia tentar fazer os exercícios anteriores antes de continuar.Vocêpodebaixarminhasoluçãoemhttp://thinkpython2.com/code/analyze_book1.py.Tambémvaiprecisardehttp://thinkpython2.com/code/emma.txt.

Aquiestáumprogramaquelêumarquivoeconstróiumhistogramadaspalavrasnoarquivo:

importstring

defprocess_file(filename):

hist=dict()

fp=open(filename)

forlineinfp:

process_line(line,hist)

returnhist

defprocess_line(line,hist):

line=line.replace('-','')

forwordinline.split():

word=word.strip(string.punctuation+string.whitespace)

word=word.lower()

hist[word]=hist.get(word,0)+1

hist=process_file('emma.txt')

Esteprogramalêemma.txt,quecontémotextodeEmma,deJaneAusten.

process_file fazolooppelaslinhasdoarquivo,passando-asumaaumaparaprocess_line.Ohistogramahistestásendousadocomoumacumulador.

process_lineusaométododestringreplaceparasubstituirhifensporespaçosantesdeusarsplitparaquebraralinhaemumalistadestrings.Eleatravessaalistadepalavraseusastripelowerpararetirarapontuaçãoeconvertertudoem

Page 190: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

letrasminúsculas.(Dizerqueasstrings“sãoconvertidas”éumaformasimplesde explicar a coisa; lembre-se de que as strings são imutáveis, entãométodoscomostripelowerretornamnovasstrings.)

Finalmente, process_line atualiza o histograma, criando um novo item ouincrementandoumexistente.

Para contar o número total de palavras no arquivo, podemos somar asfrequênciasnohistograma:

deftotal_words(hist):

returnsum(hist.values())

Onúmerodepalavrasdiferentesésomenteonúmerodeitensnodicionário:

defdifferent_words(hist):

returnlen(hist)

Aquiestáocódigoparaexibirosresultados:

print('Totalnumberofwords:',total_words(hist))

print('Numberofdifferentwords:',different_words(hist))

Eosresultados:

Totalnumberofwords:161080

Numberofdifferentwords:7214

13.4-Palavrasmaiscomuns

Paraencontraraspalavrasmaiscomuns,podemosfazerumalistadetuplas,ondecadatuplacontenhaumapalavraeasuafrequência,eordenaralista.

A função seguinte recebe um histograma e retorna uma lista de tuplas depalavrasefrequências:

defmost_common(hist):

t=[]

forkey,valueinhist.items():

t.append((value,key))

t.sort(reverse=True)

returnt

Page 191: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Emcadatupla,afrequênciaapareceprimeiro,entãoalistaresultanteéordenadaporfrequência.Aquiestáumloopqueimprimeas10palavrasmaiscomuns:

t=most_common(hist)

print('Themostcommonwordsare:')

forfreq,wordint[:10]:

print(word,freq,sep='\\t')

Uso o argumento de palavra-chave sep para que print use um caractere tabcomo separador, em vez de um espaço, assim a segunda coluna fica alinhadaverticalmente.AquiestãoosresultadosdeEmma:

Themostcommonwordsare:

to5242

the5205

and4897

of4295

i3191

a3130

it2529

her2483

was2400

she2364

Estecódigopodeser simplificadousandooparâmetrokeyda funçãosort.Setiver curiosidade, pode ler sobre ele emhttps://wiki.python.org/moin/HowTo/Sorting.

13.5-Parâmetrosopcionais

Vimos funções integradas e métodos que recebem argumentos opcionais. Épossível escrever funções definidas pelos programadores com argumentosopcionais, também. Por exemplo, aqui está uma função que exibe as palavrasmaiscomunsemumhistograma:

defprint_most_common(hist,num=10):

t=most_common(hist)

print('Themostcommonwordsare:')

forfreq,wordint[:num]:

print(word,freq,sep='\\t')

Oprimeiroparâmetroénecessário;osegundoéopcional.Ovalorpadrãodenum

Page 192: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

é10.

Sevocêsófornecerumargumento:

print_most_common(hist)

numrecebeovalorpadrão.Sefornecerdoisargumentos:

print_most_common(hist,20)

num recebe o valor do argumento em vez disso. Em outras palavras, oargumentoopcionalignoraovalorpadrão.

Se uma função tem ambos os parâmetros obrigatório e opcional, todos osparâmetrosnecessáriostêmquevirprimeiro,seguidospelosopcionais.

13.6-Subtraçãodedicionário

Encontraraspalavrasdolivroquenãoestãonalistadepalavrasdewords.txtéum problema que você pode reconhecer como subtração de conjuntos; isto é,queremosencontrartodasaspalavrasdeumconjunto(aspalavrasnolivro)quenãoestãonooutro(aspalavrasnalista).

subtract recebe os dicionários d1 e d2 e devolve um novo dicionário quecontémtodasaschavesded1quenãoestãoemd2.Comonãonospreocupamoscomosvalores,estabelecemostodoscomoNone:

defsubtract(d1,d2):

res=dict()

forkeyind1:

ifkeynotind2:

res[key]=None

returnres

Para encontrar aspalavrasno livroquenão estão emwords.txt, podemosusarprocess_fileparaconstruirumhistogramaparawords.txt,eentãosubtrair:

words=process_file('words.txt')

diff=subtract(hist,words)

print("Wordsinthebookthataren'tinthewordlist:")

forwordindiff:

print(word,end='')

Page 193: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

AquiestãoalgunsresultadosdeEmma:

Wordsinthebookthataren'tinthewordlist:

rencontrejane'sblanchewoodhousesdisingenuousness

friend'sveniceapartment...

Algumasdessaspalavrassãonomesepossessivos.Osoutros,como“rencontre”,já não são de uso comum.Mas algumas são palavras comuns que realmentedeveriamestarnalista!

Exercício13.6

O Python fornece uma estrutura de dados chamada set, que fornece muitasoperaçõesdeconjunto.Vocêpodelersobreelasem“Conjuntos”,napágina274,ou ler adocumentaçãoemhttp://docs.python.org/3/library/stdtypes.html#types-set.

Escrevaumprogramaqueuseasubtraçãodeconjuntosparaencontrarpalavrasnolivroquenãoestãonalistadepalavras.

Solução:http://thinkpython2.com/code/analyze_book2.py.

13.7-Palavrasaleatórias

Paraescolherumapalavraaleatóriadohistograma,oalgoritmomaissimpleséconstruir uma lista com várias cópias de cada palavra, segundo a frequênciaobservada,eentãoescolherdalista:

defrandom_word(h):

t=[]

forword,freqinh.items():

t.extend([word]*freq)

returnrandom.choice(t)

Aexpressão[word]*freqcriauma listacomfreq cópiasda stringword.Ométodoextendésimilaraappend,excetopeloargumento,queéumasequência.

Essealgoritmofunciona,masnãoémuitoeficiente;cadavezquevocêescolheuma palavra aleatória, ele reconstrói a lista, que é tão grande quanto o livrooriginal.Umamelhoriaóbviaéconstruiralistaumavezeentãofazerseleções

Page 194: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

múltiplas,masalistaaindaégrande.

Umaalternativaé:

1. Usarkeysparaconseguirumalistadaspalavrasnolivro.

2. Construir uma lista que contenha a soma cumulativa das frequências daspalavras(vejaoExercício10.2).Oúltimoitemdestalistaéonúmerototaldepalavrasnolivro,n.

3. Escolherumnúmeroaleatóriode1an.Useumapesquisadebisseção(vejaoExercício 10.10) para encontrar o índice onde o número aleatório seriainseridonasomacumulativa.

4. Usaroíndiceparaencontrarapalavracorrespondentenalistadepalavras.

Exercício13.7

Escrevaumprogramaqueuseestealgoritmoparaescolherumapalavraaleatóriadolivro.

Solução:http://thinkpython2.com/code/analyze_book3.py.

13.8-AnálisedeMarkov

Seescolherpalavrasdolivroaleatoriamente,vocêpodeatécaptarcertosentidoapartir do vocabulário, mas provavelmente não vai conseguir uma sentençacompleta:

thisthesmallregardharrietwhichknightley'sitmostthings

Umasériedepalavrasaleatóriasraramentefazsentidoporquenãohánenhumarelação entre palavras sucessivas. Por exemplo, em uma sentença de verdadevocê esperaria que um artigo como “o” fosse seguido de um adjetivo ou umsubstantivo,eprovavelmentenãoumverboouadvérbio.

Uma forma de medir estes tipos de relações é a análise de Markov, quecaracteriza, para uma dada sequência de palavras, o que poderia vir a seguir,segundoaprobabilidade.Porexemplo,acanção“Eric,theHalfaBee”começa

Page 195: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

assim:

Halfabee,philosophically,

Must,ipsofacto,halfnotbe.

Buthalfthebeehasgottobe

Visavis,itsentity.D’yousee?

Butcanabeebesaidtobe

Ornottobeanentirebee

Whenhalfthebeeisnotabee

Duetosomeancientinjury?

Nessetexto,afrase“halfthe”sempreéseguidapelapalavra“bee”,masafrase“thebee”podeserseguidapor“has”ou“is”.

O resultado da análise deMarkov é um mapeamento de cada prefixo (como“halfthe”e“thebee”)atodosossufixospossíveis(como“has”e“is”).

Com este mapeamento você pode gerar um texto aleatório, começando comqualquer prefixo e escolhendo a esmo entre os sufixos possíveis.Em seguida,você pode combinar o fimdoprefixo e o novo sufixo para formar o próximoprefixoerepetir.

Porexemplo,sevocêcomeçarcomoprefixo“Halfa”,entãoapróximapalavratem que ser “bee”, porque o prefixo só aparece uma vez no texto. O prefixoseguinteé“abee”,entãoopróximosufixopoderiaser“philosophically”,“be”ou“due”.

Nesteexemplo,ocomprimentodoprefixoésempredois,masvocêpodefazeraanálisedeMarkovcomqualquercomprimentodeprefixo.

Exercício13.8

AnálisedeMarkov:

a)EscrevaumprogramaqueleiaotextodeumarquivoeexecuteaanálisedeMarkov.Oresultadodeveserumdicionárioquemapeieprefixosaumacoleçãodepossíveissufixos.Acoleçãopodeseruma lista, tuplaoudicionário;vocêéque deverá fazer a escolha adequada.Você pode testar seu programa comumcomprimentodeprefixo2,masdeveescreveroprogramadeformaquesejafáciltestaroutroscomprimentos.

Page 196: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

b) Acrescente uma função ao programa anterior para gerar texto aleatóriobaseadonaanálisedeMarkov.AquiestáumexemplodeexemplodeEmmacomocomprimentodeprefixo2.

Hewasveryclever,beitsweetnessorbeangry,ashamedoronlyamused,at such a stroke. She had never thought of Hannah till you were nevermeant for me?” “I cannot make speeches, Emma:” he soon cut it allhimself.

Paraesteexemplo,deixeiapontuaçãoanexadaàspalavras.Oresultadoéquasesintaticamentecorreto,masnãoexatamente.Semanticamente,quasefazsentido,masnãoexatamente.

Oqueacontecesevocêaumentarocomprimentodosprefixos?Otextoaleatóriofazmaissentido?

c)Umavezqueoseuprogramaestejafuncionando,vocêpodequerertentarumamistura: se combinar o texto de dois oumais livros, o texto aleatório geradomisturaráovocabulárioefrasesdasfontesdeformasinteressantes.

Crédito:esteestudodecasoébaseadoemumexemplodeKernighanandPike,ThePracticeofProgramming,Addison-Wesley,1999.

Éumaboaideiatentarfazeresteexercícioantesdecontinuar;depoisvocêpodebaixar a minha solução em http://thinkpython2.com/code/markov.py. Tambémvaiprecisardehttp://thinkpython2.com/code/emma.txt.

13.9-Estruturasdedados

UsaranálisedeMarkovparagerarotextoaleatórioédivertido,mastambémháumarazãoparaesteexercício:aseleçãodaestruturadedados.Nasuasoluçãoparaosexercíciosanteriores,vocêtevequeselecionar:

comorepresentarosprefixos;

comorepresentaracoleçãodesufixospossíveis;

como representar o mapeamento de cada prefixo à coleção de possíveissufixos.

Page 197: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

O último é fácil: um dicionário é a escolha óbvia para um mapeamento dechavesavalorescorrespondentes.

Paraosprefixos,asopçõesmaisóbviassãostrings,listasdestringsoutuplasdestrings.

Paraossufixos,umaopçãoéumalista;outraéumhistograma(dicionário).

Comovocêdeveescolher?Oprimeiropassoépensarnasoperaçõesquevocêvai precisar implementar para cada estrutura de dados. Para os prefixos, éprecisopoderretirarpalavrasdocomeçoeacrescentarnofim.Porexemplo,seoprefixoatualé“Halfa”eapróximapalavraé“bee”,vocêtemquepoderformaropróximoprefixo,“abee”.

Sua primeira escolha pode ser uma lista, pois é fácil acrescentar e retirarelementos,mastambémprecisamospoderusarosprefixoscomochavesemumdicionário,paraexcluirlistas.Comtuplas,vocênãopodeacrescentarouretirar,maspodeusarooperadordeadiçãoparaformarumanovatupla:

defshift(prefix,word):

returnprefix[1:]+(word,)

shift recebe uma tupla de palavras, prefix, e uma string,word, e forma umanova tupla que tem todas as palavras em prefix, exceto a primeira e wordadicionadanofinal.

Paraacoleçãodesufixos,asoperaçõesqueprecisamosexecutarincluemasomadeumnovosufixo(ouaumentodafrequênciadeumexistente),eaescolhadeumsufixoaleatório.

Acrescentarumnovosufixoéigualmentefácilparaaimplementaçãodalistaoudohistograma.Escolherumelementoaleatóriodeumalistaéfácil;escolherdeumhistogramaémaisdifícildefazerdeformaeficiente(veroExercício13.7).

Porenquanto,falamosprincipalmentesobreafacilidadedeimplementação,masháoutrosfatoresaconsiderarnaescolhadasestruturasdedados.Umdeleséotempo de execução. Às vezes, há uma razão teórica para esperar que umaestruturadedadossejamaisrápidaqueoutra;porexemplo,eumencioneiqueooperadorinémaisrápidoparadicionáriosqueparalistas,pelomenosquandoonúmerodeelementoségrande.

Page 198: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Porém, muitas vezes não se sabe de antemão qual implementação será maisrápida.Umaopçãoéimplementarambaseverqualémelhor.Estaabordageméchamada de benchmarking. Uma alternativa prática é escolher a estrutura dedadosmais fácil para implementar, e então ver se é rápida o suficiente para aaplicação desejada. Se for o caso, não é preciso continuar. Do contrário, háferramentas, como omódulo profile, que podem identificar os lugares emumprogramaquetomammaistempodeexecução.

Outro fator a considerar éo espaçode armazenamento.Por exemplo, usarumhistograma para a coleção de sufixos pode tomar menos espaço porque só éprecisoarmazenarcadapalavraumavez,nãoimportaquantasvezesapareçanotexto. Em alguns casos, a economia de espaço também pode fazer o seuprograma rodar mais rápido e, em casos extremos, seu programa podesimplesmentenemrodarseficarsemmemória.Porém,paramuitasaplicações,oespaçoéumaconsideraçãosecundáriadepoisdotempodeexecução.

Umúltimo comentário: nessa discussão, a ideia implícita é que devemos usarumaestruturadedadostantoparaanálisecomoparageração.Entretanto,comoessas fases são separadas, também seria possível usar uma estrutura para aanálise e então convertê-la em outra estrutura para a geração. Isso seria umavantagemseotempopoupadoduranteageraçãoexcedesseotempodecorridonaconversão.

13.10-Depuração

Quando estiver depurando um programa, especialmente se estiver trabalhandoemumerrodifícil,hácincocoisasquevocêpodetentar:

LeituraExamineseucódigo,leia-oparavocêmesmoeverifiquesedizoquevocêpensouemdizer.

ExecuçãoExperimente fazer alterações e executar versões diferentes.Muitas vezes,aoseexporacoisacertanolugarcertodoprograma,oproblemaficaóbvio,maspodesernecessárioconstruiroscaffolding.

RuminaçãoPense por algum tempo! Qual é o tipo do erro: de sintaxe, de tempo deexecução ou semântico? Quais informações você consegue obter a partirdasmensagens de erro, ou da saída do programa?Que tipo de erro pode

Page 199: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

causaroproblemaqueestávendo?Oquevocêmudouporúltimo,antesqueoproblemaaparecesse?

Conversacomopatodeborracha(rubberducking)Ao explicar o problema a alguém, às vezes você consegue encontrar aresposta antesde terminar a explicação.Muitasvezes, não éprecisonemhaveroutrapessoa;vocêpodefalaratécomumpatodeborracha.Eessaéaorigemdeumaestratégiabemconhecidachamadadedepuraçãodopatodeborracha. Não estou inventando isso, vejahttps://en.wikipedia.org/wiki/Rubber_duck_debugging.

RetiradaEmumdeterminadoponto,amelhorcoisaafazerévoltaratrásedesfazeras alterações recentes, até chegardevolta aumprogramaque funcioneequevocêentenda.Entãovocêpodecomeçarareconstruir.

Programadores iniciantes às vezes ficam presos em uma dessas atividades eesquecemdasoutras.Cadaatividadevemcomoseuprópriomododefalha.

Por exemplo, a leitura do seu código pode ajudar se o problema é um errotipográfico,masnãoseoproblemaforconceitual.Sevocênãoentendeoqueoseuprogramafaz,podelê-locemvezesenuncaveráoerro,porqueoerroestánasuacabeça.

Fazerexperiênciaspodeajudar,especialmentesevocêexecutartestespequenose simples.No entanto, se executar experiências sempensar ou ler seu código,pode cair em um padrão que chamo de “programação aleatória”, que é oprocesso de fazer alterações aleatórias até que o programa faça a coisa certa.Obviamente,aprogramaçãoaleatóriapodelevarmuitotempo.

É preciso pensar um pouco. A depuração é como ciência experimental. Devehaverpelomenosumahipótesesobrequaléoproblema.Sehouverduasoumaispossibilidades,tentepensaremumtestequeeliminariaumadelas.

Não obstante, até asmelhores técnicas de depuração falharão se houver errosdemais, ou se o código que está tentando corrigir for grande e complicadodemais.Àsvezes,amelhoropçãoévoltaratrás, simplificandooprogramaatéchegaraalgoquefuncioneequevocêentenda.

Programadores iniciantes muitas vezes relutam em voltar atrás porque nãosuportam a ideia de eliminar sequer uma linha de código (mesmo se estiver

Page 200: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

errada).Paravocêsesentirmelhor,copieseuprogramaemoutroarquivoantesde começar a desmontá-lo. Então você pode copiar as partes de volta, uma auma.

Encontrar um erro difícil exige leitura, execução, ruminação, e, às vezes, aretirada.Seempacaremalgumadessasatividades,tenteasoutras.

13.11-Glossário

deterministaRelativoaumprogramaquefazamesmacoisacadavezqueéexecutado,sereceberasmesmasentradas.

pseudoaleatórioRelativoaumasequênciadenúmerosqueparecemseraleatórios,masquesãogeradosporumprogramadeterminista.

valorpadrãoValordadoaumparâmetroopcionalsenãohouvernenhumargumento.

ignorar(override)Substituirumvalorpadrãoporumargumento.

benchmarkingProcesso de escolha entre estruturas de dados pela implementação dealternativasetestesemumaamostradeentradaspossíveis.

depuraçãodopatodeborrachaDepurarexplicandooproblemaaumobjeto inanimadocomoumpatodeborracha.Articularoproblemapodeajudararesolvê-lo,mesmoseopatodeborrachanãoconhecerPython.

13.12-Exercícios

Exercício13.9

A “classificação” de uma palavra é a sua posição em uma lista de palavrasclassificadas por frequência: a palavra mais comum tem a classificação 1, asegundamaiscomumé2etc.

AleideZipfdescrevearelaçãoentreclassificaçõesefrequênciasdaspalavrasem linguagens naturais (http://en.wikipedia.org/wiki/Zipf's_law). Ela prevêespecificamentequeafrequência,f,dapalavracomclassificaçãoré:

Page 201: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

f=cr−s

ondesecsãoparâmetrosquedependemdoidiomaedotexto.Sevocêtomarologaritmodeambososladosdestaequação,obtém:

logf=logc−slogr

Sevocêtraçarologdefcontraologder,teráumalinharetacomumaelevação-seinterceptarologdec.

Escrevaumprogramaqueleiaumtextoemumarquivo,conteasfrequênciasdaspalavras e exiba uma linha para cada palavra, em ordem descendente dafrequência,comlogdefelogder.Useoprogramagráficodesuaescolhaparatraçarosresultadoseverifiqueseformamumalinhareta.Vocêpodeestimarovalordes?

Solução: http://thinkpython2.com/code/zipf.py. Para executar aminha solução,você vai precisar do módulo de gráficos matplotlib. Se você instalou oAnaconda,játemomatplotlib;senãotiver,éprecisoinstalá-lo.

Page 202: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo14:ArquivosEstecapítuloapresentaa ideiadeprogramas“persistentes”,quemantêmdadosem armazenamento permanente, e mostra como usar tipos diferentes dearmazenamentopermanente,comoarquivosebancosdedados.

14.1-Persistência

A maioria dos programas que vimos até agora são transitórios, porque sãoexecutadosporalgumtempoeproduzemalgumasaída,mas,quandoterminam,seus dados desaparecem. Se executar o programa novamente, ele começanovamentedozero.

Outrosprogramassãopersistentes: rodampormuito tempo(ou todoo tempo);mantêmpelomenosalgunsdosseusdadosemarmazenamentopermanente(umaunidade de disco rígido, por exemplo); e se são desligados e reiniciados,continuamdeondepararam.

Exemplos de programas persistentes são sistemas operacionais, que rodampraticamente durante todo o tempo em que um computador está ligado, eservidoresweb,querodamtodootempo,esperandopedidosdeentradanarede.

Umadas formasmais simplesparaprogramasmanteremseusdadosé lendoeescrevendoarquivosde texto.Jávimosprogramasque leemarquivosde texto;nestecapítuloveremosprogramasqueosescrevem.

Uma alternativa é armazenar o estado do programa em um banco de dados.Nestecapítuloapresentareiumbancodedadossimpleseummódulo,pickle,quefacilitaoarmazenamentodedadosdeprogramas.

14.2-Leituraeescrita

Umarquivode textoéumasequênciadecaracteresarmazenadosemummeiopermanentecomoumaunidadededisco rígido,pendriveouCD-ROM.Vimoscomoabrirelerumarquivoem“Leituradelistasdepalavras”napágina133.

Page 203: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Paraescreverumarquivotexto,éprecisoabri-locomomodo'w'comosegundoparâmetro:

>>>fout=open('output.txt','w')

Se o arquivo já existe, abri-lo emmodode escrita elimina os dados antigos ecomeçatudodenovo,entãotenhacuidado!Seoarquivonãoexistir,écriadoumarquivonovo.

open retorna umobjeto de arquivo que fornecemétodos para trabalhar comoarquivo.Ométodowritepõedadosnoarquivo:

>>>line1="Thishere'sthewattle,\n"

>>>fout.write(line1)

24

O valor devolvido é o número de caracteres que foram escritos. O objeto dearquivomonitoraaposiçãoemqueestá,entãosevocêchamarwritenovamente,osnovosdadossãoacrescentadosaofimdoarquivo:

>>>line2="theemblemofourland.\n"

>>>fout.write(line2)

24

Aoterminardeescrever,vocêdevefecharoarquivo:

>>>fout.close()

Senãofecharoarquivo,eleéfechadoparavocêquandooprogramatermina.

14.3-Operadordeformatação

Oargumentodewritetemqueserumastring,então,sequisermosinseriroutrosvaloresemumarquivo,precisamosconvertê-losemstrings.Omodomaisfácildefazerissoécomstr:

>>>x=52

>>>fout.write(str(x))

Umaalternativaéusarooperadordeformatação,%.Quandoaplicadoanúmerosinteiros,%éooperadordemódulo.Noentanto,quandooprimeirooperandoé

Page 204: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

umastring,%éooperadordeformatação.

O primeiro operando é a string de formatação, que contém uma ou váriassequênciasde formataçãoqueespecificamcomoo segundooperandodeve serformatado.Oresultadoéumastring.

Porexemplo,asequênciadeformatação'%d'significaqueosegundooperandodeveserformatadocomoumnúmerointeirodecimal:

>>>camels=42

>>>'%d'%camels

'42'

Oresultadoéastring'42',quenãodeveserconfundidacomovalorinteiro42.

Umasequênciadeformataçãopodeapareceremqualquerlugarnastring,entãovocêpodeembutirumvaloremumasentença:

>>>'Ihavespotted%dcamels.'%camels

'Ihavespotted42camels.'

Sehouvermaisdeumasequênciadeformataçãonastring,osegundoargumentotem que ser uma tupla. Cada sequência de formatação é combinada com umelementodatupla,nestaordem.

O seguinte exemplo usa '%d' para formatar um número inteiro, '%g' paraformatar um número de ponto flutuante e '%s' para formatar qualquer objetocomoumastring:

>>>'In%dyearsIhavespotted%g%s.'%(3,0.1,'camels')

'In3yearsIhavespotted0.1camels.'

Onúmerodeelementosnatuplatemdecorresponderaonúmerodesequênciasdeformataçãonastring.Alémdisso,ostiposdoselementostêmdecorresponderàssequênciasdeformatação:

>>>'%d%d%d'%(1,2)

TypeError:notenoughargumentsforformatstring

>>>'%d'%'dollars'

TypeError:%dformat:anumberisrequired,notstr

Noprimeiroexemplonãoháelementossuficientes;nosegundo,oelementoédo

Page 205: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

tipoincorreto.

Para obter mais informações sobre o operador de formato, vejahttps://docs.python.org/3/library/stdtypes.html#printf-style-string-formatting.Vocêpodelersobreumaalternativamaiseficiente,ométododeformataçãodestrings,emhttps://docs.python.org/3/library/stdtypes.html#str.format.

14.4-Nomesdearquivoecaminhos

Os arquivos são organizados em diretórios (também chamados de “pastas”).Cadaprogramaemexecuçãotemum“diretórioatual”,queéodiretório-padrãodamaior parte das operações. Por exemplo, quando você abre um arquivo deleitura,Pythonoprocuranodiretórioatual.

Omóduloosfornecefunçõesparatrabalharcomarquivosediretórios(“os”éaabreviaçãode“sistemaoperacional”eminglês).os.getcwddevolveonomedodiretórioatual:

>>>importos

>>>cwd=os.getcwd()

>>>cwd

'/home/dinsdale'

cwdéaabreviaçãode“diretóriodetrabalhoatual”eminglês.Oresultadonesteexemplo é/home/dinsdale, que é o diretório-padrão de um usuário chamado“dinsdale”.

Umastringcomo'/home/dinsdale',que identificaumarquivooudiretório,échamadadecaminho(path).

Um nome de arquivo simples, como memo.txt, também é considerado umcaminho,maséumcaminhorelativo,porqueserelacionaaodiretórioatual.Seodiretório atual é /home/dinsdale, o nome de arquivo memo.txt se referiria a/home/dinsdale/memo.txt.

Umcaminhoquecomeçacom/nãodependedodiretórioatual;issoéchamadodecaminhoabsoluto.Paraencontrarocaminhoabsolutoparaumarquivo,vocêpodeusaros.path.abspath:

>>>os.path.abspath('memo.txt')

Page 206: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

'/home/dinsdale/memo.txt'

os.path fornece outras funções para trabalhar com nomes de arquivo ecaminhos.Porexemplo,os.path.existsqueverificaseumarquivooudiretórioexiste:

>>>os.path.exists('memo.txt')

True

Seexistir,os.path.isdirverificaseéumdiretório:

>>>os.path.isdir('memo.txt')

False

>>>os.path.isdir('/home/dinsdale')

True

Deformasimilar,os.path.isfileverificaseéumarquivo.

os.listdirretornaumalistadosarquivos(eoutrosdiretórios)nodiretóriodado:

>>>os.listdir(cwd)

['music','photos','memo.txt']

Parademonstraressasfunções,oexemploseguinte“passeia”porumdiretório,exibe os nomes de todos os arquivos e chama a simesmo recursivamente emtodososdiretórios:

defwalk(dirname):

fornameinos.listdir(dirname):

path=os.path.join(dirname,name)

ifos.path.isfile(path):

print(path)

else:

walk(path)

os.path.join recebe um diretório e um nome de arquivo e os une em umcaminhocompleto.

Omóduloosforneceumafunçãochamadawalk,queésemelhante,sóquemaisversátil.Comoexercício,leiaadocumentaçãoeuse-aparaexibirosnomesdosarquivos em um diretório dado e seus subdiretórios. Você pode baixar minhasoluçãoemhttp://thinkpython2.com/code/walk.py.

Page 207: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

14.5-Capturadeexceções

Muitas coisaspodemdar erradoquandovocê tenta ler e escrever arquivos.Setentarabrirumarquivoquenãoexiste,vocêrecebeumIOError:

>>>fin=open('bad_file')

IOError:[Errno2]Nosuchfileordirectory:'bad\_file'

Senãotiverpermissãoparaacessarumarquivo:

>>>fout=open('/etc/passwd','w')

PermissionError:[Errno13]Permissiondenied:'/etc/passwd'

Esetentarabrirumdiretórioparaleitura,recebe

>>>fin=open('/home')

IsADirectoryError:[Errno21]Isadirectory:'/home'

Para evitar esses erros, você pode usar funções como os.path.exists eos.path.isfile, mas levaria muito tempo e código para verificar todas aspossibilidades(se"Errno21"significaalgo,podeserquepelomenos21coisaspodemdarerrado).

Émelhor ir em frente e tentar, e lidar comproblemas se eles surgirem, que éexatamenteoqueainstruçãotryfaz.Asintaxeésemelhanteàdainstruçãoif…else:

try:

fin=open('bad_file')

except:

print('Somethingwentwrong.')

O Python começa executando a cláusula try. Se tudo for bem, ele ignora acláusula except e prossegue. Se ocorrer uma exceção, o programa sai dacláusulatryeexecutaacláusulaexcept.

Lidarcomexceçõesusandoumainstruçãotrychama-secapturarumaexceção.Nesteexemplo,acláusulaexceptexibeumamensagemdeerroquenãoémuitoútil.Emgeral, a captura de uma exceçãooferece a oportunidadede corrigir oproblema ou tentar novamente, ou, ao menos, de terminar o programaadequadamente.

Page 208: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

14.6-Bancosdedados

Um banco de dados é um arquivo organizado para armazenar dados. Muitosbancosdedadossãoorganizadoscomoumdicionário,porquemapeiamchavesavalores.Amaior diferença entre um banco de dados e um dicionário é que obanco de dados está em um disco (ou outro armazenamento permanente),portantopersistedepoisqueoprogramatermina.

Omódulodbmforneceumainterfaceparacriareatualizararquivosdebancodedados. Como exemplo, criarei um banco de dados que contém legendas dearquivosdeimagem.

Abrirumbancodedadosésemelhanteàaberturadeoutrosarquivos:

>>>importdbm

>>>db=dbm.open('captions','c')

Omodo'c'significaqueobancodedadosdevesercriado,seaindanãoexistir.O resultadoéumobjetodebancodedadosquepode serusado (para amaiorpartedasoperações)comoumdicionário.

Quandovocêcriaumnovoitem,dbmatualizaoarquivodebancodedados:

>>>db['cleese.png']='PhotoofJohnCleese.'

Quandovocêacessaumdositens,dbmlêoarquivo:

>>>db['cleese.png']

b'PhotoofJohnCleese.'

Oresultadoéumobjetobytes,oqueexplicaoprefixob.Umobjetobytes ésemelhanteaumastring,emmuitosaspectos.QuandovocêavançarnoPython,adiferençasetornaráimportante,mas,porenquanto,podemosignorá-la.

Sefizeroutraatribuiçãoaumachaveexistente,odbmsubstituiovalorantigo:

>>>db['cleese.png']='PhotoofJohnCleesedoingasillywalk.'

>>>db['cleese.png']

b'PhotoofJohnCleesedoingasillywalk.'

Algunsmétodosdedicionário,comokeyseitems,nãofuncionamcomobjetos

Page 209: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

debancodedados.Noentanto,aiteraçãocomumloopfor,sim:

forkeyindb:

print(key,db[key])

Comoemoutrosarquivos,vocêdevefecharobancodedadosquandoterminar:

>>>db.close()

14.7-UsandooPickle

Umalimitaçãodedbméqueaschaveseosvalorestêmqueserstringsoubytes.Setentarusaralgumoutrotipo,vaireceberumerro.

Omódulopicklepodeajudar.Eletraduzquasequalquertipodeobjetoemumastringconvenienteparaoarmazenamentoemumbancodedados,eentãotraduzstringsdevoltaemobjetos.

pickle.dumpsrecebeumobjetocomoparâmetroeretornaumarepresentaçãodestring:

>>>importpickle

>>>t=[1,2,3]

>>>pickle.dumps(t)

b'\x80\x03]q\x00(K\x01K\x02K\x03e.'

Oformatonãoéóbvioparaleitoreshumanos;oobjetivoéquesejafácilparaopickleinterpretar.pickle.loadsreconstituioobjeto:

>>>t1=[1,2,3]

>>>s=pickle.dumps(t1)

>>>t2=pickle.loads(s)

>>>t2

[1,2,3]

Embora o novo objeto tenha omesmovalor que o antigo, não é (emgeral) omesmoobjeto:

>>>t1==t2

True

>>>t1ist2

False

Page 210: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Emoutraspalavras,usaropickle.dumpsepickle.loads temomesmoefeitoquecopiaroobjeto.

Você pode usar o pickle para guardar variáveis que não são strings em umbancodedados.Naverdade,estacombinaçãoétãocomumquefoiencapsuladaemummódulochamadoshelve.

14.8-Pipes

A maior parte dos sistemas operacionais fornece uma interface de linha decomando,conhecidacomoshell.Shellsnormalmente fornecemcomandosparanavegarnossistemasdearquivoseexecutarprogramas.Porexemplo,emUnixvocêpodealterardiretórioscomcd,exibiroconteúdodeumdiretóriocomlseabrirumnavegadorwebdigitando(porexemplo)firefox.

Qualquer programa que possa ser aberto no shell também pode ser aberto noPythonusandoumobjetopipe,querepresentaumprogramaemexecução.

Porexemplo,ocomandoUnixls-lnormalmenteexibeoconteúdododiretórioatualnoformatolongo.Vocêpodeabrirlscomos.popen[1]:

>>>cmd='ls-l'

>>>fp=os.popen(cmd)

Oargumentoéumastringquecontémumcomandoshell.Ovalorderetornoéumobjetoquesecomportacomoumarquivoaberto.Épossível lerasaídadoprocesso ls uma linha por vez com readline ou receber tudo de uma vez comread:

>>>res=fp.read()

Aoterminar,fecheopipecomosefosseumarquivo:

>>>stat=fp.close()

>>>print(stat)

None

Ovalorderetornoéostatusfinaldoprocessols;Nonesignificaqueterminounormalmente(semerros).

Page 211: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Por exemplo, amaior parte dos sistemasUnix oferece um comando chamadomd5sum,quelêoconteúdodeumarquivoecalculaumaassinaturadigital.Vocêpode ler sobre o MD5 em http://en.wikipedia.org/wiki/Md5. Este comandofornece uma forma eficiente de verificar se dois arquivos têm o mesmoconteúdo. A probabilidade de dois conteúdos diferentes produzirem a mesmaassinatura digital émuito pequena (isto é,muito poucoprovável que aconteçaantesdocolapsodouniverso).

Vocêpodeusarumpipeparaexecutaromd5sumdoPythonereceberoresultado:

>>>filename='book.tex'

>>>cmd='md5sum'+filename

>>>fp=os.popen(cmd)

>>>res=fp.read()

>>>stat=fp.close()

>>>print(res)

1e0033f0ed0656636de0d75144ba32e0book.tex

>>>print(stat)

None

14.9-Escrevendomódulos

QualquerarquivoquecontenhacódigodoPythonpodeserimportadocomoummódulo.Porexemplo,vamossuporquevocêtenhaumarquivochamadowc.pycomoseguintecódigo:

deflinecount(filename):

count=0

forlineinopen(filename):

count+=1

returncount

print(linecount('wc.py'))

Quandoesteprogramaéexecutado,elelêasimesmoeexibeonúmerodelinhasnoarquivo,queé7.Vocêtambémpodeimportá-lodestaforma:

>>>importwc

7

Agoravocêtemumobjetodemódulowc:

Page 212: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>wc

<module'wc'from'wc.py'>

Oobjetodemóduloforneceolinecount:

>>>wc.linecount('wc.py')

7

EntãoéassimqueseescrevemódulosnoPython.

Oúnicoproblemacomesteexemploéquequandovocêimportaomódulo,eleexecutaocódigodetestenofinal.Normalmente,quandoseimportaummódulo,eledefinenovasfunções,masnãoasexecuta.

Os programas que serão importados como módulos muitas vezes usam aseguinteexpressão:

if__name__=='__main__':

print(linecount('wc.py'))

__name__éumavariávelintegrada,estabelecidaquandooprogramainicia.Seoprograma estiver rodando comoum script,__name__ temovalor'__main__';nestecaso,ocódigodetesteéexecutado.Docontrário,seomóduloestásendoimportado,ocódigodetesteéignorado.

Comoexercício,digiteesteexemploemumarquivochamadowc.pyeexecute-ocomoumscript.EntãoexecuteointerpretadordoPythoneimportwc.Qualéovalorde__name__quandoomóduloestásendoimportado?

Atenção:sevocêimportarummóduloquejátenhasidoimportado,oPythonnãofaznada.Elenãorelêoarquivo,mesmosetiversidoalterado.

Sequiserrecarregarummódulo,vocêpodeusarafunçãointegradareload,masisso pode causar problemas, então omais seguro é reiniciar o interpretador eimportaromódulonovamente.

14.10-Depuração

Quando estiver lendo e escrevendo arquivos, você pode ter problemas comwhitespace. Esses erros podem ser difíceis para depurar, porque os espaços,

Page 213: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

tabulaçõesequebrasdelinhanormalmentesãoinvisíveis:

>>>s='12\t3\n4'

>>>print(s)

123

4

A função integrada repr pode ajudar. Ela recebe qualquer objeto comoargumento e retorna uma representação em string do objeto. Para strings,representacaracteresdewhitespacecomsequênciasdebarrasinvertidas:

>>>print(repr(s))

'12\t3\n4'

Issopodeserútilparaadepuração.

Outro problema que você pode ter é que sistemas diferentes usam caracteresdiferentes para indicar o fim de uma linha. Alguns sistemas usam newline,representadopor\n.Outrosusamumcaracterederetorno,representadopor\r.Alguns usam ambos. Se mover arquivos entre sistemas diferentes, essasinconsistênciaspodemcausarproblemas.

Paraamaiorpartedos sistemasháaplicaçõesparaconverterdeumformatoaoutro. Você pode encontrá-los (e ler mais sobre o assunto) emhttp://en.wikipedia.org/wiki/Newline. Ou, é claro, você pode escrever um porcontaprópria.

14.11-Glossário

persistenteRelativo a umprograma que roda indefinidamente emantémpelomenosalgunsdosseusdadosemarmazenamentopermanente.

operadordeformataçãoUmoperador,%,querecebeumastringdeformataçãoeumatuplaegeraumastringque incluioselementosda tupla formatadacomoespecificadopelastringdeformatação.

stringdeformataçãoString usada com o operador de formatação, que contém sequências deformatação.

sequênciadeformatação

Page 214: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Sequência de caracteres em uma string de formatação, como %d, queespecificacomoumvalordeveserformatado.

arquivodetextoSequência de caracteres guardados emarmazenamento permanente, comoumaunidadedediscorígido.

diretórioUmacoleçãodearquivosnomeada,tambémchamadadepasta.

caminhoStringqueidentificaumarquivo.

caminhorelativoCaminhoqueinicianodiretórioatual.

caminhoabsolutoCaminhoque inicianodiretóriodeposiçãomaisalta (raiz)nosistemadearquivos.

capturarImpedirumaexceçãodeencerrarumprogramausandoas instruçõestryeexcept.

bancodedadosUmarquivocujoconteúdoéorganizadocomoumdicionário,comchavesquecorrespondemavalores.

objetobytesObjetosemelhanteaumastring.

shellPrograma que permite aos usuários digitar comandos e executá-los parainiciaroutrosprogramas.

objetopipeObjeto que representa um programa em execução, permitindo que umprogramadoPythonexecutecomandoseleiaosresultados.

14.12-Exercícios

Exercício14.1

Escreva uma função chamada sed que receba como argumentos uma string-padrão, uma string de substituição e dois nomes de arquivo; ela deve ler oprimeiro arquivo e escrever o conteúdo no segundo arquivo (criando-o, senecessário).Seastring-padrãoapareceremalgumlugardoarquivo,eladevesersubstituídapelastringdesubstituição.

Page 215: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Se ocorrer um erro durante a abertura, leitura, escrita ou fechamento dosarquivos,seuprogramadevecapturaraexceção,exibirumamensagemdeerroeencerrar.

Solução:http://thinkpython2.com/code/sed.py.

Exercício14.2

Se você baixar minha solução do Exercício 12.2 emhttp://thinkpython2.com/code/anagram_sets.py, verá que ela cria umdicionárioque mapeia uma string ordenada de letras à lista de palavras que podem sersoletradas com aquelas letras. Por exemplo, 'opst' mapeia à lista ['opts','post','pots','spot','stop','tops'].

Escrevaummóduloque importeanagram_sets e forneçaduasnovas funções:store_anagrams deve guardar o dicionário de anagramas emuma “prateleira”(objetocriadopelomódulosheve);read_anagramsdeveprocurarumapalavraedevolverumalistadosseusanagramas.

Solução:http://thinkpython2.com/code/anagram_db.py.

Exercício14.3

Em uma grande coleção de arquivosMP3 pode haver mais de uma cópia damesma música, guardada em diretórios diferentes ou com nomes de arquivodiferentes.Ametadesteexercícioéprocurarduplicatas.

1. Escreva um programa que procure um diretório e todos os seussubdiretórios, recursivamente, e retorne uma lista de caminhos completosde todos os arquivos com um dado sufixo (como .mp3). Dica: os.pathfornece várias funções úteis para manipular nomes de caminhos e dearquivos.

2. Para reconhecer duplicatas, você pode usar md5sum para calcular uma“somadecontrole”paracadaarquivo.Sedoisarquivos tiveremamesmasomadecontrole,provavelmentetêmomesmoconteúdo.

3. Paraconferiroresultado,vocêpodeusarocomandoUnixdiff.

Page 216: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Solução:http://thinkpython2.com/code/find_duplicates.py.

Page 217: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo15:ClasseseobjetosA esta altura você já sabe como usar funções para organizar código e tiposintegrados para organizar dados. O próximo passo é aprender “programaçãoorientadaaobjeto”,queusatiposdefinidospelosprogramadoresparaorganizartantoocódigoquantoosdados.Aprogramaçãoorientadaaobjetoéumtópicoabrangente;seráprecisopassarporalgunscapítulosparaabordarotema.

Os exemplos de código deste capítulo estão disponíveis emhttp://thinkpython2.com/code/Point1.py; as soluções para os exercícios estãodisponíveisemhttp://thinkpython2.com/code/Point1_soln.py.

15.1-Tiposdefinidospelosprogramadores

Já usamos muitos tipos integrados do Python; agora vamos definir um tipopróprio.Comoexemplo,criaremosumtipochamadoPoint,querepresentaumpontonoespaçobidimensional.

Na notaçãomatemática, os pontosmuitas vezes são escritos entre parênteses,com uma vírgula separando as coordenadas. Por exemplo, (0,0) representa aorigem e (x, y) representa o ponto que está x unidades à direita e y unidadesacimadaorigem.

HáváriasformaspararepresentarpontosnoPython:

Podemosarmazenarascoordenadasseparadamenteemduasvariáveis,xey.

Podemosarmazenarascoordenadascomoelementosemumalistaoutupla.

Podemoscriarumtipopararepresentarpontoscomoobjetos.

Criarumtipoémaiscomplicadoqueoutrasopções,mastemvantagensquelogoficarãoevidentes.

Um tipo definido pelo programador também é chamado de classe. Umadefiniçãodeclassepodeserassim:

Page 218: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

classPoint:

"""Representsapointin2-Dspace."""

OcabeçalhoindicaqueanovaclassesechamaPoint.Ocorpoéumadocstringque explica para que a classe serve. Você pode definir variáveis e métodosdentrodeumadefiniçãodeclasse,masvoltaremosaissodepois.

DefinirumaclassedenominadaPointcriaumobjetodeclasse:

>>>Point

<class'__main__.Point'>

Como Point é definido no nível superior, seu “nome completo” é__main__.Point.

Oobjetodeclasseécomoumafábricaparacriarobjetos.ParacriarumPoint,vocêchamaPointcomosefosseumafunção:

>>>blank=Point()

>>>blank

<__main__.Pointobjectat0xb7e9d3ac>

O valor de retorno é uma referência a um objeto Point, ao qual atribuímosblank.

Criarumobjetochama-seinstanciação,eoobjetoéumainstânciadaclasse.

Quandovocêexibeumainstância,oPythondizaqueclasseelapertenceeondeestá armazenada namemória (o prefixo o 0x significa que o número seguinteestáemformatohexadecimal).

Cadaobjetoéumainstânciadealgumaclasse,então“objeto”e“instância”sãointercambiáveis. Porém, neste capítulo uso “instância” para indicar que estoufalandosobreumtipodefinidopeloprogramador.

15.2-Atributos

Vocêpodeatribuirvaloresaumainstânciausandoanotaçãodeponto:

>>>blank.x=3.0

>>>blank.y=4.0

Page 219: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Essasintaxeésemelhanteàusadaparaselecionarumavariáveldeummódulo,comomath.pi ou string.whitespace.Nesse caso, entretanto, estamos atribuindovalores a elementos nomeados de um objeto. Esses elementos chamam-seatributos.

Eminglês,quandoéumsubstantivo,apalavra“AT-trib-ute”épronunciadacomênfasenaprimeirasílaba,aocontráriode“a-TRIB-ute”,queéumverbo.

O diagrama seguinte mostra o resultado dessas atribuições. Um diagrama deestadoquemostraumobjetoeseusatributoschama-sediagramadeobjeto;vejaaFigura15.1.

Figura15.1–DiagramadeumobjetoPoint.

Avariávelblankrefere-seaumobjetoPoint,quecontémdoisatributos.Cadaatributorefere-seaumnúmerodepontoflutuante.

Vocêpodelerovalordeumatributousandoamesmasintaxe:

>>>blank.y

4.0

>>>x=blank.x

>>>x

3.0

Aexpressãoblank.x significa “Vá ao objeto a que blank se refere e pegue ovalordex”.Noexemplo,atribuímosestevaloraumavariávelx.Nãohánenhumconflitoentreavariávelxeoatributox.

Você pode usar a notação de ponto como parte de qualquer expressão. Porexemplo:

>>>'(%g,%g)'%(blank.x,blank.y)

'(3.0,4.0)'

>>>distance=math.sqrt(blank.x**2+blank.y**2)

>>>distance

5.0

Page 220: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Você pode passar uma instância como argumento da forma habitual. Porexemplo:

defprint_point(p):

print('(%g,%g)'%(p.x,p.y))

print_pointtomaumpontocomoargumentoeoexibeemnotaçãomatemática.Parainvocá-lo,vocêpodepassarblankcomoargumento:

>>>print_point(blank)

(3.0,4.0)

Dentroda função,p é umaliasparablank, então, se a função alterap, blanktambémmuda.

Comoexercício,escrevaumafunçãochamadadistance_between_points,quetomadoispontoscomoargumentoseretornaadistânciaentreeles.

15.3-Retângulos

Àsvezes, é óbvio quais deveriam ser os atributos de umobjeto,mas outras épreciso decidir entre as possibilidades. Por exemplo, vamos supor que vocêestejacriandoumaclassepararepresentarretângulos.Queatributosusariaparaespecificaraposiçãoeotamanhodeumretângulo?Vocêpodeignorarângulo;para manter as coisas simples, suponha que o retângulo seja vertical ouhorizontal.

Háduaspossibilidades,nomínimo:

Você pode especificar um canto do retângulo (ou o centro), a largura e aaltura.

Vocêpodeespecificardoiscantosopostos.

Nesse ponto é difícil dizer qual opção é melhor, então implementaremos aprimeira,comoexemplo.

Aquiestáadefiniçãodeclasse:

classRectangle:

"""Representsarectangle.

Page 221: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

attributes:width,height,corner.

"""

Adocstring listaosatributos:widtheheight sãonúmeros;corneréumobjetoPointqueespecificaocantoinferioresquerdo.

Pararepresentarumretângulo,vocêtemqueinstanciarumobjetoRectangleeatribuirvaloresaosatributos:

box=Rectangle()

box.width=100.0

box.height=200.0

box.corner=Point()

box.corner.x=0.0

box.corner.y=0.0

Aexpressãobox.corner.xsignifica“Váaoobjetoaoqualboxserefereepegueo atributo denominado corner; então vá a este objeto e pegue o atributodenominadox”.

A Figura 15.2mostra o estado deste objeto. Um objeto que é um atributo deoutroobjetoéintegrado.

AFigura10.1mostraodiagramadeestadoparacheeses,numberseempty.

Figura15.2–DiagramadeumobjetoRectangle.

15.4-Instânciascomovaloresderetorno

As funções podem retornar instâncias. Por exemplo, find_center recebe umRectanglecomoargumentoedevolveumPoint,quecontémascoordenadasdocentrodoretângulo:

deffind_center(rect):

p=Point()

Page 222: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

p.x=rect.corner.x+rect.width/2

p.y=rect.corner.y+rect.height/2

returnp

Aquiestáumexemploquepassaboxcomoumargumentoparafind_centereatribuiopontoresultanteàvariávelcenter:

>>>center=find_center(box)

>>>print_point(center)

(50,100)

15.5-Objetossãomutáveis

Vocêpodealteraroestadodeumobjetofazendoumaatribuiçãoaumdosseusatributos.Porexemplo,paramudarotamanhodeumretângulosemmudarsuaposição,vocêpodealterarosvaloresdewidtheheight:

box.width=box.width+50

box.height=box.height+100

Você também pode escrever funções que alteram objetos. Por exemplo,grow_rectangle recebe um objeto Rectangle e dois números, dwidth edheight,eadicionaosnúmerosàlarguraealturadoretângulo:

defgrow_rectangle(rect,dwidth,dheight):

rect.width+=dwidth

rect.height+=dheight

Eisumexemploquedemonstraoefeito:

>>>box.width,box.height

(150.0,300.0)

>>>grow_rectangle(box,50,100)

>>>box.width,box.height

(200.0,400.0)

Dentrodafunção,rect éumaliasdebox, entãoquandoa funçãoalterarect,boxapontaparaoobjetoalterado.

Como exercício, escreva uma função chamada move_rectangle que toma umRectangle e dois números chamados dx e dy. Ela deve alterar a posição doretângulo, adicionando dx à coordenada x de corner e adicionando dy à

Page 223: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

coordenadaydecorner.

15.6-Cópia

Aliaspodemtornarumprogramadifícildelerporqueasalteraçõesemumlugarpodem ter efeitos inesperados em outro lugar. É difícil monitorar todas asvariáveisquepodemreferir-seaumdadoobjeto.

Emvezdeusaralias,copiaroobjetopodeserumaalternativa.Omódulocopycontémumafunçãochamadacopyquepodeduplicarqualquerobjeto:

>>>p1=Point()

>>>p1.x=3.0

>>>p1.y=4.0

>>>importcopy

>>>p2=copy.copy(p1)

p1ep2contêmosmesmosdados,masnãosãoomesmoPoint:

>>>print_point(p1)

(3,4)

>>>print_point(p2)

(3,4)

>>>p1isp2

False

>>>p1==p2

False

O operador is indica que p1 e p2 não são o mesmo objeto, que é o queesperamos. Porém, você poderia ter esperado que == fosse apresentado comoTrue, porque esses pontos contêm os mesmos dados. Nesse caso, pode ficardesapontadoaosaberque,parainstâncias,ocomportamentopadrãodooperador==éomesmoqueodooperadoris;eleverificaaidentidadedosobjetos,nãoasuaequivalência.Issoaconteceporque,paratiposdefinidospeloprogramador,oPythonnãosabeoquedeveserconsideradoequivalente.Pelomenos,aindanão.

Sevocêusarcopy.copyparaduplicarumretângulo,descobriráqueelecopiaoobjetoRectangle,masnãooPointembutidonele:

>>>box2=copy.copy(box)

>>>box2isbox

False

Page 224: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>box2.cornerisbox.corner

True

AFigura15.3mostracomoficaodiagramadeobjeto.Estaoperaçãochama-secópiasuperficialporquecopiaoobjetoequalquerreferênciaquecontenha,masnãoosobjetosintegrados.

Figura 15.3 – Diagrama: dois objetos Rectangle compartilhando o mesmoPoint.

Para amaior parte das aplicações, não é isso que você quer. Nesse exemplo,invocar grow_rectangle em um dos Rectangles não afetaria o outro, masinvocar move_rectangle em qualquer um deles afetaria a ambos! Essecomportamentoéconfusoepropensoaerros.

Felizmente, omódulo copy oferece ummétodo chamado deepcopy que copianãosóoobjeto,mastambémosobjetosaosquaiseleserefere,eosobjetosaosquaisestessereferem,eassimpordiante.Vocênãosesurpreenderáaodescobrirqueestaoperaçãosechamacópiaprofunda.

>>>box3=copy.deepcopy(box)

>>>box3isbox

False

>>>box3.cornerisbox.corner

False

box3eboxsãoobjetoscompletamenteseparados.

Comoexercício,escrevaumaversãodemove_rectanglequecriaeretorneumnovoretânguloemvezdealteraroantigo.

15.7-Depuração

Ao começar a trabalhar com objetos, provavelmente você encontrará algumasnovas exceções. Se tentar acessar um atributo que não existe, recebe umAttributeError:

Page 225: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>p=Point()

>>>p.x=3

>>>p.y=4

>>>p.z

AttributeError:Pointinstancehasnoattribute'z'

Senãoestivercertosobreotipoqueumobjetoé,podeperguntar:

>>>type(p)

<class'__main__.Point'>

Vocêtambémpodeusarisinstanceparaverificarseumobjetoéumainstânciadeumaclasse:

>>>isinstance(p,Point)

True

Casonãotenhacertezaseumobjetotemdeterminadoatributo,vocêpodeusarafunçãointegradahasattr:

>>>hasattr(p,'x')

True

>>>hasattr(p,'z')

False

O primeiro argumento pode ser qualquer objeto; o segundo argumento é umastringcomonomedoatributo.

Vocêtambémpodeusarumainstruçãotryparaverseoobjetotemosatributosdequeprecisa:

try:

x=p.x

exceptAttributeError:

x=0

Essa abordagem pode facilitar a escrita de funções que atuam com tiposdiferentes;vocêverámaisinformaçõessobreissoem“Polimorfismo”,napágina248.

15.8-Glossário

Page 226: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

classeTipodefinidopeloprogramador.Umadefiniçãodeclassecriaumobjetodeclasse.

objetodeclasseObjetoquecontémainformaçãosobreumtipodefinidopeloprogramador.Oobjetodeclassepodeserusadoparacriarinstânciasdotipo.

instânciaObjetoquepertenceaumaclasse.

instanciarCriarumobjeto.

atributoUmdosvaloresdenominadosassociadosaumobjeto.

objetointegradoObjetoqueéarmazenadocomoumatributodeoutroobjeto.

cópiasuperficialCopiar o conteúdo de um objeto, inclusive qualquer referência a objetosintegrados;implementadapelafunçãocopynomódulocopy.

cópiaprofundaCopiar o conteúdo de umobjeto, bem comoqualquer objeto integrado, equalquer objeto integrado a estes, e assim por diante; implementado pelafunçãodeepcopynomódulocopy.

diagramadeobjetoDiagramaquemostraobjetos,seusatributoseosvaloresdosatributos.

15.9-Exercícios

Exercício15.1

1. Escreva uma definição para uma classe denominada Circle, com osatributos center e radius, onde center é um objeto Point e radius é umnúmero.

2. Instancie um objeto Circle, que represente um círculo com o centro em150,100eraio75.

3. Escrevaumafunçãodenominadapoint_in_circle,quetomeumCircleeumPointeretorneTrue,seopontoestiverdentroounolimitedocírculo.

Page 227: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

4. Escrevaumafunçãochamadarect_in_circle,quetomeumCircleeumRectangle e retorne True, se o retângulo estiver totalmente dentro ou nolimitedocírculo.

5. Escreva uma função denominada rect_circle_overlap, que tome umCircle eumRectangle e retorneTrue, se algumdoscantosdo retângulocairdentrodocírculo.Ou,emumaversãomaisdesafiadora,retorneTruesealgumapartedoretângulocairdentrodocírculo.

Solução:http://thinkpython2.com/code/Circle.py.

Exercício15.2

1. Escreva uma função chamadadraw_rect que receba umobjetoTurtle eumRectangleeuseoTurtleparadesenharoretângulo.VejanoCapítulo4osexemplosdeusodeobjetosTurtle.

2. Escreva uma função chamada draw_circle, que tome um Turtle e umCircleedesenheocírculo.

Page 228: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo16:ClassesefunçõesAgoraquesabemoscomocriartipos,opróximopassodeveserescreverfunçõesquerecebamobjetosdefinidospeloprogramadorcomoparâmetroseosretornemcomo resultados.Neste capítulo tambémvou apresentar o “estilo funcional deprogramação”edoisnovosplanosdedesenvolvimentodeprogramas.

Os exemplos de código deste capítulo estão disponíveis emhttp://thinkpython2.com/code/Time1.py.Assoluçõesparaosexercíciosestãoemhttp://thinkpython2.com/code/Time1_soln.py.

16.1-Time

Para termais um exemplo de tipo definido pelo programador, criaremos umaclasse chamada Time (hora), que registra um horário no dia. A definição daclasseéassim:

classTime:

"""Representsthetimeofday.

attributes:hour,minute,second

"""

PodemoscriarumobjetoTimeeteratributosparahoras,minutosesegundos:

time=Time()

time.hour=11

time.minute=59

time.second=30

OdiagramadeestadodoobjetoTimeestánaFigura16.1.

Figura16.1–DiagramadeumobjetoTime.

Page 229: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Como exercício, escreva uma função chamada print_time, que receba umobjeto Time e o exiba na forma hour:minute:second. Dica: a sequência deformatação '%.2d' exibe um número inteiro com, pelo menos, dois dígitos,incluindoumzeroàesquerda,sefornecessário.

Escrevaumafunçãobooleanachamadais_after,querecebadoisobjetosTime,t1et2,edevolvaTrueset1forcronologicamentedepoisdet2eFalsesenãofor.Desafio:nãouseumainstruçãoif.

16.2-Funçõespuras

Nas próximas seções, vamos escrever duas funções que adicionam valores detempo.Elasdemonstramdois tiposdefunções: funçõespurasemodificadores.Tambémdemonstramumplanodedesenvolvimentoquechamareideprotótipoecorreção, que é uma formade atacar umproblema complexo começando comumprotótiposimpleselidandocomascomplicaçõesdeformaincremental.

Aquiestáumprotótiposimplesdeadd_time:

defadd_time(t1,t2):

sum=Time()

sum.hour=t1.hour+t2.hour

sum.minute=t1.minute+t2.minute

sum.second=t1.second+t2.second

returnsum

A função cria um novo objeto Time, inicializa seus atributos e retorna umareferência ao novo objeto. A função pura é chamada assim porque não alteranenhumdosobjetospassadosaelacomoargumentos;alémdisso,elanão temefeitos,comoexibirumvaloroureceberentradasdeusuário,apenasretornaumvalor.

Para testar esta função, criarei objetos Time: start, que contém o tempo deinício de um filme, comoMonty Python e o cálice sagrado, e duration, quecontémotempodeexecuçãodofilme,queéde1horae35minutos.

add_timecalculaquandoofilmeacaba:

>>>start=Time()

>>>start.hour=9

>>>start.minute=45

Page 230: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>start.second=0

>>>duration=Time()

>>>duration.hour=1

>>>duration.minute=35

>>>duration.second=0

>>>done=add_time(start,duration)

>>>print_time(done)

10:80:00

Oresultado,10:80:00,podenãoseroquevocêesperava.Oproblemaéqueestafunçãonãotratacasosondeonúmerodesegundosouminutosémaiorque60.Quando isso acontece, precisamos transportaros segundos extras à colunadosminutosouosminutosextrasàcolunadashoras.

Aquiestáumaversãomelhorada:

defadd_time(t1,t2):

sum=Time()

sum.hour=t1.hour+t2.hour

sum.minute=t1.minute+t2.minute

sum.second=t1.second+t2.second

ifsum.second>=60:

sum.second-=60

sum.minute+=1

ifsum.minute>=60:

sum.minute-=60

sum.hour+=1

returnsum

Emboraestafunçãoestejacorreta,éumpoucoextensa.Veremosumaalternativamenormaisadiante.

16.3-Modificadores

Àsvezeséútilumafunçãoalterarosobjetosquerecebecomoparâmetros.Nessecaso,asmudançassãovisíveisaquemchamaafunção.Asfunçõesquefazemissochamam-semodificadores.

increment,queacrescentaumdadonúmerodesegundosaumobjetoTime,podeserescritanaturalmentecomoummodificador.Aquiestáumprimeiroesboço:

defincrement(time,seconds):

time.second+=seconds

Page 231: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

iftime.second>=60:

time.second-=60

time.minute+=1

iftime.minute>=60:

time.minute-=60

time.hour+=1

Aprimeiralinhaexecutaaoperaçãobásica;orestolidacomoscasosespeciaisquevimosantes.

Estafunçãoestácorreta?Oqueacontecesesecondformuitomaisque60?

Nestecasonãobastatransportarumavez,temosquecontinuarfazendoissoatéquetime.secondsejamenosde60.Umasoluçãoésubstituirainstruçãoifpelainstruçãowhile. Isso tornariaafunçãocorreta,masnãomuitoeficiente.Comoexercício,escrevaumaversãocorretadeincrementquenãocontenhaloops.

Oquesefazcommodificadorestambémpodeserfeitocomfunçõespuras.Naverdade, algumas linguagens de programação só permitem funções puras. Háevidênciasdequeosprogramasqueusamfunçõespurassãomaisrápidosparaserem desenvolvidos e menos propensos a erros que programas que usammodificadores.Noentanto,modificadoressãoconvenientesdevezemquando,eosprogramasfuncionaistendemasermenoseficientes.

De formageral, recomendoquevocê escreva funções puras sempre que acharrazoável e recorra amodificadores só se houver alguma vantagem clara. Estaabordagempodeserchamadadeprogramaçãofuncional.

Comoexercício,escrevaumaversão“pura”deincrementquecriaeretornaumobjetoTimeemvezdealteraroparâmetro.

16.4-Prototipaçãoversusplanejamento

O plano de desenvolvimento que estou demonstrando chama-se “protótipo ecorreção”.Paracadafunção,escreviumprotótipoqueexecutaocálculobásicoeentãotestaafunção,corrigindoerrosnodecorrerdocaminho.

Esta abordagem pode ser eficaz, especialmente se você ainda não tem umacompreensão profunda do problema. Porém, as correções incrementais podemgerar código que se complica desnecessariamente (pois trata de muitos casos

Page 232: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

especiais) e pouco confiáveis (já que é difícil saber se todos os erros foramencontrados).

Umaalternativaéodesenvolvimentoplanejado,noqualacompreensãodealtoníveldoproblemapodefacilitarmuitoaprogramação.Nestecaso,descobre-sequeumobjetoTimeé,naverdade,umnúmerodetrêsdígitosnabase60(vejahttp://en.wikipedia.org/wiki/Sexagesimal)! O atributo second é a “coluna deunidades”,oatributominuteéa“colunados60”,eoatributohouréa“colunado3.600”.

Quando escrevemos add_time e increment, estávamos na verdade fazendoadiçõesnabase60, e por isso transportávamosos resultadosdeumacoluna àseguinte.

Essa observação sugere outra abordagem para o problema inteiro – podemosconverter objetos Time em números inteiros e aproveitar o fato de que ocomputadorsabetrabalharcomaritméticadenúmerosinteiros.

AquiestáumafunçãoqueconverteobjetosTimeemnúmerosinteiros:

deftime_to_int(time):

minutes=time.hour*60+time.minute

seconds=minutes*60+time.second

returnseconds

EaquiestáumafunçãoqueconverteumnúmerointeiroemumTime(lembre-sedequedivmoddivideoprimeiroargumentopelosegundoedevolveoquocienteeorestocomoumatupla):

defint_to_time(seconds):

time=Time()

minutes,time.second=divmod(seconds,60)

time.hour,time.minute=divmod(minutes,60)

returntime

Vocêpodeterquepensarumpoucoefazeralgunstestes,paraseconvencerdeque essas funções estão corretas. Um modo de testá-las é ver setime_to_int(int_to_time(x)) == x para muitos valores de x. Este é umexemplodeumaverificaçãodeconsistência.

Uma vez que esteja convencido de que estão corretas, você pode usá-las para

Page 233: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

reescreveradd_time:

defadd_time(t1,t2):

seconds=time_to_int(t1)+time_to_int(t2)

returnint_to_time(seconds)

Estaversãoémaiscurtaqueaoriginal,emaisfácildeverificar.Comoexercício,reescrevaincrementusandotime_to_inteint_to_time.

Emalgumas situações, converter da base 60 para a base 10 e de volta émaisdifícilqueapenaslidarcomashoras.Aconversãodebaseémaisabstrata;nossaintuiçãoparalidarcomvalorestemporaisémelhor.

Noentanto, se tivermosdiscernimentopara lidar comhorascomonúmerosdebase 60 e investirmos esforço em escrever as funções de conversão(time_to_inteint_to_time),chegamosaumprogramaqueémaiscurto,maisfácildeleredepurar,emaisconfiável.

Tambémémaisfácilacrescentarrecursosdepois.Porexemplo,imaginesubtrairdoisobjetosTimeparaencontraraduraçãoentreeles.Umaabordagemingênuaseriaimplementarasubtraçãocomtransporte.Porém,usarfunçõesdeconversãoseriamaisfácile,provavelmente,maiscorreto.

Ironicamente,tornarumproblemamaisdifícil(oumaisgeral)facilita(porquehámenoscasosespeciaisemenosoportunidadesdeerro).

16.5-Depuração

Umobjeto Time é bem formado se os valores de minute e second estiverementre 0 e 60 (incluindo 0,mas não 60) e sehour for positivo.hour e minutedevemservalores inteiros,maspodemospermitirquesecond tenhaumapartefracionária.

Requisitos como esses chamam-se invariáveis porque sempre devem serverdadeiros. Para dizer de outra forma, se não forem verdadeiros, algo deuerrado.

Escrever código para verificar requisitos invariáveis pode ajudar a descobrirerros e encontrar suas causas. Por exemplo, você pode ter uma função comovalid_time,querecebaumobjetoTimeeretorneFalseseeleviolarumrequisito

Page 234: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

invariável:

defvalid_time(time):

iftime.hour<0ortime.minute<0ortime.second<0:

returnFalse

iftime.minute>=60ortime.second>=60:

returnFalse

returnTrue

Noiníciodecadafunçãovocêpodeverificarosargumentosparatercertezadequesãoválidos:

defadd_time(t1,t2):

ifnotvalid_time(t1)ornotvalid_time(t2):

raiseValueError('invalidTimeobjectinadd_time')

seconds=time_to_int(t1)+time_to_int(t2)

returnint_to_time(seconds)

Ou você pode usar uma instrução assert, que verifica determinado requisitoinvariávelecriaumaexceçãoseelafalhar:

defadd_time(t1,t2):

assertvalid_time(t1)andvalid_time(t2)

seconds=time_to_int(t1)+time_to_int(t2)

returnint_to_time(seconds)

Instruçõesassertsãoúteisporquedistinguemocódigoquelidacomcondiçõesnormaisdocódigoqueverificaerros.

16.6-Glossário

protótipoecorreçãoPlano de desenvolvimento no qual a escrita do programa parte de umesboçoinicial,edepoissegueaotesteecorreçãodeerros,conformesejamencontrados.

desenvolvimentoplanejadoPlanodedesenvolvimentoque implicaumacompreensãodealtoníveldoproblema e mais planejamento que desenvolvimento incremental oudesenvolvimentoprototipado.

funçãopuraFunçãoquenãoalteranenhumdosobjetosquerecebecomoargumento.A

Page 235: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

maiorpartedasfunçõespurasgeraresultado.modificador

Funçãoquemodificaumouváriosdosobjetosquerecebecomoargumento.Amaiorpartedosmodificadoressãonulos;istoé,retornamNone.

programaçãofuncionalEstilodeprojetodeprogramanoqualamaioriadasfunçõessãopuras.

invariávelCondição que sempre deve ser verdadeira durante a execução de umprograma.

instruçãoassertInstruçãoqueverificaumacondiçãoelevantaumaexceçãoseestafalhar.

16.7-Exercícios

Os exemplos de código deste capítulo estão disponíveis emhttp://thinkpython2.com/code/Time1.py; as soluções para os exercícios estãodisponíveisemhttp://thinkpython2.com/code/Time1_soln.py.

Exercício16.1

Escreva uma função chamada mul_time que receba um objeto Time e umnúmeroeretorneumnovoobjetoTimequecontenhaoprodutodoTimeoriginaledonúmero.

Então use mul_time para escrever uma função que receba um objeto Timerepresentandootempoatéofimdeumacorridaeumnúmeroquerepresenteadistância,eretorneumobjetoTimecomopassomédio(tempopormilha).

Exercício16.2

OmódulodatetimeforneceobjetostimequesãosemelhantesaosobjetosTimedeste capítulo,mas ele oferece um grande conjunto demétodos e operadores.Leiaadocumentaçãoemhttp://docs.python.org/3/library/datetime.html.

1. Useomódulodatetimeparaescreverumprogramaquerecebaadataatualeexibaodiadasemana.

2. Escreva umprogramaque receba um aniversário como entrada e exiba a

Page 236: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

idadedousuárioeonúmerodedias,horas,minutosesegundosatéoseupróximoaniversário.

3. Paraduaspessoasnascidasemdiasdiferentes,háumdiaemqueaidadedeumaequivaleaduasvezesadaoutra.EsteéoDiaDuplodelas.Escrevaumprograma que receba dois aniversários e calcule o Dia Duplo dosaniversariantes.

4. Paraumdesafioumpoucomaior,escrevaaversãomaisgeralquecalculeodiaemqueumapessoaéNvezesmaisvelhaqueaoutra.

Page 237: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo17:ClassesemétodosEmboraestejamosusandoalgunsrecursosdeorientaçãoaobjetodoPython,osprogramas dos dois últimos capítulos não são realmente orientados a objeto,porquenãorepresentamasrelaçõesentreostiposdefinidospeloprogramadoreasfunçõesqueosproduzem.Opróximopassoé transformaressasfunçõesemmétodosquetornemasrelaçõesclaras.

Os exemplos de código deste capítulo estão disponíveis emhttp://thinkpython2.com/code/Time2.py e as soluções para os exercícios estãoemhttp://thinkpython2.com/code/Point2_soln.py.

17.1-Recursosdeorientaçãoaobjeto

Pythonéumalinguagemdeprogramaçãoorientadaaobjeto,ouseja,elaoferecerecursosdeprogramaçãoorientadaaobjetoquetemaseguintescaracterísticas:

Osprogramasincluemdefiniçõesdeclassesemétodos.

Amaiorpartedoscálculoséexpressaemtermosdeoperaçõesemobjetos.

Osobjetosmuitasvezes representamcoisasnomundo real, eosmétodosmuitas vezes correspondem às formas em que as coisas no mundo realinteragem.

Porexemplo,aclasseTimedefinidanoCapítulo16correspondeàformacomoaspessoasregistramahoradodia,easfunçõesquedefinimoscorrespondemaostipos de coisas que as pessoas fazem com os horários. De forma similar, asclasses Point e Rectangle no Capítulo 15 correspondem aos conceitosmatemáticosdepontoeretângulo.

Por enquanto, não aproveitamos os recursos que o Python oferece paraprogramaçãoorientadaaobjeto.Essesrecursosnãosãoestritamentenecessários;amaioriadelesofereceumasintaxealternativaparacoisasque já fizemos.Noentanto, emmuitos casos, a alternativa é mais concisa e representa de formamaisexataaestruturadoprograma.

Page 238: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Porexemplo,emTime1.pynãohánenhumaconexãoóbviaentreadefiniçãodeclasse e as definições de função que seguem. Com um pouco de atenção, éevidentequecadafunçãorecebepelomenosumobjetoTimecomoargumento.

Essa observação é amotivação para usarmétodos; ummétodo é uma funçãoassociada a determinada classe.Vimosmétodos de string, listas, dicionários etuplas. Neste capítulo definiremos métodos para tipos definidos peloprogramador.

Métodos são semanticamente o mesmo que funções, mas há duas diferençassintáticas:

Osmétodos são definidos dentro de uma definição de classe para tornarclaraarelaçãoentreaclasseeométodo.

Asintaxeparainvocarummétodoédiferentedasintaxeparachamarumafunção.

Nas próximas seções tomaremos as funções dos dois capítulos anteriores e astransformaremosemmétodos.Essatransformaçãoépuramentemecânica;vocêpode fazê-la seguindo uma série de passos. Se estiver à vontade para fazer aconversãoentreumaformaeoutra,semprepoderáescolheramelhorformaparacontemplarosseusobjetivos.

17.2-Exibiçãodeobjetos

NoCapítulo16definimosumaclassechamadaTimeem“Time”,napágina231,evocêescreveuumafunçãodenominadaprint_time:

classTime:

"""Representsthetimeofday."""

defprint_time(time):

print('%.2d:%.2d:%.2d'%(time.hour,time.minute,time.second))

Parachamarestafunção,vocêprecisapassarumobjetoTimecomoargumento:

>>>start=Time()

>>>start.hour=9

>>>start.minute=45

>>>start.second=00

Page 239: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>print_time(start)

09:45:00

Para fazerdeprint_time ummétodo, tudooqueprecisamos fazer émover adefinição da função para dentro da definição da classe. Note a alteração naendentação:

classTime:

defprint_time(time):

print('%.2d:%.2d:%.2d'%(time.hour,time.minute,time.second))

Agora há duas formas de chamar print_time. A primeira forma (e menoscomum)éusarasintaxedefunção:

>>>Time.print_time(start)

09:45:00

Nesse uso da notação de ponto, Time é o nome da classe, e print_time é onomedométodo.startépassadocomoumparâmetro.

Asegundaforma(emaisconcisa)éusarasintaxedemétodo:

>>>start.print_time()

09:45:00

Nesseusodanotaçãodeponto,print_timeéonomedométodo(novamente),estartéoobjetonoqualométodoéinvocado,quesechamadesujeito.Assimcomo em uma sentença, onde o sujeito é o foco da escrita, o sujeito de umainvocaçãodemétodoéofocodométodo.

Dentrodométodo,osujeitoéatribuídoaoprimeiroparâmetro,portanto,nestecaso,startéatribuídoatime.

Porconvenção,oprimeiroparâmetrodeummétodochama-seself,entãoseriamaiscomumescreverprint_timedestaforma:

classTime:

defprint_time(self):

print('%.2d:%.2d:%.2d'%(self.hour,self.minute,self.second))

Arazãodessaconvençãoéumametáforaimplícita:

Page 240: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

A sintaxe de uma chamada de função,print_time(start), sugere que afunçãoéoagenteativo.Eladizalgocomo:“Ei,print_time!Aquiestáumobjetoparavocêexibir”.

Naprogramaçãoorientadaaobjeto,osobjetossãoosagentesativos.Umainvocação de método como start.print_time() diz: “Ei, start! Porfavor,exiba-se”.

Essamudança de perspectiva pode sermais polida,mas não é óbvio que sejaútil.Nosexemplosquevimosatéagora,podenãoser.Porém,àsvezes,deslocara responsabilidade das funções para os objetos permite escrever funções (oumétodos)maisversáteisefacilitaamanutençãoereutilizaçãodocódigo.

Como exercício, reescreva time_to_int (de “Prototipação versusplanejamento”, na página 234) como um método. Você pode ficar tentado areescrever int_to_time como um método também, mas isso não faz muitosentidoporquenãohaverianenhumobjetosobreoqualinvocá-lo.

17.3-Outroexemplo

Aqui está uma versão de increment (de “Modificadores”, na página 233)reescritacomométodo:

#dentrodaclasseTime:

defincrement(self,seconds):

seconds+=self.time_to_int()

returnint_to_time(seconds)

Essa versão assume que time_to_int seja escrita comométodo. Além disso,observequeéumafunçãopura,nãoummodificador.

Éassimqueeuinvocariaincrement:

>>>start.print_time()

09:45:00

>>>end=start.increment(1337)

>>>end.print_time()

10:07:17

Osujeito, start, é atribuído aoprimeiroparâmetro, self.O argumento, 1337, éatribuídoaosegundoparâmetro,seconds.

Page 241: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Esse mecanismo pode ser confuso, especialmente se você fizer um erro. Porexemplo,seinvocarincrementcomdoisargumentos,recebe:

>>>end=start.increment(1337,460)

TypeError:increment()takes2positionalargumentsbut3weregiven

Amensagemdeerroéinicialmenteconfusa,porquehásódoisargumentosentreparênteses.No entanto, o sujeito tambémé considerado umargumento, então,somandotudo,sãotrês.

Apropósito,umargumentoposicionaléoquenãotemumnomedeparâmetro;istoé,nãoéumargumentodepalavra-chave.Nestachamadadafunção:

sketch(parrot,cage,dead=True)

parrotecagesãoposicionais,edeadéumargumentodepalavra-chave.

17.4-Umexemplomaiscomplicado

Reescrever is_after (de “Time”, na página 231) é ligeiramente maiscomplicado,porqueelarecebedoisobjetosTimecomoparâmetros.Nessecaso,a convenção é denominar o primeiro parâmetro self e o segundo parâmetroother:

#dentrodaclasseTime:

defis_after(self,other):

returnself.time_to_int()>other.time_to_int()

Parausarestemétodo,vocêdeveinvocá-loparaumobjetoepassaroutrocomoargumento:

>>>end.is_after(start)

True

Umavantagemdestasintaxeéqueéquaseliteraleminglês:“ofimédepoisdapartida?”.

17.5-Métodoinit

Page 242: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Ométodo__init__(abreviaçãodapalavraeminglêspara“inicialização”)éummétodoespecial,invocadoquandoumobjetoéinstanciado.Seunomecompletoé __init__ (dois caracteres de sublinhado, seguidos de init, e mais doissublinhados).Ummétodo__init__daclasseTimepodeseralgoassim:

#dentrodaclasseTime:

def__init__(self,hour=0,minute=0,second=0):

self.hour=hour

self.minute=minute

self.second=second

É comum que os parâmetros de __init__ tenham os mesmos nomes que osatributos.Ainstrução

self.hour=hour

guardaovalordoparâmetrohourcomoumatributodeself.

Os parâmetros são opcionais, então, se você chamar Time sem argumentos,recebeosvalorespadrão:

>>>time=Time()

>>>time.print_time()

00:00:00

Seincluirumargumento,eledefinehour.

>>>time=Time(9)

>>>time.print_time()

09:00:00

Sefornecerdoisargumentos,houreminuteserãodefinidos:

>>>time=Time(9,45)

>>>time.print_time()

09:45:00

Esevocêfornecertrêsargumentos,ostrêsvaloresserãodefinidos.

Comoexercício,escrevaummétodoinitdaclassePointquerecebaxeycomoparâmetrosopcionaiseosrelacioneaosatributoscorrespondentes.

Page 243: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

17.6-Método__str__

__str__ é um método especial, como __init__, usado para retornar umarepresentaçãodestringdeumobjeto.

Porexemplo,aquiestáummétodostrparaobjetosTime:

#dentrodaclasseTime:

def__str__(self):

return'%.2d:%.2d:%.2d'%(self.hour,self.minute,self.second)

Aoexibirumobjetocomprint,oPythoninvocaométodostr:

>>>time=Time(9,45)

>>>print(time)

09:45:00

Quandoescrevoumanovaclasse,quasesemprecomeçoescrevendo__init__,oquefacilitaainstanciaçãodeobjetos,e__str__,queéútilparaadepuração.

Comoexercício,escrevaummétodostrdaclassePoint.CrieumobjetoPointeexiba-o.

17.7-Sobrecargadeoperadores

Aodefiniroutrosmétodosespeciais,vocêpodeespecificarocomportamentodeoperadoresnos tiposdefinidospeloprogramador.Porexemplo,sevocêdefinirummétodochamado__add__paraaclasseTimedeTime,podeusarooperador+emobjetosTime.

Adefiniçãopodeserassim:

#dentrodaclasseTime:

def__add__(self,other):

seconds=self.time_to_int()+other.time_to_int()

returnint_to_time(seconds)

Vocêpodeusá-loassim:

Page 244: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>start=Time(9,45)

>>>duration=Time(1,35)

>>>print(start+duration)

11:20:00

Aoaplicarooperador+aobjetosTime,oPythoninvoca__add__.Aoexibiroresultado, o Python invoca__str__.Ou seja, hámuita coisa acontecendo nosbastidores!

Alterarocomportamentodeumoperadorparaquefuncionecomtiposdefinidospelo programador chama-se sobrecarga de operadores. Para cada operador noPythonháummétodoespecialcorrespondente,como__add__.Paraobtermaisinformações, vejahttp://docs.python.org/3/reference/datamodel.html#specialnames.

Comoexercício,escrevaummétodoaddparaaclassePoint.

17.8-Despachoportipo

Na seção anterior, acrescentamos dois objetos Time, mas você também podequerer acrescentar um número inteiro a um objeto Time. A seguir, veja umaversãode__add__,queverificaotipodeothereinvocaadd_timeouincrement:

#dentrodaclasseTime:

def__add__(self,other):

ifisinstance(other,Time):

returnself.add_time(other)

else:

returnself.increment(other)

defadd_time(self,other):

seconds=self.time_to_int()+other.time_to_int()

returnint_to_time(seconds)

defincrement(self,seconds):

seconds+=self.time_to_int()

returnint_to_time(seconds)

AfunçãoconstruídaisinstancerecebeumvaloreumobjetodeclasseeretornaTrueseovalorforumainstânciadaclasse.

Seother forumobjetoTime,__add__ invocaadd_time.Docontrário, assume

Page 245: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

queoparâmetro sejaumnúmeroe invoca increment.Essaoperaçãochama-sedespachoportipoporquedespachaaoperaçãoamétodosdiferentes,baseadosnotipodosargumentos.

Vejaexemplosqueusamooperador+comtiposdiferentes:

>>>start=Time(9,45)

>>>duration=Time(1,35)

>>>print(start+duration)

11:20:00

>>>print(start+1337)

10:07:17

Infelizmente, esta implementação da adição não é comutativa. Se o númerointeiroforoprimeirooperando,vocêrecebe

>>>print(1337+start)

TypeError:unsupportedoperandtype(s)for+:'int'and'instance'

Oproblema é que, em vez de pedir ao objeto Time que adicione um númerointeiro,oPythonestápedindoqueumnúmerointeiroadicioneumobjetoTime,eelenãosabecomofazerisso.Entretanto,háumasoluçãointeligenteparaesteproblema: ométodo especial __radd__, que significa “adição à direita”. EssemétodoéinvocadoquandoumobjetoTimeaparecenoladodireitodooperador+.Aquiestáadefinição:

#dentrodaclasseTime:

def__radd__(self,other):

returnself.__add__(other)

Eéassimqueeleéusado:

>>>print(1337+start)

10:07:17

Como exercício, escreva um método add para Points que funcione com umobjetoPointoucomumatupla:

Se o segundo operando for um Point, o método deve retornar um novoPoint cuja coordenada x é a soma das coordenadas x dos operandos, e omesmoseaplicaàscoordenadasdey.

Page 246: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Seosegundooperandoforumatupla,ométododeveadicionaroprimeiroelementodatuplaàcoordenadadexeosegundoelementoàcoordenadadey,retornandoumnovoPointcomoresultado.

17.9-Polimorfismo

Odespachopor tipoéútil,mas (felizmente)nemsempreénecessário.Muitasvezes,vocêpodeevitá-loescrevendofunçõesquefuncionemcorretamenteparaargumentosdetiposdiferentes.

Muitasdasfunçõesqueescrevemosparastringstambémfuncionamparaoutrostipos de sequência. Por exemplo, em “Um dicionário como uma coleção decontadores”, na página 163, usamoshistogrampara contar o númerode vezesquecadaletraaparecenumapalavra:

defhistogram(s):

d=dict()

forcins:

ifcnotind:

d[c]=1

else:

d[c]=d[c]+1

returnd

Essafunçãotambémfuncionacomlistas,tuplaseatédicionários,desdequeoselementosdessejamhashable,entãoelespodemserusadoscomochavesemd:

>>>t=['spam','egg','spam','spam','bacon','spam']

>>>histogram(t)

{'bacon':1,'egg':1,'spam':4}

As funções que funcionam com vários tipos chamam-se polimórficas. Opolimorfismo pode facilitar a reutilização do código. Por exemplo, a funçãointegradasum,queadicionaoselementosdeumasequência,funcionasóseoselementosdasequênciaforemcompatíveiscomadição.

ComoosobjetosTimeoferecemométodoadd,elesfuncionamcomsum:

>>>t1=Time(7,43)

>>>t2=Time(7,41)

>>>t3=Time(7,37)

>>>total=sum([t1,t2,t3])

Page 247: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>print(total)

23:01:00

Emgeral, se todasasoperaçõesdentrodeumafunçãoforemcompatíveiscomumdadotipo,nãohaveráproblemas.

Omelhor tipodepolimorfismoéonãointencional,quandovocêdescobrequeumafunçãoquejáescreveupodeseraplicadaaumtipoparaoqualelanãotinhaplanejada.

17.10-Interfaceeimplementação

Uma das metas do projeto orientado a objeto é facilitar a manutenção doprograma, para que você possamantê-lo funcionandoquandooutras partes dosistema forem alteradas, e também poder alterar o programa para satisfazernovascondições.

Um princípio de projeto que ajuda a atingir essameta é manter as interfacesseparadasdasimplementações.Paraobjetos,issoquerdizerqueosmétodosqueumaclasseoferecenãodevemdependerdecomoosatributossãorepresentados.

Porexemplo,nestecapítulodesenvolvemosumaclassequerepresentaumahorado dia. Osmétodos fornecidos por esta classe incluem time_to_int, is_after eadd_time.

Podemos implementar esses métodos de várias formas. Os detalhes daimplementação dependemde como representamos as horas.Neste capítulo, osatributosdeumobjetoTimesãohour,minuteesecond.

Como alternativa, podemos substituir esses atributos por um número inteiroúnico que represente o número de segundos desde a meia-noite. Essaimplementaçãofariacomquealgunsmétodos,comois_after,fossemmaisfáceisdeescrever,masdificultariaousodeoutrosmétodos.

Podeacontecerque,depoisdeimplementarumanovaclasse,vocêdescubraumaimplementaçãomelhor. Se outras partes do programa estiverem usando a suaclasse,mudarainterfacepodesertrabalhosoeinduziraerros.

No entanto, se projetou a interface cuidadosamente, pode alterar aimplementaçãosemmudarainterface,enãoseráprecisomudaroutraspartesdo

Page 248: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

programa.

17.11-Depuração

É legal acrescentar atributos a objetos em qualquer ponto da execução de umprograma,mas se você tiver objetos domesmo tipo que não têm osmesmosatributos,éfácilcometererros.Éumaboaideiainicializartodososatributosdeumobjetonométodoinit.

Casonão tenha certeza seumobjeto temumdeterminadoatributo, vocêpodeusarafunçãointegradahasattr(ver“Depuração”,napágina236).

Outraformadeacessaratributosécomafunçãointegradavars,querecebeumobjetoeretornaumdicionárioquemapeiaosnomesdosatributos(comostrings)aosseusvalores:

>>>p=Point(3,4)

>>>vars(p)

{'y':4,'x':3}

Parafacilitaradepuração,podeserútilusarestafunção:

defprint_attributes(obj):

forattrinvars(obj):

print(attr,getattr(obj,attr))

print_attributesatravessaodicionárioeimprimecadanomedeatributoeoseuvalorcorrespondente.

Afunçãointegradagetattrrecebeumobjetoeumnomedeatributo(comoumastring)edevolveovalordoatributo.

17.12-Glossário

linguagemorientadaaobjetoLinguagemquefornecerecursos,comotiposdefinidospeloprogramadoremétodos,quefacilitamaprogramaçãoorientadaaobjeto.

programaçãoorientadaaobjetoEstilodeprogramaçãonaqualosdadoseasoperaçõesqueosmanipulamsãoorganizadasemclassesemétodos.

Page 249: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

métodoFunçãocriadadentrodeumadefiniçãodeclasseeinvocadaeminstânciasdestaclasse.

sujeitoObjetosobreoqualummétodoéinvocado.

argumentoposicionalArgumento que não inclui um nome de parâmetro, portanto não é umargumentodepalavra-chave.

sobrecargadeoperadorAlteração do comportamento de um operador como + para que funcionecomumtipodefinidopeloprogramador.

despachoportipoModelodeprogramaçãoqueinvocafunçõesdiferentesdependendodotipodooperando.

polimórficoPertinenteaumafunçãoquepodefuncionarcommaisdeumtipo.

ocultamentodeinformaçãoPrincípio segundo o qual a interface fornecida por um objeto não devedependerdasuaimplementação,especialmenteemrelaçãoàrepresentaçãodosseusatributos.

17.13-Exercícios

Exercício17.1

Baixeocódigodestecapítuloemhttp://thinkpython2.com/code/Time2.py.AltereosatributosdeTimeparaqueumnúmerointeiroúnicorepresenteossegundosdecorridosdesdeameia-noite.Entãoaltereosmétodos(eafunçãoint_to_time)parafuncionarcomanovaimplementação.Vocênãodevemodificarocódigodetesteemmain.Aoterminar,asaídadeveseramesmaqueantes.

Solução:http://thinkpython2.com/code/Time2_soln.py.

Exercício17.2

Este exercício é uma história com moral sobre um dos erros mais comuns edifíceis de encontrar no Python. Escreva uma definição de classe chamadaKangaroocomosseguintesmétodos:

Page 250: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

1. Ummétodo__init__queinicializeumatributochamadopouch_contentsemumalistavazia.

2. Ummétodochamadoput_in_pouchquerecebaumobjetodequalquertipoeoacrescenteapouch_contents.

3. Ummétodo __str__ que retorne uma representação de string do objetoKangarooeosconteúdosdepouch(bolsa).

Teste o seu código criando dois objetos Kangaroo, atribuindo-os a variáveischamadaskangaeroo,eentãoacrescentandorooaoconteúdodabolsadekanga.

Baixe http://thinkpython2.com/code/BadKangaroo.py. Ele contém uma soluçãopara o problema anterior com um defeito bem grande e bem feio. Encontre ecorrijaodefeito.

Se não conseguir achar a solução, você pode baixarhttp://thinkpython2.com/code/GoodKangaroo.py, que explica o problema edemonstraumasolução.

Page 251: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo18:HerançaO termomais associado com a programação orientada a objeto é herança. Aherança é a capacidade de definir uma nova classe que seja uma versãomodificada de uma classe existente. Neste capítulo demonstrarei a herançausandoclassesquerepresentamjogosdecartas,baralhosemãosdepôquer.

Se você não joga pôquer, pode ler sobre ele emhttp://en.wikipedia.org/wiki/Poker,masnão énecessário; voudizer tudooqueprecisasaberparaosexercícios.

Os exemplos de código deste capítulo estão disponíveis emhttp://thinkpython2.com/code/Card.py.

18.1-ObjetosCard

Há52cartasemumbaralho,ecadaumapertencea1dos4naipesea1dos13valores. Os naipes são espadas, copas, ouros e paus (no bridge, em ordemdescendente).Aordemdosvaloreséás,2,3,4,5,6,7,8,9,10,valete,damaerei.Dependendodojogoqueestiverjogando,umáspodesermaisaltoqueoreioumaisbaixoque2.

Sequiséssemosdefinirumnovoobjetopara representarumacartade jogo,osatributosóbviosseriamrank(valor)esuit(naipe).Masnãoétãoóbvioqualtipode atributodeveriam ser.Umapossibilidade éusar strings compalavras como'Spade'(Espadas)paranaipese'Queen'(Dama)paravalores.Umproblemacomestaimplementaçãoéquenãoseriafácilcompararcartasparaverqualvalorounaipetemclassificaçãomaisaltaemrelaçãoaosoutros.

Uma alternativa é usar números inteiros para codificar os valores e os naipes.Neste contexto, “codificar” significa que vamos definir ummapeamento entrenúmerosenaipes,ouentrenúmerosevalores.Estetipodecodificaçãonãotemnadaavercomcriptografia.

Por exemplo, esta tabela mostra os naipes e os códigos de número inteirocorrespondentes:

Page 252: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Spades(Espadas)↦3Hearts(Copas)↦2Diamonds(Ouros)↦1Clubs(Paus)↦0

Este código facilita a comparação entre as cartas; como naipes mais altosmapeiamanúmerosmaisaltos,podemoscompararnaipesaosseuscódigos.

O mapeamento de valores é até óbvio; cada um dos valores numéricos émapeadoaonúmerointeirocorrespondente,eparacartascomfiguras:

Jack(Valete)↦11Queen(Dama)↦12King(Rei)↦13

Estou usando o símbolo ↦ para deixar claro que esses mapeamentos não sãopartedoprogramaemPython.Elessãopartedoprojetodoprograma,masnãoaparecemexplicitamentenocódigo.

AdefiniçãodeclasseparaCard(carta)éassim:

classCard:

"""Representsastandardplayingcard."""

def__init__(self,suit=0,rank=2):

self.suit=suit

self.rank=rank

Como sempre, o método __init__ recebe um parâmetro opcional de cadaatributo.Acartapadrãoé2depaus.

ParacriarumCard,vocêchamaCardcomonaipeevalordesejados:

queen_of_diamonds=Card(1,12)

18.2-Atributosdeclasse

Para exibir objetos Card de uma forma que as pessoas possam ler comfacilidade, precisamos de ummapeamento dos códigos de número inteiro aosnaipesevalorescorrespondentes.Umaformanaturaldefazerissoécomlistasdestrings.Atribuímosessaslistasaatributosdeclasse:

#dentrodaclasseCard:

Page 253: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

suit_names=['Clubs','Diamonds','Hearts','Spades']

rank_names=[None,'Ace','2','3','4','5','6','7',

'8','9','10','Jack','Queen','King']

def__str__(self):

return'%sof%s'%(Card.rank_names[self.rank],

Card.suit_names[self.suit])

Variáveis como suit_names e rank_names, que são definidas dentro de umaclasse,masforadequalquermétodo,chamam-seatributosdeclasseporquesãoassociadascomoobjetodeclasseCard.

Estetermoasdistinguedevariáveiscomosuiterank,chamadasdeatributosdeinstânciaporquesãoassociadoscomdeterminadainstância.

Ambos os tipos de atributo são acessados usando a notação de ponto. Porexemplo,em__str__,self é umobjetoCard, eself.rank é o seu valor.Deformasemelhante,Cardéumobjetodeclasse,eCard.rank_nameséuma listadestringsassociadasàessaclasse.

Cada carta tem seupróprio suit e rank,mashá sóumacópiade suit_names erank_names.

Juntandotudo,aexpressãoCard.rank_names[self.rank]significa“useorank(valor)doatributodoobjetoselfcomoumíndicenalistarank_namesdaclasseCardeselecioneastringadequada”.

Oprimeiroelementoderank_nameséNone,porquenãohánenhumacartacomvalor zero. Incluindo None para ocupar uma variável, conseguimos fazer umbelomapeamento onde o índice 2 é associado à string '2', e assimpor diante.Paraevitar terqueusaresse truque,poderíamosusarumdicionárioemvezdeumalista.

Comosmétodosquetemosporenquanto,podemoscriareexibircartas:

>>>card1=Card(2,11)

>>>print(card1)

JackofHearts

AFigura18.1éumdiagramadoobjetodeclasseCardeumainstânciadeCard.Cardéumobjetodeclasse;seutipoétype.card1éumainstânciadeCard,então

Page 254: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

seutipoéCard.Paraeconomizarespaço,nãoincluíoconteúdodesuit_nameserank_names.

Figura 18.1 – Diagrama de objetos: classe Card e card1, uma instância deCard.

18.3-Comparaçãodecartas

Para tipos integrados, há operadores relacionais (<, >, == etc.) que comparamvalores e determinam quando um émaior,menor ou igual a outro. Para tiposdefinidospeloprogramador,podemosignorarocomportamentodosoperadoresintegrados fornecendoummétododenominado__lt__,querepresenta“menosque”.

__lt__ recebe dois parâmetros, self e other, e True se self for estritamentemenorqueother.

Aordemcorretadascartasnãoéóbvia.Porexemplo,qualémelhor,o3depausouo2deouros?Umatemovalormaisalto,masaoutratemumnaipemaisalto.Para comparar cartas, é preciso decidir o que émais importante, o valor ou onaipe.

A resposta pode depender de que jogo você está jogando,mas, paramanter asimplicidade,vamosfazeraescolhaarbitráriadequeonaipeémaisimportante,entãotodasascartasdeespadassãomaisimportantesqueasdeouros,eassimpordiante.

Page 255: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Comistodecidido,podemosescrever__lt__:

#dentrodaclasseCard:

def__lt__(self,other):

#conferirosnaipes

ifself.suit<other.suit:returnTrue

ifself.suit>other.suit:returnFalse

#osnaipessãoosmesmos...conferirvalores

returnself.rank<other.rank

Você pode escrever isso de forma mais concisa usando uma comparação detuplas:

#dentrodaclasseCard:

def__lt__(self,other):

t1=self.suit,self.rank

t2=other.suit,other.rank

returnt1<t2

Comoexercício,escrevaummétodo__lt__paraobjetosTime.Vocêpodeusaruma comparação de tuplas,mas tambémpode usar a comparação de númerosinteiros.

18.4-Baralhos

Agora que temos Card, o próximo passo é definir Deck (baralho). Como umbaralhoé compostodecartas, énaturalqueumbaralhocontenhauma listadecartascomoatributo.

Vejaa seguirumadefiniçãodeclasseparaDeck.Ométodo initcriaoatributocardsegeraoconjuntopadrãode52cartas:

classDeck:

def__init__(self):

self.cards=[]

forsuitinrange(4):

forrankinrange(1,14):

card=Card(suit,rank)

self.cards.append(card)

Page 256: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

A formamais fácil de preencher o baralho é com um loop aninhado. O loopexteriorenumeraosnaipesde0a3.Oloopinteriorenumeraosvaloresde1a13.CadaiteraçãocriaumnovoCardcomonaipeevaloratual,eaacrescentaaself.cards.

18.5-Exibiçãodobaralho

AquiestáummétodostrparaDeck:

#dentrodaclasseDeck:

def__str__(self):

res=[]

forcardinself.cards:

res.append(str(card))

return'\n'.join(res)

Estemétododemonstrauma formaeficientedeacumularumastringgrande:acriaçãodeumalistadestringseautilizaçãodométododestringjoin.Afunçãointegradastrinvocaométodo__str__emcadacartaeretornaarepresentaçãodastring.

Como invocamos join em um caractere newline, as cartas são separadas porquebrasdelinha.Oresultadoéesse:

>>>deck=Deck()

>>>print(deck)

AceofClubs

2ofClubs

3ofClubs

...

10ofSpades

JackofSpades

QueenofSpades

KingofSpades

Emboraoresultadoapareçaem52linhas,naverdadeeleéumastringlongacomquebrasdelinha.

18.6-Adição,remoção,embaralhamentoeclassificação

Page 257: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Paralidarcomascartas,gostaríamosdeterummétodoqueremovesseumacartadobaralhoeadevolvesse.Ométododelistapopofereceumaformaconvenientedefazerisso:

#dentrodaclasseDeck:

defpop_card(self):

returnself.cards.pop()

Comopopretiraaúltimacartanalista,estamoslidandocomofundodobaralho.

Paraadicionarumacarta,podemosusarométododelistaappend:

#dentrodaclasseDeck:

defadd_card(self,card):

self.cards.append(card)

Ummétodocomoesse,queusaoutrométodosemdarmuitotrabalho,àsvezeséchamadodefolheado.Ametáforavemdotrabalhoemmadeira,ondeofolheadoé uma camada fina de madeira de boa qualidade colada à superfície de umamadeiramaisbarataparamelhoraraaparência.

Nessecaso,add_cardéummétodo“fino”queexpressaumaoperaçãode listaem termos adequados a baralhos. Ele melhora a aparência ou interface daimplementação.

Em outro exemplo, podemos escrever um método Deck denominado shuffle,usandoafunçãoshuffledomódulorandom:

#dentrodaclasseDeck:

defshuffle(self):

random.shuffle(self.cards)

Nãoseesqueçadeimportarrandom.

Comoexercício,escrevaummétododeDeckchamadosort,queuseométododelistasortparaclassificarascartasemumDeck.sortusaométodo__lt__quedefinimosparadeterminaraordem.

18.7-Herança

Page 258: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

A herança é a capacidade de definir uma nova classe que seja uma versãomodificadadeumaclasseexistente.Comoexemplo,digamosquequeremosqueuma classe represente uma “mão”, isto é, as cartasmantidas por um jogador.Umamãoésemelhanteaumbaralho:ambossãocompostosporumacoleçãodecartas,eambosexigemoperaçõescomoadicionareremovercartas.

Umamãotambémédiferentedeumbaralho;háoperaçõesquequeremosparamãos que não fazem sentido para um baralho. Por exemplo, no pôquerpoderíamos comparar duasmãos para ver qual ganha. No bridge, poderíamoscalcularapontuaçãodeumamãoparafazerumaaposta.

Essa relação entre classes – semelhante,mas diferente – adequa-se à herança.Para definir uma nova classe que herda algo de uma classe existente, bastacolocaronomedaclasseexistenteentreparênteses:

classHand(Deck):

"""Representsahandofplayingcards."""

EstadefiniçãoindicaqueHandherdadeDeck;issosignificaquepodemosusarmétodoscomopop_cardeadd_cardparaHandbemcomoparaDeck.

Quandoumanovaclasseherdadeumaexistente, aexistentechama-sepaieanovaclassechama-sefilho.

Nesteexemplo,Handherda__init__deDeck,masnaverdadenão fazoquequeremos: emvezdepreencher amão com52 cartas novas, ométodo init deHanddeveinicializarcardcomumalistavazia.

SefornecermosummétodoinitnaclasseHand,eleignoraodaclasseDeck:

#dentrodaclasseHand:

def__init__(self,label=''):

self.cards=[]

self.label=label

AocriarHand,oPythoninvocaestemétodoinit,nãoodeDeck.

>>>hand=Hand('newhand')

>>>hand.cards

[]

>>>hand.label

Page 259: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

'newhand'

Outros métodos são herdados de Deck, portanto podemos usar pop_card eadd_cardparalidarcomumacarta:

>>>deck=Deck()

>>>card=deck.pop_card()

>>>hand.add_card(card)

>>>print(hand)

KingofSpades

Umpróximopassonaturalseriaencapsularestecódigoemummétodochamadomove_cards:

#dentrodaclasseDeck:

defmove_cards(self,hand,num):

foriinrange(num):

hand.add_card(self.pop_card())

move_cardsrecebedoisargumentos,umobjetoHandeonúmerodecartascomquevailidar.ElealteratantoselfcomohanderetornaNone.

Emalgunsjogos,ascartassãomovidasdeumamãoaoutra,oudeumamãodevolta ao baralho. É possível usar move_cards para algumas dessas operações:selfpodeserumDeckouHand,ehand,apesardonome,tambémpodeserumDeck.

Aherançaéumrecursoútil.Algunsprogramasquepoderiamserrepetitivossemherança podem ser escritos de formamais elegante com ela. A herança podefacilitar a reutilização de código, já que você pode personalizar ocomportamento de classes pais sem ter que alterá-las. Em alguns casos, aestruturadeherançarefleteaestruturanaturaldoproblema,oquetornaoprojetomaisfácildeentender.

Deoutro lado,aherançapode tornarosprogramasdifíceisde ler.Quandoummétodo é invocado, às vezes não está claro onde encontrar sua definição. Ocódigorelevantepodeserespalhadoporváriosmódulos.Alémdisso,muitasdascoisas que podem ser feitas usando a herança podem ser feitas sem elas, àsvezes,atédeformamelhor.

Page 260: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

18.8-Diagramasdeclasse

Porenquantovimosdiagramasdepilha,quemostramoestadodeumprogramaediagramasde objeto, quemostramos atributos de umobjeto e seus valores.Esses diagramas representam um retrato da execução de um programa, entãoelesmudamnodecorrerdaexecuçãodoprograma.

Eles também são altamente detalhados; para alguns objetivos, detalhadosdemais.Umdiagramadeclasseéumarepresentaçãomaisabstratadaestruturadeumprograma.Emvezdemostrarobjetosindividuais,elemostraclasseseasrelaçõesentreelas.

Háváriostiposderelaçõesentreasclasses:

Os objetos de uma classe podem conter referências a objetos em outraclasse.Porexemplo,cadaRectanglecontémumareferênciaaumPoint,ecadaDeckcontémreferênciasamuitosCards.Essetipoderelaçãochama-se composição. É uma relação do tipoHAS-A (tem um), com a ideia de“umRectangletemumPoint”.

Umaclassepodeherdardeoutra.Estarelaçãochama-seIS-A(éum),comaideiade“umHandéumtipodeDeck”.

Umaclassepodedependerdeoutranosentidodequeosobjetosemumaclassepossamreceberobjetosnasegundaclassecomoparâmetrosouusaresses objetos como parte de um cálculo. Este tipo de relação chama-sedependência.

Um diagrama de classe é uma representação gráfica dessas relações. Porexemplo,aFigura18.2mostraasrelaçõesentreCard,DeckeHand.

Figura18.2–Diagramadeclasses.

Page 261: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

AflechacomumtriânguloocorepresentaumarelaçãoIS-A;nessecaso,indicaqueHandherdadeDeck.

ApontadeflechapadrãorepresentaumarelaçãoHAS-A;nessecaso,umDecktemreferênciasaobjetosCard.

A estrela __*__ perto da ponta de flecha indica a multiplicidade; ela indicaquantosCardsumDecktem.Umamultiplicidadepodeserumnúmerosimplescomo52,umintervalocomo5..7ouumaestrela,queindicaqueumDeckpodeterqualquernúmerodeCards.

Não há nenhuma dependência neste diagrama. Elas normalmente apareceriamcomumaflechatracejada.Ou,sehouvermuitasdependências,àsvezeselassãoomitidas.

UmdiagramamaisdetalhadopoderiamostrarqueumDecknaverdadecontémuma lista de Cards, mas os tipos integrados como lista e dict não sãonormalmenteincluídosemdiagramasdeclasse.

18.9-Encapsulamentodedados

Os capítulos anteriores demonstram um plano de desenvolvimento quepoderíamoschamarde“projetoorientadoaobjeto”.Identificamososobjetosdeque precisamos – como Point, Rectangle e Time – e definimos classes pararepresentá-los. Em cada caso há uma correspondência óbvia entre o objeto ealgumaentidadenomundoreal(ou,pelomenos,nomundomatemático).

Mas, às vezes, émenos óbvio quais objetos você precisa e como eles deveminteragir.Nesse caso é necessário um plano de desenvolvimento diferente.Damesma forma emquedescobrimos interfaces de funçãopor encapsulamento egeneralização, podemos descobrir interfaces de classe por encapsulamento dedados.

AanálisedeMarkov,de“AnálisedeMarkov”,napágina200,apresentaumbomexemplo.Sebaixaromeucódigoemhttp://thinkpython2.com/code/markov.py,vocêvaiverqueeleusaduasvariáveisglobais–suffix_mapeprefix–quesãolidaseescritasapartirdeváriasfunções.

suffix_map={}

Page 262: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

prefix=()

Comoessasvariáveissãoglobais,sópodemosexecutarumaanálisedecadavez.Se lermosdois textos,seusprefixosesufixosseriamacrescentadosàsmesmasestruturasdedados(oquegerariatextosinteressantes).

Para executar análises múltiplas e guardá-las separadamente, podemosencapsularoestadodecadaanáliseemumobjeto.Éassimquefica:

classMarkov:

def__init__(self):

self.suffix_map={}

self.prefix=()

Em seguida, transformamos as funções em métodos. Por exemplo, aqui estáprocess_word:

defprocess_word(self,word,order=2):

iflen(self.prefix)<order:

self.prefix+=(word,)

return

try:

self.suffix_map[self.prefix].append(word)

exceptKeyError:

#senãohouverentradasdesteprefixo,crieuma.

self.suffix_map[self.prefix]=[word]

self.prefix=shift(self.prefix,word)

Transformar um programa como esse – alterando o projeto sem mudar ocomportamento–éoutroexemploderefatoração(veja“Refatoração”,napágina70).

Este exemplo sugere um plano de desenvolvimento para projetar objetos emétodos:

1. Comece escrevendo funções que leiam e criemvariáveis globais (quandonecessário).

2. Uma vez que o programa esteja funcionando, procure associações entrevariáveisglobaisefunçõesqueasusem.

3. Encapsulevariáveisrelacionadascomoatributosdeobjeto.

Page 263: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

4. Transformeasfunçõesassociadasemmétodosdanovaclasse.

Como exercício, baixe o meu código de Markov dehttp://thinkpython2.com/code/markov.py e siga os passos descritos acima paraencapsular as variáveis globais como atributos de uma nova classe chamadaMarkov.

Solução:http://thinkpython2.com/code/Markov.py(observeoMmaiúsculo).

18.10-Depuração

Aherançapodedificultar adepuraçãoporquequandovocê invocaummétodoemumobjeto,podeserdifícilcompreenderqualmétodoseráinvocado.

Suponha que esteja escrevendo uma função que funcione com objetos Hand.Você gostaria que ela funcionasse com todos os tipos de Hand, comoPokerHands, BridgeHands etc. Se invocar um método como shuffle, poderáreceberoquefoidefinidoemDeck,massealgumadassubclassesignorarestemétodo, você receberá outra versão. Este comportamento pode ser bom, mastambémconfuso.

Aqualquermomentoemquenãoestejaseguroarespeitodofluxodeexecuçãodoseuprograma,asoluçãomaissimpleséacrescentarinstruçõesdeexibiçãonoiníciodosmétodosemquestão.SeDeck.shuffleexibirumamensagemquedizalgo comoRunningDeck.shuffle, entãonodecorrer da execuçãodoprogramaelemonitoraseufluxo.

Umaalternativaéusarestafunção,querecebeumobjetoeumnomedemétodo(comoumastring)eretornaaclassequeforneceadefiniçãodométodo:

deffind_defining_class(obj,meth_name):

fortyintype(obj).mro():

ifmeth_nameinty.__dict__:

returnty

Aquiestáumexemplo:

>>>hand=Hand()

>>>find_defining_class(hand,'shuffle')

<class'Card.Deck'>

Page 264: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

EntãoométodoshuffledesteHandéodeDeck.

find_defining_classusaométodomroparaobteralistadeobjetosdeclasse(tipos) onde os métodos serão procurados. “MRO” significa “ordem deresoluçãodométodo”,queéasequênciadeclassesqueoPythonpesquisapara“descobrir”umnomedemétodo.

Aquiestáumasugestãodeprojeto:quandovocêignoraummétodo,ainterfacedonovométododeveseramesmaqueadoantigo.Eladevereceberosmesmosparâmetros, retornar omesmo tipo e obedecer àsmesmasprecondições e pós-condições.Seseguiresta regra,vocêdescobriráquequalquer funçãoprojetadapara funcionar com uma instância de uma classe pai, como Deck, tambémfuncionarácominstânciasdeclassesfilhocomoHandePokerHand.

Seviolar esta regra,oque sechamade“princípiode substituiçãodeLiskov”,seucódigocairácomo(desculpe)umcastelodecartas.

18.11-Glossário

codificarRepresentar um conjunto de valores usando outro conjunto de valoresconstruindoummapeamentoentreeles.

atributodeclasseAtributo associado a um objeto de classe. Os atributos de classe sãodefinidosdentrodeumadefiniçãodeclasse,masforadequalquermétodo.

atributodeinstânciaAtributoassociadoaumainstânciadeumaclasse.

folheadoMétodooufunçãoqueapresentaumainterfacediferenteparaoutrafunçãosemfazermuitoscálculos.

herançaCapacidadededefinirumanovaclassequesejaumaversãomodificadadeumaclassedefinidaanteriormente.

classe-paiClassedaqualumaclasse-filhoherda.

classe-filhoNovaclassecriadaporherançadeumaclasseexistente; tambémchamadade“subclasse”.

relaçãoIS-A

Page 265: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Relação entre uma classe-filho e sua classe-pai. Também chamada deherança.

relaçãoHAS-ARelação entre duas classes onde as instâncias de uma classe contêmreferênciasainstânciasdaoutra.Tambémchamadadecomposição.

dependênciaRelaçãoentreduasclassesondeasinstânciasdeumaclasseusaminstânciasdeoutraclasse,masnãoasguardamcomoatributos.

diagramadeclasseDiagramaquemostraasclassesemumprogramaeasrelaçõesentreelas.

multiplicidadeNotaçãoemumdiagramadeclassequemostra,paraumarelaçãoHAS-A,quantasreferênciasainstânciasdaoutraclassepodemexistir.

encapsulamentodedadosPlanodedesenvolvimentodeprogramaqueenvolveumprotótipousandovariáveisglobaiseumaversãofinalquetransformaasvariáveisglobaisematributosdeinstância.

18.12-Exercícios

Exercício18.1

Para o seguinte programa, desenhe um diagrama de classe UML que mostreestasclasseseasrelaçõesentreelas.

classPingPongParent:

pass

classPing(PingPongParent):

def__init__(self,pong):

self.pong=pong

classPong(PingPongParent):

def__init__(self,pings=None):

ifpingsisNone:

self.pings=[]

else:

self.pings=pings

defadd_ping(self,ping):

self.pings.append(ping)

Page 266: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

pong=Pong()

ping=Ping(pong)

pong.add_ping(ping)

Exercício18.2

EscrevaummétodoDeckchamadodeal_handsque recebadoisparâmetros:onúmero de mãos e o número de cartas por mão. Ele deve criar o númeroadequadodeobjetosHand, lidarcomonúmeroadequadodecartaspormãoeretornarumalistadeHands.

Exercício18.3

A seguir, asmãos possíveis no pôquer, em ordem crescente de valor e ordemdecrescentedeprobabilidade:

parDuascartascomomesmovalor.

doisparesDoisparesdecartascomomesmovalor.

trincaTrêscartascomomesmovalor.

sequênciaCincocartascomvaloresemsequência(osasespodemseraltosoubaixos,entãoAce-2-3-4-5éumasequência,assimcomo10-Jack-Queen-King-Ace,masQueen-King-Ace-2-3nãoé.)

flushCincocartascomomesmonaipe.

fullhouseTrêscartascomumvalor,duascartascomoutro.

quadraQuatrocartascomomesmovalor.

straightflushCincocartasemsequência(comodefinidoacima)ecomomesmonaipe.

Ametadessesexercícioséestimaraprobabilidadedeterestasváriasmãos.

1. Baixeosseguintesarquivosdehttp://thinkpython2.com/code:

Page 267: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Card.py:VersãocompletadasclassesCard,DeckeHanddestecapítulo.

PokerHand.py: Uma implementação incompleta de uma classe querepresentaumamãodepôquerecódigoparatestá-la.

2. SeexecutarPokerHand.py,vocêveráqueoprogramacriamãosdepôquercom7cartaseverificasealgumadelascontémumflush.Leiaestecódigocomatençãoantesdecontinuar.

3. Acrescente métodos a PokerHand.py chamados has_pair, has_twopair,etc. que retornemTrue ou False conforme amão cumpra os critérios emquestão. Seu código deve funcionar corretamente para “mãos” quecontenhamqualquernúmerodecartas(embora5e7sejamasquantidadesmaiscomuns).

4. Escrevaummétodochamadoclassifyquedescubraaclassificaçãodovalormais alto para uma mão e estabeleça o atributo label em questão. Porexemplo,umamãode7cartaspoderiaconterumflusheumpar;eladevesermarcadacomo“flush”.

5. Quando se convencer de que os seus métodos de classificação estãofuncionando,opróximopassodeveserestimarasprobabilidadesdeváriasmãos.EscrevaumafunçãoemPokerHand.pyqueembaralhecartas,divida-asemmãos,classifiqueasmãoseconteonúmerodevezesemqueváriasclassificaçõesaparecem.

6. Exiba uma tabela das classificações e suas probabilidades. Execute seuprograma com números cada vezmaiores demãos até que os valores desaídaconvirjamaumgraurazoáveldeexatidão.Compareseusresultadoscomosvaloresemhttp://en.wikipedia.org/wiki/Hand_rankings.

Solução:http://thinkpython2.com/code/PokerHandSoln.py.

Page 268: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Capítulo19:ExtraUmadasminhasmetascomeste livroéensinaromínimopossíveldePython.Quando havia duas formas de fazer algo, escolhia uma e evitavamencionar aoutra.Ou,àsvezes,usavaasegundacomoexercício.

Agora quero voltar a algumas coisas boas que ficaram para trás. O Pythonofereceváriosrecursosquenãosãorealmentenecessários–vocêpodeescreverumbomcódigo semeles–mas comeles épossível escreverumcódigomaisconciso,legíveloueficientee,àsvezes,todosostrês.

19.1-Expressõescondicionais

Vimos instruções condicionais em “Execução condicional”, na página 78. Asinstruções condicionais muitas vezes são usadas para escolher um entre doisvalores;porexemplo:

ifx>0:

y=math.log(x)

else:

y=float('nan')

Esta instrução verifica se x é positivo. Nesse caso, ela calcula math.log. Docontrário,math.logcausariaumValueError.Paraevitarinterromperoprograma,geramosum“NaN”,queéumvalordepontoflutuanteespecialquerepresentaum“Nãonúmero”.

Podemosescreveressa instruçãodeformamaisconcisausandoumaexpressãocondicional:

y=math.log(x)ifx>0elsefloat('nan')

Vocêquasepodelerestalinhacomosetivessesidoescritaeminglês:“yrecebelog-xsexformaiorque0;docontrário,elerecebeNaN”.

As funções recursivas por vezes podem ser reescritas usando expressõescondicionais.Porexemplo,aquiestáumaversãorecursivadefactorial:

Page 269: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

deffactorial(n):

ifn==0:

return1

else:

returnn*factorial(n-1)

Podemosreescrevê-laassim:

deffactorial(n):

return1ifn==0elsen*factorial(n-1)

Outro uso de expressões condicionais é lidar com argumentos opcionais. Porexemplo,aquiestáométodoinitdeGoodKangaroo(vejaoExercício17.2):

def__init__(self,name,contents=None):

self.name=name

ifcontents==None:

contents=[]

self.pouch_contents=contents

Podemosreescrevê-loassim:

def__init__(self,name,contents=None):

self.name=name

self.pouch_contents=[]ifcontents==Noneelsecontents

Em geral, é possível substituir uma instrução condicional por uma expressãocondicional se ambos os ramos contiverem expressões simples que sejamretornadasouatribuídasàmesmavariável.

19.2-Abrangênciadelistas

Em “Mapeamento, filtragem e redução”, na página 147, vimos os padrões defiltragem emapeamento. Por exemplo, esta função toma uma lista de strings,mapeiaométododestringcapitalizeaoselementos,eretornaumanovalistadestrings:

defcapitalize_all(t):

res=[]

forsint:

res.append(s.capitalize())

returnres

Page 270: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Podemosescreverissodeformamaisconcisausandoabrangênciadelistas(listcomprehension):

defcapitalize_all(t):

return[s.capitalize()forsint]

Osoperadoresdecolchete indicamqueestamosconstruindoumanovalista.Aexpressãodentrodoscolchetesespecificaoselementosdalista,eacláusulaforindicaqualsequênciaestamosatravessando.

A sintaxe da abrangência de listas é um pouco esquisita porque a variável deloop,snesseexemplo,aparecenaexpressãoantesdechegarmosàdefinição.

Abrangênciasde listas tambémpodemserusadaspara filtragem.Porexemplo,esta função só selecionaos elementos de t que sãomaiúsculos, e retornaumanovalista:

defonly_upper(t):

res=[]

forsint:

ifs.isupper():

res.append(s)

returnres

Podemosreescrevê-lausandoabrangênciadelistas:

defonly_upper(t):

return[sforsintifs.isupper()]

Abrangênciasdelistassãoconcisasefáceisdeler,pelomenosparaexpressõessimples.Esãonormalmentemaisrápidasqueosloopsforequivalentes,àsvezesmuitomaisrápidas.Então,sevocêficarirritadocomigopornãotermencionadoissoantes,euentendo.

Porém,emminhadefesa,asabrangênciasdelistassãomaisdifíceisdedepurarporquenãoépossívelterinstruçõesdeexibiçãodentrodoloop.Sugiroquevocêasusesóseocálculoforsimplesosuficienteparaqueacertejádeprimeira.Eparaprincipiantesissosignificanunca.

19.3-Expressõesgeradoras

Page 271: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Expressões geradoras são semelhantes às abrangências de listas, mas comparêntesesemvezdecolchetes:

>>>g=(x**2forxinrange(5))

>>>g

<generatorobject<genexpr>at0x7f4c45a786c0>

O resultado é um objeto gerador que sabe como fazer iterações por umasequênciadevalores.Noentanto,aocontráriodeumaabrangênciadelistas,elenãocalculatodososvaloresdeumavez;esperapelopedido.Afunçãointegradanextrecebeopróximovalordogerador:

>>>next(g)

0

>>>next(g)

1

Quandovocêchegano fimdasequência,nextcriaumaexceçãoStopIteration.Tambémépossívelusarumloopforparafazeraiteraçãopelosvalores:

>>>forvaling:

...print(val)

4

9

16

Oobjetogeradormonitoraaposiçãoemqueestánasequência,portantooloopforcontinuadeondenextparou.Umavezqueogeradorseesgotar,elecontinuacriandoStopException:

>>>next(g)

StopIteration

Asexpressõesgeradorasmuitasvezessãousadascomfunçõescomosum,maxemin:

>>>sum(x**2forxinrange(5))

30

19.4-anyeall

OPythontemumafunçãointegrada,any,querecebeumasequênciadevalores

Page 272: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

booleanoseretornaTruesealgumdosvaloresforTrue.Elafuncionaemlistas:

>>>any([False,False,True])

True

Entretanto,muitasvezeséusadacomexpressõesgeradoras:

>>>any(letter=='t'forletterin'monty')

True

Esse exemplo não émuito útil porque faz amesma coisa que o operador in.Porém,podemosusaranyparareescreveralgumasdasfunçõesdepesquisaqueescrevemos em “Busca”, na página 136. Por exemplo, poderíamos escreveravoidsdessaforma:

defavoids(word,forbidden):

returnnotany(letterinforbiddenforletterinword)

Afunçãoquasepodeserlidacomoumafraseeminglês:“wordevitaforbiddensenãohouvernenhumaletraproibidaemword”.

Usar any com uma expressão geradora é eficiente porque ela retornaimediatamente se encontrar um valor True, então não é preciso avaliar asequênciainteira.

O Python oferece outra função integrada, all, que retorna True se todos oselementos da sequência forem True. Como exercício, use all para reescreveruses_allde“Busca”,napágina136.

19.5-Conjuntos

Na seção “Subtração de dicionário”, da página 198, uso dicionários paraencontraraspalavrasqueaparecememumdocumento,masnãonumalistadepalavras.Afunçãoqueescrevirecebed1,quecontémaspalavrasdodocumentocomochavesed2,quecontémalistadepalavras.Elaretornaumdicionárioquecontémaschavesded1quenãoestãoemd2:

defsubtract(d1,d2):

res=dict()

forkeyind1:

ifkeynotind2:

Page 273: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

res[key]=None

returnres

Emtodosessesdicionários,osvaloresnãosãoNoneporquenuncaosusamos.Oresultadoéquedesperdiçamosespaçodearmazenamento.

OPythonforneceoutrotipointegrado,chamadoset(conjunto),quesecomportacomoumacoleçãodechavesdedicionáriosemvalores.Acrescentarelementosaumconjuntoérápido;assimcomoverificaraadesão.Eosconjuntosfornecemmétodoseoperadoresparacalcularoperaçõesdeconjuntos.

Por exemplo, a subtração de conjuntos está disponível como um métodochamado difference ou como um operador, -. Portanto, podemos reescreversubtractdestaforma:

defsubtract(d1,d2):

returnset(d1)-set(d2)

Oresultadoéumconjuntoemvezdeumdicionário,mas,paraoperaçõescomoiteração,ocomportamentoéomesmo.

Algunsexercíciosnestelivropodemserfeitosdeformaconcisaeeficientecomconjuntos.Porexemplo,aquiestáumasoluçãoparahas_duplicates,doExercício10.7,queusaumdicionário:

defhas_duplicates(t):

d={}

forxint:

ifxind:

returnTrue

d[x]=True

returnFalse

Quando um elemento aparece pela primeira vez, ele é acrescentado aodicionário.Seomesmoelementoaparecenovamente,afunçãoretornaTrue.

Usandoconjuntos,podemosescreveramesmafunçãodessaforma:

defhas_duplicates(t):

returnlen(set(t))<len(t)

Um elemento só pode aparecer em um conjunto uma vez, portanto, se um

Page 274: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

elementoemtaparecermaisdeumavez,oconjuntoserámenorquet.Senãohouverduplicatas,oconjuntoteráomesmotamanhoquet.

TambémpodemosusarconjuntosparafazeralgunsexercíciosnoCapítulo9.Porexemplo,aquiestáumaversãodeuses_onlycomumloop:

defuses_only(word,available):

forletterinword:

ifletternotinavailable:

returnFalse

returnTrue

uses_only verifica se todas as cartas em word estão em available. Podemosreescrevê-laassim:

defuses_only(word,available):

returnset(word)<=set(available)

Ooperador<=verificaseumconjuntoéumsubconjuntoououtro, incluindoapossibilidade de que sejam iguais, o que é verdade se todas as letras dewordaparecerememavailable.

Comoexercício,reescrevaavoidsusandoconjuntos.

19.6-Contadores

Umcontadorécomoumconjunto,excetoqueseumelementoaparecermaisdeumavez, o contador registra quantas vezes ele aparece. Se tiver familiaridadecom a ideia matemática de um multiconjunto (multiset), um contador é umaformanaturalderepresentarummulticonjunto.

Contadores são definidos em um módulo padrão chamado collections,portanto é preciso importá-lo. Você pode inicializar um contador com umastring,listaoualgumaoutracoisaquesejacompatívelcomiteração:

>>>fromcollectionsimportCounter

>>>count=Counter('parrot')

>>>count

Counter({'r':2,'t':1,'o':1,'p':1,'a':1})

Oscontadorescomportam-secomodicionáriosdemuitasformas;elesmapeiam

Page 275: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

cada chave aonúmerodevezes que aparece.Comoemdicionários, as chavestêmdeserhashable.

Ao contrário de dicionários, os contadores não causam uma exceção se vocêacessarumelementoquenãoaparece.Emvezdisso,retornam0:

>>>count['d']

0

Podemosusarcontadoresparareescreveris_anagramdoExercício10.6:

defis_anagram(word1,word2):

returnCounter(word1)==Counter(word2)

Se duas palavras forem anagramas, elas contêm as mesmas letras com asmesmascontagens,entãoseuscontadoressãoequivalentes.

Oscontadoresoferecemmétodoseoperadoresparaexecutaroperaçõessimilaresàs dos conjuntos, incluindo adição, subtração, união e intersecção. E elesfornecemummétodomuitasvezesútil,most_common,queretornaumalistadeparesfrequência-valor,organizadosdomaisaomenoscomum:

>>>count=Counter('parrot')

>>>forval,freqincount.most_common(3):

...print(val,freq)

r2

p1

a1

19.7-defaultdict

O módulo collections também tem defaultdict, que se parece com umdicionário,excetopelofatodequesevocêacessarumachavequenãoexiste,umnovovalorpodesergeradoautomaticamente.

Quandovocêcriaumdefaultdict,forneceumafunçãousadaparacriarvalores.Umafunçãousadaparacriarobjetosàsvezeséchamadadefactory(fábrica).Asfunções integradasquecriam listas,conjuntoseoutros tipospodemserusadascomofábricas:

>>>fromcollectionsimportdefaultdict

Page 276: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

>>>d=defaultdict(list)

Notequeo argumento é list, que é umobjetode classe, não list(), que é umanovalista.Afunçãoquevocêfornecenãoéchamadaamenosquevocêacesseumachavequenãoexiste:

>>>t=d['newkey']

>>>t

[]

Anova lista, que estamos chamandode t, tambémé adicionada aodicionário.Então,sealterarmost,amudançaapareceemd:

>>>t.append('newvalue')

>>>d

defaultdict(<class'list'>,{'newkey':['newvalue']})

Seestiverfazendoumdicionáriodelistas,vocêpodeescreverumcódigomaissimplesusandodefaultdict.NaminhasoluçãoparaoExercício12.2,quevocêpodeveremhttp://thinkpython2.com/code/anagram_sets.py,façoumdicionárioquemapeiaumastringorganizadadeletrasaumalistadepalavrasquepodesersoletrada com essas letras. Por exemplo, 'opst' mapeia para a lista ['opts','post','pots','spot','stop','tops'].

Aquiestáocódigooriginal:

defall_anagrams(filename):

d={}

forlineinopen(filename):

word=line.strip().lower()

t=signature(word)

iftnotind:

d[t]=[word]

else:

d[t].append(word)

returnd

Isso pode ser simplificado usando setdefault, que você poderia ter usado noExercício11.2:

defall_anagrams(filename):

d={}

forlineinopen(filename):

Page 277: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

word=line.strip().lower()

t=signature(word)

d.setdefault(t,[]).append(word)

returnd

Oproblemadessasoluçãoéqueelafazumalistanovaacadavez,mesmoquenãosejanecessário.Paralistas,issonãoégrandecoisa,masseafunçãofábricaforcomplicada,poderiaser.

Podemosevitaresteproblemaesimplificarocódigousandoumdefaultdict:

defall_anagrams(filename):

d=defaultdict(list)

forlineinopen(filename):

word=line.strip().lower()

t=signature(word)

d[t].append(word)

returnd

A minha solução para o Exercício 18.3, que você pode baixar emhttp://thinkpython2.com/code/PokerHandSoln.py, usa setdefault na funçãohas_straightflush.OproblemadessasoluçãoécriarumobjetoHandcadavezque passa pelo loop, seja ele necessário ou não. Como exercício, reescreva-ausandoumdefaultdict.

19.8-Tuplasnomeadas

Muitos objetos simples são basicamente coleções de valores relacionados. Porexemplo,oobjetoPoint,definidonoCapítulo15,contémdoisnúmeros,xey.Aodefinir uma classe como essa, normalmente você começa comummétodoiniteummétodostr:

classPoint:

def__init__(self,x=0,y=0):

self.x=x

self.y=y

def__str__(self):

return'(%g,%g)'%(self.x,self.y)

É muito código para transmitir pouca informação. O Python tem uma formamaisconcisadedizeramesmacoisa:

Page 278: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

fromcollectionsimportnamedtuple

Point=namedtuple('Point',['x','y'])

Oprimeiroargumentoéonomedaclassequevocêquercriar.OsegundoéumalistadosatributosqueoobjetoPointdeveter,comostrings.Ovalorderetornodenamedtupleéumobjetodeclasse:

>>>Point

<class'__main__.Point'>

Pointforneceautomaticamentemétodoscomo__init__e__str__entãonãoéprecisoescrevê-los.

ParacriarumobjetoPoint,vocêusaaclassePointcomoumafunção:

>>>p=Point(1,2)

>>>p

Point(x=1,y=2)

Ométodo__init__atribuiosargumentosaatributosusandoosnomesquevocêforneceu.Ométodo __str__ exibe uma representação do objeto Point e seusatributos.

Vocêpodeacessaroselementosdatuplanomeadapelonome:

>>>p.x,p.y

(1,2)

Mastambémpodetratarumatuplanomeadacomoumatupla:

>>>p[0],p[1]

(1,2)

>>>x,y=p

>>>x,y

(1,2)

Tuplas nomeadas fornecem uma forma rápida de definir classes simples. Oproblema é que classes simples não ficam sempre simples.Mais adiante vocêpoderádecidirquequeracrescentarmétodosaumatuplanomeada.Nessecaso,vocêpoderádefinirumanovaclassequeherdedatuplanomeada:

classPointier(Point):

#adicionarmaismétodosaqui

Page 279: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Oupoderámudarparaumadefiniçãodeclasseconvencional.

19.9-Reunindoargumentosdepalavra-chave

Em“Tuplascomargumentosdecomprimentovariável”,napágina181,vimoscomoescreverumafunçãoquereúneseusargumentosemumatupla:

defprintall(*args):

print(args)

Vocêpodechamarestafunçãocomqualquernúmerodeargumentosposicionais(istoé,argumentosquenãotêmpalavras-chave):

>>>printall(1,2.0,'3')

(1,2.0,'3')

Porém,ooperador*nãoreúneargumentosdepalavra-chave:

>>>printall(1,2.0,third='3')

TypeError:printall()gotanunexpectedkeywordargument'third'

Parareunirargumentosdepalavra-chave,vocêpodeusarooperador**:

defprintall(*args,**kwargs):

print(args,kwargs)

Você pode chamar o parâmetro de coleta de palavra-chave, como quiser,maskwargséumaescolhacomum.Oresultadoéumdicionárioquemapeiapalavras-chaveavalores:

>>>printall(1,2.0,third='3')

(1,2.0){'third':'3'}

Se tiver um dicionário de palavras-chave e valores, pode usar o operador dedispersão,**,parachamarumafunção:

>>>d=dict(x=1,y=2)

>>>Point(**d)

Point(x=1,y=2)

Sem o operador de dispersão, a função trataria d como um único argumentoposicional, e então atribuiria d a x e se queixaria porque não há nada para

Page 280: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

atribuiray:

>>>d=dict(x=1,y=2)

>>>Point(d)

Traceback(mostrecentcalllast):

File"<stdin>",line1,in<module>

TypeError:__new__()missing1requiredpositionalargument:'y'

Quandoestivertrabalhandocomfunçõescomumgrandenúmerodeparâmetros,muitas vezes é útil criar dicionários e passá-los como argumentos paraespecificarasopçõesusadascommaiorfrequência.

19.10-Glossário

expressãocondicionalExpressãoquecontémumdedoisvalores,dependendodeumacondição.

abrangênciadelista(listcomprehension)Expressãocomumloopforentrecolchetesqueproduzumanovalista.

expressãogeradoraUma expressão com um loop for entre parênteses que produz um objetogerador.

multiconjuntoEntidadematemáticaquerepresentaummapeamentoentreoselementosdeumconjuntoeonúmerodevezesqueaparecem.

fábrica(factory)Funçãonormalmentepassadacomoparâmetro,usadaparacriarobjetos.

19.11-Exercícios

Exercício19.1

Estaéumafunçãoquecalculaocoeficientebinominalrecursivamente:

defbinomial_coeff(n,k):

"""Computethebinomialcoefficient"nchoosek".

n:numberoftrials

k:numberofsuccesses

returns:int

Page 281: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

"""

ifk==0:

return1

ifn==0:

return0

res=binomial_coeff(n-1,k)+binomial_coeff(n-1,k-1)

returnres

Reescrevaocorpodafunçãousandoexpressõescondicionaisaninhadas.

Umaobservação:estafunçãonãoémuitoeficienteporqueacabacalculandoosmesmos valores várias vezes. Você pode torná-lo mais eficiente com memos(veja “Memos”, na página 169). No entanto, vai ver que é mais difícil usarmemosseescrevê-lausandoexpressõescondicionais.

Page 282: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ApêndiceA:DepuraçãoDurante a depuração, você deve distinguir entre tipos diferentes de erros pararastreá-losmaisrapidamente:

Erros de sintaxe são descobertos pelo interpretador quando ele estátraduzindoocódigo-fonteparacódigodebytes.Eles indicamqueháalgoerradocomaestruturadoprograma.Exemplo:aomissãodosdoispontosno fim de uma instrução def gera a mensagem um tanto redundanteSyntaxError:invalidsyntax.

Errosdetempodeexecuçãosãoproduzidospelointerpretadorsealgodererradoduranteaexecuçãodoprograma.Amaiorpartedasmensagensdeerrodetempodeexecuçãoincluiinformaçõessobreondeoerroocorreueoque as funções estavam fazendo. Exemplo: a recursividade infinitaeventualmente leva ao erro de tempo de execução maximum recursiondepthexceeded.

Erros semânticos são problemas com um programa que é executado semproduzirmensagensdeerro,masquenãofazacoisacerta.Exemplo:umaexpressão que não pode ser avaliada na ordem esperada, produzindo umresultadoincorreto.

Oprimeiropassodadepuraçãoécompreendercomque tipodeerrovocêestálidando. Embora as próximas seções sejam organizadas pelo tipo de erro,algumastécnicassãoaplicáveisemmaisdeumasituação.

A.1-Errosdesintaxe

Os erros de sintaxe normalmente são fáceis de corrigir, uma vez que vocêdescubra quais são. Infelizmente, asmensagens de erromuitas vezes não sãoúteis. As mensagens mais comuns são SyntaxError: invalid syntax eSyntaxError:invalidtoken,enenhumadasduasémuitoinformativa.

Por outro lado, amensagemdiz ondenoprogramaoproblemaocorreu.E, naverdade, diz a você onde o Python notou um problema, que é não

Page 283: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

necessariamente onde o erro está. Às vezes, o erro está antes da posição damensagemdeerro,muitasvezesnalinhaprecedente.

Se estiver construindo o programa incrementalmente, você terá uma boa ideiasobreondeencontraroerro.Estaránaúltimalinhaqueacrescentou.

Seestivercopiandoocódigodeum livro,comececomparandocomatençãooseucódigoeodo livro.Verifiquecadacaractere.Aomesmotempo, lembre-sedequeolivropodeestarerrado,então,seviralgoquepareceumerrodesintaxe,podesermesmo.

Aquiestãoalgumasformasdeevitaroserrosdesintaxemaiscomuns:

1. Confirasenãoestáusandoumapalavra-chavedoPythonparaumnomedevariável.

2. Verifique se há dois pontos no fim do cabeçalho de cada instruçãocomposta,incluindoinstruçõesfor,while,ifedef.

3. Confiraseasstringsnocódigotêmasaspascorrespondentes.Verifiquesetodasasaspassãoretas,emvezdecurvas.

4. Se tiver strings com várias linhas com aspas triplas (simples ou duplas),confira se fechou a string adequadamente. Uma string não fechada podecausarumerrode invalid tokennofimdoseuprograma,oupodetrataraparte seguintedoprogramacomoumastringatéchegarà stringseguinte.Nosegundocaso,oprogramapodenemproduzirumamensagemdeerro!

5. Umoperadorinicialaberto–(,{ou[–fazoPythoncontinuaratéalinhaseguinte,comoseestafossepartedainstruçãoatual.Geralmente,umerroocorrequaseimediatamentenalinhaseguinte.

6. Confiraseháoclássico=emvezdo==dentrodeumacondicional.

7. Verifiqueaendentaçãoparatercertezadequeestáalinhadacomodeveria.O Python pode lidar com espaços e tabulações,mas, semisturá-los, issopodecausarproblemas.AmelhorformadeevitaresseproblemaéusarumeditordetextoqueidentifiqueoPythonegereendentaçãoconsistente.

8. Se há caracteres nãoASCII no código (incluindo strings e comentários),

Page 284: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

isso pode causar problemas, embora o Python 3 normalmente lide comcaracteresnãoASCII.Tenhacuidadosecolartextodeumapáginawebououtrafonte.

Senadafuncionar,váparaapróximaseção...

A.1.1-Continuofazendoalteraçõesenãofaznenhumadiferença

Seo interpretador disser que há umerro e você não o encontra, pode ser quevocê eo interpretadornão estejamolhandoparaomesmocódigo.Verifiqueoseu ambiente de programação para ter certeza de que o programa que estáeditandoéomesmoqueoPythonestátentandoexecutar.

Senãoestivercerto,tentepôrumerrodesintaxeóbvioedeliberadonoiníciodoprograma.Agoraexecute-onovamente.Seointerpretadornãoencontraronovoerro,vocênãoestáexecutandoonovocódigo.

Háalgunsculpadosprováveis:

Vocêeditouoarquivoeesqueceudesalvarasalteraçõesantesdeexecutá-lonovamente.Algunsambientesdeprogramação fazem issoparavocê,masalgunsnãofazem.

Vocêmudouonomedoarquivo,masaindaestáexecutandoonomeantigo.

Algonoseuambientededesenvolvimentoestáconfiguradoincorretamente.

Seestiverescrevendoummóduloeusando import, confira senãousouomesmonomenoseumóduloqueosdosmódulospadrãodoPython.

Se você estiver usando import para ler um módulo, lembre-se de que éprecisoreiniciarointerpretadorouusarreloadparalerumarquivoalterado.Seimportaromódulonovamente,elenãofaznada.

Se já esgotou as possibilidades e não conseguiu descobrir o que estáacontecendo, uma abordagem é começar novamente com um programa como“Hello, World!”, para ter certeza de que consegue executar um programaconhecido. Então, gradualmente acrescente as partes do programa original aonovo.

Page 285: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

A.2-Errosdetempodeexecução

Umavezqueoseuprogramaestejasintaticamentecorreto,oPythonpodelê-loe,pelomenos,começaraexecutá-lo.Oquepoderiadarerrado?

A.2.1-Meuprogramanãofaznada

Este problema émais comumquando o seu arquivo é composto de funções eclasses,masnaverdadenãoinvocaumafunçãoparacomeçaraexecução.Issopode ser intencional se você só planeja importar este módulo para fornecerclassesefunções.

Se não for intencional, tenha certeza de que há uma chamada de função noprograma, e que o fluxo de execução o alcança (veja “Fluxo da execução” aseguir).

A.2.2-Meuprogramatrava

Seumprogramaparareparecerquenãoestáfazendonada,eleestá“travado”.Muitasvezesissosignificaqueestápresoemumloopourecursãoinfinita.

Sehouverdeterminado loopquevocêsuspeitaseroproblema,acrescenteuma instrução print imediatamente antes do loop que diga “entrando noloop”,eoutraimediatamentedepoisquediga“saindodoloop”.

Execute o programa. Se receber a primeira mensagem e a segunda não,vocêtemumloopinfinito.Váàseção“Loopinfinito”maisadiante.

Namaiorpartedotempo,arecursividadeinfinitafarácomqueoprogramasejaexecutadodurantealgumtempoeentãogereumerro“RuntimeError:Maximum recursion depth exceeded”. Se isso acontecer, vá à seção“Recursividadeinfinita”maisadiante.

Senãoestiverrecebendoesteerro,massuspeitaqueháumproblemacomummétodooufunçãorecursiva,vocêaindapodeusarastécnicasdaseção“Recursividadeinfinita”.

Senenhumdessespassosfuncionar,comecea testaroutros loopseoutras

Page 286: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

funçõesemétodosrecursivos.

Se isso não funcionar, então é possível que você não entenda o fluxo deexecuçãodoseuprograma.Váàseção“Fluxodeexecução”maisadiante.

Loopinfinito

Sevocêachaqueháumloop infinitoe talvezsaibaqual loopestácausandooproblema, acrescenteuma instruçãoprint no fimdo loopque exibaosvaloresdasvariáveisnacondiçãoeovalordacondição.

Porexemplo:

whilex>0andy<0:

#fazalgocomx

#fazalgocomy

print('x:',x)

print('y:',y)

print("condition:",(x>0andy<0))

Agora,quandoexecutaroprograma,vocêverátrêslinhasdesaídaparacadavezqueoprogramapassarpeloloop.Naúltimavezquepassarpeloloop,acondiçãodeve ser False. Se o loop continuar, você poderá ver os valores de x e y, ecompreenderporquenãoestãosendoatualizadoscorretamente.

Recursividadeinfinita

Na maioria das vezes, a recursividade infinita faz o programa rodar durantealgumtempoeentãoproduzirumerrode"Maximumrecursiondepthexceeded".

Sesuspeitarqueumafunçãoestácausandorecursividadeinfinita,confiraseháumcaso-base.Devehaveralgumacondiçãoquefazafunçãoretornarsemfazeruma invocação recursiva. Do contrário, você terá que repensar o algoritmo eidentificarumcaso-base.

Sehouverumcaso-base,masoprogramanãoparecealcançá-lo,acrescenteumainstrução print no início da função para exibir os parâmetros. Agora, quandoexecutaroprograma,vocêveráalgumaslinhasdesaídacadavezqueafunçãoforinvocada,everáosvaloresdosparâmetros.Seosparâmetrosnãoestiveremsemovendo em direção ao caso-base, você terá algumas ideias sobre a razão

Page 287: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

disso.

Fluxodeexecução

Se não tiver certeza de como o fluxo de execução está semovendo pelo seuprograma, acrescente instruções print ao começo de cada função com umamensagemcomo“entradanafunçãofoo”,ondefooéonomedafunção.

Agora,quandoexecutaroprograma,eleexibirácadafunçãoqueforinvocada.

A.2.3-Quandoexecutooprogramareceboumaexceção

Sealgodererradoduranteotempodeexecução,oPythonexibeumamensagemqueincluionomedaexceção,alinhadoprogramaondeoproblemaocorreu,eumtraceback.

O traceback identificaa funçãoqueestá rodandoatualmente,ea funçãoqueachamou,assimcomoafunçãoquechamouesta,eassimpordiante.Emoutraspalavras, ele traça a sequência de chamadas de função que fez com que vocêchegasse onde está, incluindo o número da linha no seu arquivo onde cadachamadaocorreu.

Oprimeiropassoéexaminarolugarnoprogramaondeoerroocorreueverseconseguecompreenderoqueaconteceu.Essessãoalgunsdoserrosdetempodeexecuçãomaiscomuns:

NameError

Vocêestátentandousarumavariávelquenãoexistenoambienteatual.Confiraseonomeestáescritocorretamenteedeformaconsistente.Elembre-sedequeasvariáveislocaissãolocais;vocênãopodesereferiraelasapartirdoexteriordafunçãoondesãodefinidas.

TypeError

Háváriascausaspossíveis:

Vocêestá tentandousarumvalordeforma inadequada.Exemplo: indexar

Page 288: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

umastring,listaoutuplacomalgodiferentedeumnúmerointeiro.

Nãohá correspondência entre os itens emuma string de formatação e ositens passados para conversão. Isso pode acontecer se o número de itensnãotivercorrespondênciaouumaconversãoinválidaforchamada.

Vocêestápassandoonúmeroincorretodeargumentosaumafunção.Paramétodos, olhe para a definição do método e verifique se o primeiroparâmetro é self.Então olhe para a invocaçãodométodo; confira se estáinvocandoométodoaumobjetocomotipocorretoefornecendoosoutrosargumentoscorretamente.

KeyError

Vocêestátentandoacessarumelementodeumdicionáriousandoumachavequeo dicionário não contém. Se as chaves forem strings, lembre-se de que letrasmaiúsculassãodiferentesdeminúsculas.

AttributeError

Você está tentando acessar um atributo oumétodo que não existe.Verifique aortografia!Vocêpodeusar a função integradavars para listar os atributos queexistemmesmo.

Se um AttributeError indicar que um objeto é do tipo NoneType, ficasubentendidoqueéNone.Entãooproblemanãoéonomedoatributo,masoobjeto.

Podeserqueoobjetosejanoneporquevocêseesqueceuderetornarumvalordeumafunção;sechegaraofimdeumafunçãosemchegaraumainstruçãoreturn,elaretornaNone.Outracausacomuméusaroresultadodeummétododelista,comosort,queretorneNone.

IndexError

Oíndicequevocêestáusandoparaacessarumalista,stringoutuplaémaiorqueoseucomprimentomenosum.Imediatamenteantesdolocaldoerro,acrescenteumainstruçãoprintparaexibirovalordo índiceeocomprimentodoarray.O

Page 289: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

arrayédotamanhocerto?Oíndicetemovalorcerto?

O depurador do Python (pdb) é útil para rastrear exceções porque permiteexaminar o estado do programa imediatamente antes do erro. Você pode lersobreopdbemhttps://docs.python.org/3/library/pdb.html.

A.2.4-Acrescenteitantasinstruçõesprintquefuiinundadopelosresultados

Umdosproblemascomautilizaçãodeinstruçõesprintparaadepuraçãoéquevocê pode terminar enterrado pelos resultados.Há duas formas de prosseguir:simplifiqueasaídaousimplifiqueoprograma.

Parasimplificarasaída,vocêpoderetiraroutransformarasinstruçõesprintquenão estão ajudando emcomentários, ou combiná-las, ou formatar a saída paraquesejamaisfácildeentender.

Parasimplificaroprograma,háváriascoisasquevocêpodefazer.Emprimeirolugar,reduzaoproblemanoqualoprogramaestátrabalhando.Porexemplo,seestá fazendo uma busca em uma lista, procure em uma lista pequena. Se oprograma receber entradas do usuário, dê a entradamais simples possível quecauseoproblema.

Em segundo lugar, limpe o programa. Retire o código morto e reorganize oprograma para torná-lo o mais fácil possível de ler. Por exemplo, se vocêsuspeitar que o problema está em uma parte profundamente aninhada doprograma, tente reescrever aquela parte com uma estrutura mais simples. Sesuspeitardeumafunçãogrande,tentequebrá-laemfunçõesmenoresparatestá-lasseparadamente.

Muitasvezes,opróprioprocessodeencontrarocasodetestemínimolevavocêaoproblema.Sedescobrirqueumprogramafuncionaemumasituação,masnãoemoutra,issodáumapistasobreoqueestáacontecendo.

Deformasimilar,reescreverumapartedocódigopodeajudaraencontrarerrossutis.Sefizerumaalteraçãoquevocêachequenãovaiafetaroprograma,masqueacabeafetando,issopodeajudá-lo.

A.3-Errossemânticos

Page 290: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Dealgumasformas,oserrossemânticossãoosmaisdifíceisdedepurar,porqueo interpretador não fornece nenhuma informação sobre qual é o problema. Sóvocêsabeoqueoprogramadevefazer.

O primeiro passo é fazer uma conexão entre o texto do programa e ocomportamento que está vendo. Você precisa de uma hipótese sobre o que oprograma está fazendode fato.Umadas coisas que torna issodifícil é queoscomputadoressãorápidos.

Pode ser que você queira diminuir a velocidade do programa para serequivalenteàhumana;comalgunsdepuradoresépossívelfazerisso.Noentanto,o tempo que leva para inserir instruções print bem colocadas muitas vezes écurtoemcomparaçãoaodaconfiguraçãododepurador, inserçãoe remoçãodemarcaçõesecolocaçãodo“compasso”doprogramaondeoerroestáocorrendo.

A.3.1-Meuprogramanãofunciona

Vocêdeveseperguntaroseguinte:

Há algo que o programa deveria fazer, mas que não parece acontecer?Encontreaseçãodocódigoqueexecutaafunçãoemquestãoeconfiraseestásendoexecutadaquandovocêachaquedeveria.

Algoestáacontecendo,masnãooquedeveria?Encontreocódigonoseuprogramaqueexecutaafunçãoemquestãoevejaseestásendoexecutadanahoraerrada.

Uma seção do código está produzindo um efeito que não é o esperado?Tenha certeza de que entende o código em questão, especialmente seenvolver funções ou métodos de outros módulos do Python. Leia adocumentaçãodas funçõesquechama.Teste-asescrevendocasosde testesimpleseverificandoosresultados.

Para programar, é preciso ter um modelo mental de como os programasfuncionam.Seescreverumprogramaquenãofazoqueespera,muitasvezesoproblemanãoestánoprograma,estánoseumodelomental.

Amelhorformadecorrigiroseumodelomentaléquebraroprogramanosseuscomponentes(normalmenteasfunçõesemétodos)etestarcadacomponenteem

Page 291: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

separado.Umavezqueencontreadiscrepânciaentreoseumodeloearealidade,poderáresolveroproblema.

Naturalmente,vocêdeveriaconstruiretestarcomponentesconformedesenvolvao programa. Assim, se encontrar um problema, deve haver só uma pequenaquantidadedecódigonovoquenãosabeseestácorreto.

A.3.2-Tenhoumabaitaexpressãocabeludaeelanãofazoqueespero

Escreverexpressõescomplexaséótimoenquantosãolegíveis,maselaspodemser difíceis de depurar.Muitas vezes é uma boa ideia quebrar uma expressãocomplexaemumasériedeatribuiçõesavariáveistemporárias.

Porexemplo:

self.hands[i].addCard(self.hands[self.findNeighbor(i)].popCard())

Aexpressãopodeserreescritaassim:

neighbor=self.findNeighbor(i)

pickedCard=self.hands[neighbor].popCard()

self.hands[i].addCard(pickedCard)

Aversãoexplícitaémais fácilde lerporqueosnomesdasvariáveisoferecemdocumentaçãoadicional,eémaisfácildedepurarporquevocêpodeverificarostiposdasvariáveisintermediáriaseexibirseusvalores.

Outro problema que pode ocorrer com grandes expressões é que a ordem daavaliaçãopodenãoseroquevocêespera.Porexemplo,seestivertraduzindoa

expressão paraoPython,poderiaescrever:

y=x/2*math.pi

Isso não está correto porque a multiplicação e a divisão têm a mesmaprecedênciaesãoavaliadasdaesquerdaparaadireita.Então,éassimqueessaexpressãoécalculada:xπ/2.

Uma boa forma de depurar expressões é acrescentar parênteses para tornar aordemdaavaliaçãoexplícita:

Page 292: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

y=x/(2*math.pi)

Semprequenãotivercertezasobreaordemdaavaliação,useparênteses.Alémde o programa ficar correto (quanto à execução do que era pretendido), eletambémserámaislegívelparaoutraspessoasquenãomemorizaramaordemdeoperações.

A.3.3-Tenhoumafunçãoquenãoretornaoqueespero

Se tiver uma instrução return com uma expressão complexa, não hápossibilidadedeexibiroresultadoantesdoretorno.Novamente,vocêpodeusarumavariáveltemporária.Porexemplo,emvezde:

returnself.hands[i].removeMatches()

vocêpoderiaescrever:

count=self.hands[i].removeMatches()

returncount

Agoravocêtemaoportunidadedeexibirovalordecountantesdoretorno.

A.3.4-Estouperdidoeprecisodeajuda

Emprimeirolugar,afaste-sedocomputadorporalgunsminutos.Computadoresemitemondasqueafetamocérebro,causandoestessintomas:

frustraçãoeraiva;

crençassupersticiosas(“ocomputadormeodeia”)epensamentomágico(“oprogramasófuncionaquandousoomeuchapéuviradoparatrás”);

programação aleatória (a tentativa de programar escrevendo todos osprogramaspossíveiseescolhendoaquelequefazacoisacerta).

Seestiversofrendoalgumdessessintomas,levante-seedêumavolta.Quandoseacalmar,pensenoprograma.Oqueeleestáfazendo?Quaissãoalgumascausaspossíveis para esse comportamento? Quando foi a última vez que tinha umprogramafuncionando,eoquefezdepoisdisso?

Page 293: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Às vezes leva tempo para encontrar um erro. Com frequência encontro errosquandoestou longedocomputadoredeixoaminhamentevagar.Osmelhoreslugares para encontrar erros são os trens, o chuveiro e a cama, logo antes deadormecer.

A.3.5-Sério,precisomesmodeajuda

Acontece.Mesmoosmelhoresprogramadoresocasionalmente empacam.Podeocorrerdevocê trabalhar tantoemumprogramaquenãoconsegueenxergaroerro.Precisadeoutropardeolhos.

Antesdetrazermaisalguém,nãoseesqueçadesepreparar.Seuprogramadeveser o mais simples possível, e deve estar funcionando com a menor entradapossívelquecauseoerro.Deveterinstruçõesprintnoslugaresadequados(easaídaqueproduzemdevesercompreensível).Vocêdeveentenderoproblemaosuficienteparadescrevê-lodeformaconcisa.

Aotrazeralguémparaajudar,lembre-sededarasinformaçõesdequeapessoapossaprecisar:

Sehouverumamensagemdeerro,qualéequepartedoprogramaindica?

Qualfoiaúltimacoisaquefezantesdeesteerroocorrer?Quaisforamasúltimaslinhasdecódigoqueescreveu,ouqualéonovocasodetestequefalhou?

Oquetentouatéagoraeoqueaprendeu?

Quando encontrar o erro, pense por um segundonoquepoderia ter feito paraencontrá-lo mais rápido. Na próxima vez em que vir algo similar, poderáencontraroerromaisrapidamente.

Lembre-se,ametanãoésófazeroprogramafuncionar.Ametaéaprendercomofazeroprogramafuncionar.

Page 294: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ApêndiceB:AnálisedealgoritmosEsteapêndiceéumexcertoeditadodeThinkComplexity,porAllenB.Downey,também publicado pelaO’ReillyMedia (2012). Depois de ler este livro aqui,podeserumaboaideialê-lotambém.

Análise de algoritmos é um ramo da Ciência da Computação que estuda odesempenhodealgoritmos,especialmentesuasexigênciasdetempodeexecuçãoe requisitos de espaço. Vejahttp://en.wikipedia.org/wiki/Analysis_of_algorithms.

Ametaprática da análise de algoritmos é prever o desempenhode algoritmosdiferentesparaguiardecisõesdeprojeto.

Durante a campanha presidencial dos Estados Unidos de 2008, pediram aocandidato Barack Obama para fazer uma entrevista de emprego improvisadaquandovisitouaGoogle.Odiretorexecutivo,EricSchmidt,brincou,pedindoaele“aformamaiseficientedeclassificarummilhãodenúmerosinteirosde32bits”. Aparentemente, Obama tinha sido alertado porque respondeu na hora:“Creioqueaordenaçãoporbolha(bubblesort)nãoseriaaescolhacerta”.Vejahttp://bit.ly/1MpIwTf.

Issoéverdade:aordenaçãoporbolhaéconceitualmentesimples,maslentaparagrandesconjuntosdedados.ArespostaqueSchmidtprocuravaprovavelmenteé“ordenaçãoradix”(radixsort)(http://en.wikipedia.org/wiki/Radix_sort)[2].

A meta da análise de algoritmos é fazer comparações significativas entrealgoritmos,masháalgunsproblemas:

Odesempenhorelativodosalgoritmospodedependerdecaracterísticasdohardware;entãoumalgoritmopodesermaisrápidonaMáquinaA,eoutronaMáquinaB.Asoluçãogeralparaesteproblemaéespecificarummodelodemáquinaeanalisaronúmerodepassosouoperaçõesqueumalgoritmoexigesobummodelodado.

Odesempenhorelativopodedependerdosdetalhesdoconjuntodedados.Por exemplo, alguns algoritmos de ordenação rodam mais rápido se os

Page 295: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

dados já foram parcialmente ordenados; outros algoritmos rodam maisdevagarnestecaso.Umaformacomumdeevitaresteproblemaéanalisaropiorcaso.Àsvezeséútilanalisarodesempenhodecasosmédios,masissoé normalmentemais difícil, e pode não ser óbvio qual conjunto de casosdeveserusadoparaamédia.

O desempenho relativo também depende do tamanho do problema. Umalgoritmo de ordenação que é rápido para pequenas listas pode ser lentopara longas listas. A solução habitual para este problema é expressar otempo de execução (ou o número de operações) como uma função dotamanhodeproblemaefunçõesdegrupoemcategoriasquedependemdesuavelocidadedecrescimentoquandootamanhodeproblemaaumenta.

Uma coisa boa sobre este tipo de comparação é que ela é própria para aclassificação simples de algoritmos. Por exemplo, se souber que o tempo deexecuçãodoalgoritmoAtendeaserproporcionalaotamanhodaentradan,eoalgoritmoBtendeaserproporcionalan2,entãoesperoqueAsejamaisrápidoqueB,pelomenosparavaloresgrandesden.

Esse tipo de análise tem algumas desvantagens, mas falaremos disso maisadiante.

B.1-Ordemdecrescimento

Vamos supor que você analisou dois algoritmos e expressou seus tempos deexecuçãoemrelaçãoaotamanhodaentrada:oalgoritmoAleva100n+1passospara resolver umproblema como tamanho n; o algoritmoB leva n2+ n + 1passos.

Atabelaseguintemostraotempodeexecuçãodessesalgoritmosparatamanhosdeproblemadiferentes:

Tamanhodaentrada

TempodeexecuçãodoalgoritmoA

TempodeexecuçãodoalgoritmoB

10 1001 111100 10001 101011000 100001 100100110000 1000001 >1010

Page 296: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Aochegaremn=10,oalgoritmoAparecebemruim;eleéquasedezvezesmaislongoqueoalgoritmoB.Noentanto,paran=100elessãobemparecidos,e,paravaloresmaiores,Aémuitomelhor.

A razão fundamental é que para grandes valores de n, qualquer função quecontenha um termo n2 serámais rápida que uma função cujo termo principalsejan.Otermoprincipaléoquetemoexpoentemaisalto.

ParaoalgoritmoA,otermoprincipal temumgrandecoeficiente,100,queéarazãodeBsermelhorqueAparaumvalorpequenoden.Entretanto,apesardoscoeficientes,semprehaveráalgumvalordenemquean2>bn,paravaloresdeaeb.

Omesmoargumentoseaplicaaos termosquenãosãoprincipais.MesmoseotempodeexecuçãodoalgoritmoAfossen+1000000,aindaseriamelhorqueoalgoritmoBparaumvalorsuficientementegrandeden.

Emgeral,esperamosqueumalgoritmocomumtermoprincipalmenorsejaumalgoritmomelhorparagrandesproblemas,mas,paraproblemasmenores,podehaverumpontodedesvioondeoutroalgoritmosejamelhor.Aposiçãodopontode desvio depende dos detalhes dos algoritmos, das entradas e do hardware;então, ele é normalmente ignorado para os propósitos da análise algorítmica.Porém,issonãosignificaquevocêpodeseesquecerdele.

Se dois algoritmos tiveremomesmo termo principal de ordem, é difícil dizerqual émelhor;mais uma vez, a resposta depende dos detalhes.Assim, para aanálise algorítmica, funções com o mesmo termo principal são consideradasequivalentes,mesmosetiveremcoeficientesdiferentes.

Umaordemdecrescimentoéumconjuntode funçõescujocomportamentodecrescimentoéconsideradoequivalente.Porexemplo,2n,100nen+1pertencemàmesma ordem de crescimento, que se escreveO(n) em notaçãoGrande-O emuitas vezes é chamada de linear, porque cada função no conjunto crescelinearmenteemrelaçãoan.

Todas as funções com o termo principal n2 pertencem a O(n2); elas sãochamadasdequadráticas.

Atabelaseguintemostraalgumasordensdecrescimentomaiscomunsnaanálisealgorítmica,emordemcrescentedecomplexidade.

Page 297: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Ordemdecrescimento NomeO(1) constanteO(logbn) logarítmica(paraqualquerb)O(n) linearO(nlogbn) log-linearO(n2) quadráticaO(n3) cúbicaO(cn) exponencial(paraqualquerc)

Para os termos logarítmicos, a base do logaritmo não importa; a alteração debases é o equivalente damultiplicação por uma constante, o que não altera aordem de crescimento. De forma similar, todas as funções exponenciaispertencem à mesma ordem de crescimento, apesar da base do expoente. Asfunções exponenciais crescem muito rapidamente, então os algoritmosexponenciaissósãoúteisparapequenosproblemas.

ExercícioB.1

Leia a página daWikipédia sobre a notação Grande-O (Big-Oh notation) emhttp://en.wikipedia.org/wiki/Big_O_notationerespondaàsseguintesperguntas:

1.Qualéaordemdecrescimentoden3+n2?Ede1000000n3+n2?Ouden3+1000000n2?

2.Qual é a ordemde crescimento de (n2+ n) . (n+ 1)?Antes de começar amultiplicar,lembre-sedequevocêsóprecisadotermoprincipal.

3. Se f está emO(g), para alguma função não especificada g, o que podemosdizerdeaf+b?

4.Sef1ef2estãoemO(g),oquepodemosdizerarespeitodef1+f2?

5.Sef1estáemO(g)ef2estáemO(h),oquepodemosdizerarespeitodef1+f2?

6.Sef1estáemO(g)ef2éO(h),oquepodemosdizerarespeitodef1.f2?

Programadoresquesepreocupamcomodesempenhomuitasvezesconsideram

Page 298: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

esse tipo de análise difícil de engolir. A razão para isso é: às vezes oscoeficientes e os termos não principais fazemmuita diferença.Os detalhes dohardware, a linguagem de programação e as características da entrada fazemgrande diferença. E para pequenos problemas, o comportamento assintótico éirrelevante.

Porém,semantiveressasquestõesemmente,aanálisealgorítmicapodeserumaferramentaútil.Pelomenosparagrandesproblemas,os“melhores”algoritmossãonormalmentemelhores,e,àsvezes,muitomelhores.Adiferençaentredoisalgoritmos com a mesma ordem de crescimento é normalmente um fatorconstante, mas a diferença entre um bom algoritmo e um algoritmo ruim éilimitada!

B.2-AnálisedeoperaçõesbásicasdoPython

NoPython,amaiorpartedasoperaçõesaritméticastemumtempoconstante;amultiplicação normalmente leva mais tempo que a adição e a subtração, e adivisão levaatémais tempo,masesses temposdeexecuçãonãodependemdamagnitudedosoperandos.Osnúmerosinteirosmuitograndessãoumaexceção;nessecaso,otempodeexecuçãoaumentacomonúmerodedígitos.

Operações de indexação – ler ou escrever elementos em uma sequência oudicionário–tambémtêmtempoconstante,nãoimportao tamanhodaestruturadedados.

Um loop forqueatravesseumasequênciaoudicionárioénormalmente linear,desdeque todasasoperaçõesnocorpodo loopsejamde tempoconstante.Porexemplo,somaroselementosdeumalistaélinear:

total=0

forxint:

total+=x

Afunçãointegradasumtambémélinearporquefazamesmacoisa,mastendeasermais rápida porque é uma implementaçãomais eficiente; na linguagemdaanálisealgorítmica,temumcoeficienteprincipalmenor.

Viaderegra,seocorpodeumloopestáemO(na),entãooloopinteiroestáemO(na+1).Aexceçãoésevocêpudermostrarqueoloopencerradepoisdeum

Page 299: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

númeroconstantedeiterações.Seumloopéexecutadokvezes,nãoimportaovalorden,entãooloopestáemO(na),mesmoparavaloresgrandesdek.

Amultiplicaçãoporknãoalteraaordemdecrescimento,nemadivisão.Então,seocorpodeumloopestáemO(na)eéexecutadon/kvezes,o loopestáemO(na+1),mesmoparavaloresgrandesdek.

Amaiorpartedasoperaçõesdestringsetuplassãolineares,excetoaindexaçãoelen,quesãodetempoconstante.Asfunçõesintegradasminemaxsãolineares.Otempodeexecuçãodeumaoperaçãodefatiaéproporcionalaocomprimentodasaída,masnãodependedotamanhodaentrada.

Aconcatenaçãodestringsélinear;otempodeexecuçãodependedasomadoscomprimentosdosoperandos.

Todos osmétodos de string são lineares,mas se os comprimentos das stringsforem limitados por uma constante – por exemplo, operações em caracteresúnicos–sãoconsideradasdetempoconstante.Ométododestringjoinélinear;otempodeexecuçãodependedocomprimentototaldasstrings.

Amaiorpartedosmétodosdelistasãolineares,masháalgumasexceções:

A soma de um elemento ao fim de uma lista é de tempo constante emmédia;quandooespaçoacaba,elaocasionalmenteécopiadaaumaposiçãomaior,masotempototaldeoperaçõesnéO(n),portantootempomédiodecadaoperaçãoéO(1).

Aremoçãodeumelementodofimdeumalistaédetempoconstante.

AordenaçãoéO(nlogn).

Amaior parte das operações emétodosdedicionário sãode tempo constante,masháalgumasexceções:

O tempodeexecuçãodeupdateéproporcional ao tamanhododicionáriopassadocomoparâmetro,nãoodicionárioqueestásendoatualizado.

keys, values e items são de tempo constante porque retornam iteradores.Porém,sefizerumlooppelositeradores,oloopserálinear.

Page 300: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

O desempenho de dicionários é um dos milagres menores da ciência dacomputação.Vemoscomofuncionamem“Hashtables”,napágina302.

ExercícioB.2

Leia a página da Wikipédia sobre algoritmos de ordenação emhttp://en.wikipedia.org/wiki/Sorting_algorithm e responda às seguintesperguntas:

1.Oqueéum“tipodecomparação”?Qualéamelhoropçãonoscasosdepiorcenáriodeordemdecrescimentoparaumtipodecomparação?Qualéamelhoropção nos casos de pior cenário de ordem de crescimento para qualqueralgoritmodeordenação?

2.Qualéaordemdecrescimentodotipobolha,eporqueBarackObamaachaque“nãoéaescolhacerta”?

3. Qual é a ordem de crescimento do tipo radix? Quais são as precondiçõesnecessáriasparausá-la?

4.Oqueéumtipoestávelequalésuaimportâncianaprática?

5.Qualéopioralgoritmodeordenação(quetenhaumnome)?

6.QuealgoritmodeordenaçãoabibliotecaCusa?Quealgoritmodeordenaçãoo Python usa? Esses algoritmos são estáveis?Você pode ter que pesquisar noGoogleparaencontraressasrespostas.

7. Muitosdostiposdenãocomparaçãosãolineares,então,porqueoPythonusaumtipodecomparaçãoO(nlogn)?

B.3-Análisedealgoritmosdebusca

Uma busca é um algoritmo que recebe uma coleção e um item de objetivo edetermina se o objetivo está na coleção,muitas vezes retornando o índice doobjetivo.

Oalgoritmodebuscamaissimpleséuma“buscalinear”,queatravessaositensdacoleçãoemordem,parandoseencontraroobjetivo.Nopiorcaso,eletemque

Page 301: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

atravessaracoleçãointeira,entãootempodeexecuçãoélinear.

O operador in para sequências usa uma busca linear; assim comométodos destringcomofindecount.

Seoselementosdasequênciaestiverememordem,vocêpodeusarumabuscaporbisseção,queéO(logn).Abuscaporbisseçãoé semelhanteaoalgoritmoque você poderia usar para procurar uma palavra em um dicionário (umdicionáriodepapel,nãoaestruturadedados).Emvezdecomeçarno inícioeverificarcadaitememordem,vocêcomeçacomoitemdomeioeverificaseapalavraqueestáprocurandovemantesoudepois.Sevierantes,entãoprocuranaprimeirametadeda sequência.Senão,procurana segundametade.Seja comofor,vocêcortaonúmerodeitensrestantespelametade.

Sea sequência tiverummilhãode itens, serãonecessários cercade20passosparaencontrarapalavraouconcluirquenãoestálá.Entãoéaproximadamente50milvezesmaisrápidoqueumabuscalinear.

A busca por bisseção pode ser muito mais rápida que a busca linear, mas éprecisoqueasequênciaestejaemordem,oquepodeexigirtrabalhoextra.

Há outra estrutura de dados chamada hashtable, que é atémais rápida – vocêpodefazerumabuscaemtempoconstante–eelanãoexigequeositensestejamordenados.OsdicionáriosdoPythonsãoimplementadosusandohashtableseéporissoamaiorpartedasoperaçõesdedicionário,incluindoooperadorin,sãodetempoconstante.

B.4-Hashtables

Para explicar como hashtables funcionam e por que o seu desempenho é tãobom,começocomuma implementação simplesdeummapaevoumelhorá-logradualmenteatéquesejaumahashtable.

UsooPythonparademonstraressasimplementações,mas,navidareal,eunãoescreveriaumcódigocomoessenoPython;bastariausarumdicionário!Assim,paraorestodestecapítulo,vocêtemquesuporqueosdicionáriosnãoexistemeque quer implementar uma estrutura de dados que faça o mapa de chaves avalores.Asoperaçõesqueprecisaimplementarsão:

Page 302: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

add(k,v)Insereumnovoitemquemapeiaachavekaovalorv.ComumdicionáriodePython,d,essaoperaçãoéescritad[k]=v.

get(k)Procuraedevolveovalorquecorrespondeàchavek.ComumdicionáriodePython,d,estaoperaçãoéescritad[k]oud.get(k).

Porenquanto,vousuporquecadachavesóapareçaumavez.Aimplementaçãomaissimplesdesta interfaceusauma listade tuplas,ondecada tuplaéumparchave-valor:

classLinearMap:

def__init__(self):

self.items=[]

defadd(self,k,v):

self.items.append((k,v))

defget(self,k):

forkey,valinself.items:

ifkey==k:

returnval

raiseKeyError

addacrescentaumatuplachave-valoràlistadeitens,oquetemtempoconstante.

get usa um loop for para buscar na lista: se encontrar a chave-alvo, retornaovalorcorrespondente;docontrário,exibeumKeyError.Entãogetélinear.

Umaalternativaémanterumalistaordenadaporchaves.Assim,getpoderiausarumabuscaporbisseção,queéO(logn).Porém,inserirumnovoitemnomeiodeumalistaélinear,entãoissopodenãoseramelhoropção.Háoutrasestruturasdedadosquepodemimplementaraddegetemtempologarítmico,masissonãoétãobomcomotempoconstante,entãovamoscontinuar.

Uma forma demelhorarLinearMap é quebrar a lista de pares chave-valor emlistasmenores.Aquiestáuma implementaçãochamadaBetterMap, que é umalista de cem LinearMaps. Como veremos em um segundo, a ordem decrescimentoparagetaindaélinear,masBetterMapéumpassonocaminhoemdireçãoahashtables:

Page 303: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

classBetterMap:

def__init__(self,n=100):

self.maps=[]

foriinrange(n):

self.maps.append(LinearMap())

deffind_map(self,k):

index=hash(k)%len(self.maps)

returnself.maps[index]

defadd(self,k,v):

m=self.find_map(k)

m.add(k,v)

defget(self,k):

m=self.find_map(k)

returnm.get(k)

__init__criaumalistadenLinearMaps.

find_mapéusadaporaddegetparasaberemqualmapaonovoitemdeveirouemqualmapafazerabusca.

find_map usa a função integrada hash, que recebe quase qualquer objeto doPythoneretornaumnúmerointeiro.Umalimitaçãodestaimplementaçãoéqueelasófuncionacomchaveshashable.Tiposmutáveiscomolistasedicionáriosnãosãohashable.

Objetoshashableconsideradosequivalentesretornamomesmovalorhash,maso oposto não é necessariamente verdade: dois objetos com valores diferentespodemretornaromesmovalorhash.

find_mapusaooperadormóduloparamanterosvaloreshashnointervalode0alen(self.maps), entãoo resultadoéum índice legalna lista.Naturalmente, issosignifica quemuitos valores hash diferentes serão reunidos nomesmo índice.Entretanto, se a funçãohashdispersar as coisasde formaconsistente (que éoque as funções hash foram projetadas para fazer), então esperamos ter n/100itensporLinearMap.

Como o tempo de execução de LinearMap.get é proporcional ao número deitens, esperamosqueBetterMap seja aproximadamentecemvezesmais rápidoque LinearMap. A ordem de crescimento ainda é linear, mas o coeficiente

Page 304: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

principalémenor.Istoébom,masnãotãobomquantoumahashtable.

Aqui(finalmente)estáaideiacrucialquefazhashtablesseremrápidas:sepuderlimitar o comprimento máximo de LinearMaps, LinearMap.get é de tempoconstante.TudooquevocêprecisafazerérastrearonúmerodeitensequandoonúmerodeitensporLinearMapexcederolimite,alterarotamanhodahashtableacrescentandoLinearMaps.

Aquiestáumaimplementaçãodeumahashtable:

classHashMap:

def__init__(self):

self.maps=BetterMap(2)

self.num=0

defget(self,k):

returnself.maps.get(k)

defadd(self,k,v):

ifself.num==len(self.maps.maps):

self.resize()

self.maps.add(k,v)

self.num+=1

defresize(self):

new_maps=BetterMap(self.num*2)

forminself.maps.maps:

fork,vinm.items:

new_maps.add(k,v)

self.maps=new_maps

Cada HashMap contém um BetterMap; __init__ inicia com apenas doisLinearMapseinicializanum,quemonitoraonúmerodeitens.

get apenas despacha paraBetterMap.O verdadeiro trabalho acontece em add,que verifica o número de itens e o tamanhodeBetterMap: se forem iguais, onúmeromédiodeitensporLinearMapéum,entãoresizeéchamada.

resize faz um novo BetterMap duas vezes maior que o anterior, e então“redispersa”ositensdomapaantigononovo.

A redispersão é necessária porque alterar o número de LinearMaps muda odenominador do operador módulo em find_map. Isso significa que algunsobjetos que costumavam ser dispersos no mesmo LinearMap serão separados(queéoquequeríamos,certo?).

Page 305: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

A redispersão é linear, então resize é linear, o que pode parecer ruim, já queprometi que add seria de tempo constante. Entretanto, lembre-se de que nãotemos que alterar o tamanho a cada vez, então add normalmente é de tempoconstanteesóocasionalmente linear.Ovolume totalde trabalhoparaexecutaraddnvezeséproporcionalan, entãoo tempomédiodecadaaddéde tempoconstante!

Para ver como isso funciona, pense como seria começar com umaHashTablevaziae inserirumasériede itens.ComeçamoscomdoisLinearMaps,entãoasduas primeiras inserções são rápidas (não é necessário alterar o tamanho).Digamos que elas tomem uma unidade do trabalho cada uma. A próximainserção exige uma alteração de tamanho, então temos de redispersar os doisprimeirositens(vamoschamarissodemaisduasunidadesdetrabalho)eentãoacrescentar o terceiro item (mais uma unidade). Acrescentar o próximo itemcustaumaunidade,entãoo total,porenquanto, éde seisunidadesde trabalhoparaquatroitens.

Opróximoaddcustacincounidades,masostrêsseguintessãosóumaunidadecadaum,entãoototaléde14unidadesparaasprimeirasoitoinserções.

Opróximoaddcustanoveunidades,masentãopodemosinserirmaisseteantesda próxima alteração de tamanho, então o total é de 30 unidades para asprimeiras16inserções.

Depoisde32inserções,ocustototaléde62unidades,eesperoquevocêestejacomeçandoaverumpadrão.Depoisdeninserções,nasquaisnéumapotênciadedois,ocustototaléde2n-2unidades,entãootrabalhomédioporinserçãoéumpoucomenosdeduasunidades.Quandonéumapotênciadedois,esseéomelhorcaso;paraoutrosvaloresden,otrabalhomédioéumpoucomaior,masissonãoéimportante.OimportanteéquesejaO(1).

AFigura21.1mostragraficamentecomo isso funciona.Cadabloco representaumaunidadedetrabalho.Ascolunasmostramotrabalhototalparacadainserçãonaordemdaesquerdaparaadireita:osprimeirosdoisaddscustamumaunidade,oterceirocustatrêsunidadesetc.

Page 306: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

FiguraB.1–Ocustodeinserçõesemumahashtable.

Otrabalhoextraderedispersãoaparececomoumasequênciadetorrescadavezmaisaltascomumaumentodeespaçoentreelas.Agora,sederrubaras torres,espalhando o custo de alterar o tamanho por todas as inserções, poderá vergraficamentequeocustototaldepoisdeninserçõeséde2n−2.

Uma característica importante deste algoritmo é que quando alteramos otamanho da HashTable, ela cresce geometricamente; isto é, multiplicamos otamanho por uma constante. Se você aumentar o tamanho aritmeticamente –somandoumnúmerofixodecadavez–otempomédioporaddélinear.

Você pode baixar minha implementação de HashMap emhttp://thinkpython2.com/code/Map.py,mas lembre-sedequenãohá razãoparausá-la;sequiserummapa,bastausarumdicionáriodoPython.

B.5-Glossário

análisedealgoritmosForma de comparar algoritmos quanto às suas exigências de espaço e/outempodeexecução.

modelodemáquinaRepresentação simplificada de um computador usada para descreveralgoritmos.

piorcasoEntradaquefazumdadoalgoritmorodarmaislentamente(ouexigirmaisespaço).

termoprincipalEmumpolinômio,otermocomoexpoentemaisalto.

pontodedesvioTamanhodoproblemaemquedoisalgoritmosexigemomesmotempodeexecuçãoouespaço.

Page 307: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ordemdecrescimentoConjunto de funções em que todas crescem em uma forma consideradaequivalenteparaospropósitosdaanálisedealgoritmos.Porexemplo,todasas funções que crescem linearmente pertencem à mesma ordem decrescimento.

notaçãoGrande-O(Big-Ohnotation)Notação para representar uma ordem de crescimento; por exemplo, O(n)representaoconjuntodefunçõesquecrescemlinearmente.

linearAlgoritmo cujo tempo de execução é proporcional ao tamanho doproblema,pelomenosparagrandestamanhosdeproblema.

quadráticoAlgoritmo cujo tempo de execução é proporcional a n2, onde n é umamedidadetamanhodoproblema.

buscaProblema de localizar um elemento de uma coleção (como uma lista oudicionário)oudedecidirquenãoestápresente.

hashtableEstrutura de dados que representa uma coleção de pares chave-valor eexecutabuscasemtempoconstante.

[1]popen foidescartado,ouseja,devemosparardeusá-loecomeçarausaromódulo subprocess. Entretanto, para casos simples, eu considero subprocessmaiscomplicadoqueonecessário.Entãovoucontinuarusandopopenatéqueoremovam.

[2] Mas se fizerem uma pergunta como essa em uma entrevista, creio que amelhor resposta é “A formamais rápida de classificar ummilhão de númerosinteiroséusarqualquerfunçãodeordenaçãooferecidapelalinguagemqueestouusando. Se o desempenho é bom o suficiente para a grande maioria dasaplicações,masaminhaaplicaçãoacabassesendolentademais,euusariaalgumrecurso para investigar onde o tempo está sendo gasto. Se parecesse que umalgoritmomais rápido teria umefeito significativo sobreodesempenho, entãoprocurariaumaboaimplementaçãodotiporadix”.

Page 308: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

ColofãoO animal na capa de Pense emPython é umpapagaio-da-carolina,tambémconhecidocomoperiquito-da-carolina (Conuropsiscarolinensis). Este papagaiohabitava o sudeste dos EstadosUnidos e foi o único papagaiocontinental ahabitar regiõesacimadonortedoMéxico.Umdia,viviano norte, em locais tão distantesquanto Nova Iorque e os GrandesLagos, embora fosse encontradoprincipalmentenaregiãodaFlóridaàsCarolinas.

O papagaio-da-carolina era quasetodoverdecomacabeçaamarelae,namaturidade,tinhaumacoloraçãolaranja na testa e na face. Seutamanhomédiovariavade31a33cm.Tinha uma voz alta, ruidosa epalrava constantemente enquanto se alimentava. Habitava troncos de árvoresocospertodebrejosebarrancos.Opapagaio-da-carolinaeraumanimalmuitogregário, que vivia em pequenos grupos os quais podiam chegar a váriascentenasquandosealimentavam.

Infelizmente, essas áreas de alimentação muitas vezes eram as plantações deagricultores,quedisparavamnospássarosparamantê-los longedasplantas.Anaturezasocialdospássarosfaziacomqueelesvoassemaoresgatedequalquerpapagaio ferido, permitindo aos agricultores derrubar bandos inteiros de cadavez.Alémdisso,suaspenaseramusadasparaembelezarchapéusdesenhoras,ealguns papagaios eram mantidos como mascotes. Uma combinação dessesfatoreslevouopapagaio-da-carolinaatornar-seraronofimdosanos1800,easdoenças de aves domésticas podem ter contribuído para diminuir seu número.

Page 309: Pense em Python · 2020. 7. 12. · Fred Bremmer enviou uma correção da Seção 2.1. Jonah Cohen escreveu os scripts em Perl para converter a fonte de LaTeX deste livro para o belo

Pelosanos1920,aespécieestavaextinta.

Hoje, há mais de 700 espécimes de papagaios-da-carolina conservados emmuseusnomundointeiro.

MuitosdosanimaisnascapasdelivrosdaO’Reillyestãoemperigodeextinção;todoselessãoimportantesparaomundo.Parasabermaissobrecomovocêpodeajudar, acesse animals.oreilly.com. A imagem da capa é do livro Johnson’sNaturalHistory.

Sobreoautor

Allen Downey é professor de Ciência da Computação no Olin College ofEngineering. Ele já ensinou no Wellesley College, Colby College e na U.C.Berkeley.Édoutor emCiência daComputaçãopelaU.C.Berkeley emestre egraduadopeloMIT.