213
.

Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

  • Upload
    others

  • View
    17

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

.

Page 2: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança
Page 3: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

2

4

15

Sumário

1ComoaprenderPython1.1Oqueérealmenteimportante? 21.2Sobreosexercícios 31.3Tirandodúvidaseindoalém 3

2OqueéPython2.1Python 42.2BreveHistória 42.3Interpretador 52.4Qualversãoutilizar? 62.5Download 72.6Cpython,Jython,IronPython? 72.7PEP-Oquesãoepraqueservem 82.8Ondeusareobjetivos 82.9Primeiroprograma 92.10ModoInterativo 92.11ModoScript 102.12Exercício:Modificandooprograma 122.13Oquepodedarerrado? 12

3Variáveisetiposembutidos3.1Tiposembutidos(built-ins) 153.2Variáveis 163.3Parasabermais:Nomesdevariáveis 173.4Instruções 183.5OperadoresAritméticos 193.6Strings 203.7Entradadousuário 213.8Constantes 233.9Comandoif 26

SumárioCaelum

Page 4: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

38

55

65

3.10Convertendoumastringparainteiro 273.11Ocomandoelif 283.12Exercícios-Jogodaadivinhação 293.13Comandowhile 313.14Exercícios-Jogocomwhile 323.15Comandofor 343.16Exercícios-Utilizandoofornojogo 36

4Estruturadedados4.1Exercícios:JogodaForca 424.2Sequências 454.3Conjuntos 504.4Dicionários 514.5Exercícios:Estruturadedados 53

5Funções5.1Oqueéumafunção? 555.2ParâmetrosdeFunção 565.3Funçãocomretorno 575.4Retornandomúltiplosvalores 585.5Exercícios:Funções 595.6Númeroarbitráriodeparâmetros(*args) 605.7Númeroarbitráriodechaves(**kwargs) 615.8Exercício-*argse**kwargs 625.9Exercício-Funçãojogar() 635.10Móduloseocomandoimport 63

6Arquivos6.1Escritadeumarquivo 656.2Fechandoumarquivo 666.3Escrevendopalavrasemnovaslinhas 666.4Exercicios 676.5Lendoumarquivo 686.6Lendolinhaporlinhadoarquivo 696.7Gerandoumnúmeroaleatório 706.8Exercícios-Leituradearquivos 716.9Parasabermais-comandowith 736.10Melhorandonossocódigo 736.11Exercício-RefatorandoojogodaForca 74

CaelumSumário

Page 5: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

81

102

117

132

7OrientaçãoaObjetos7.1Funcionalidades 827.2Exercício:Criandoumaconta 837.3ClasseseObjetos 847.4Construtor 867.5Métodos 877.6Métodoscomretorno 897.7Objetossãoacessadosporreferência 907.8Métodotransfere 927.9Continuandocomatributos 937.10Tudoéobjeto 957.11Composição 967.12Parasabermais:outrosmétodosdeumaclasse 987.13Exercício:PrimeiraclassePython 99

8Modificadoresdeacessoemétodosdeclasse8.1Encapsulamento 1058.2Atributosdeclasse 1098.3Métodosdeclasse 1128.4Parasabermais-Slots 1138.5Exercícios: 115

9Pycharm9.1IDE 1179.2Pycharm 1179.3DownloadeInstalaçãodoPyCharm 1189.4CriandoumProjeto 1199.5Criandoumaclasse 1229.6Executandocódigo 1249.7Criandométodos 1269.8PrincipaisAtalhos 1279.9Exercício-CriandoprojetobanconoPyCharm 128

10HerançaePolimorfismo10.1Repetindocódigo? 13210.2Reescritademétodos 13610.3Invocandoométodoreescrito 13710.4Parasabermais-MétodosMágicos 14010.5Polimorfismo 140

SumárioCaelum

Page 6: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

153

169

184

198

201

10.6DuckTyping 14310.7Exercício:HerançaePolimorfismo 14510.8ClassesAbstratas 14810.9Exercícios-classesabstratas 150

11HerançaMúltiplaeInterfaces11.1Problemadodiamante 15511.2Mix-ins 15811.3Parasabemais-Tkinter 15911.4(Opcional)Exercícios-Mix-Ins 16011.5Intefaces 16211.6Exercícios-InterfaceseclassesAbstratas 165

12ExceçõeseErros12.1Exceçõesetiposdeerros 17412.2TratandoExceções 17612.3Levantandoexceções 17712.4DefinirumaExceção 17712.5Parasabermais:finally 17912.6ÁrvoredeExceções 18012.7Exercícios:Exceções 18112.8OutrosErros 18212.9Parasabermais-depuradordoPython 183

13Collections13.1UserList,UserDicteUserString 18413.2Parasabermais 18613.3Collectionsabc 18813.4ConstruindoumContainer 18913.5Sized 19013.6Iterable 19113.7Exercício:CriandonossaSequência 194

14Apêndice-Python2ouPython3?14.1Quaisasdiferenças? 19814.2Afunçãoprint() 19914.3Afunçãoinput() 19914.4Divisãodecimal 19914.5Herança 200

15Apêndice-Instalação

CaelumSumário

Page 7: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

15.1InstalandooPythonnoWindows 20115.2InstalandooPythonnoLinux 20515.3InstalandooPythonnoMacOS 20515.4OutrasformasdeutilizaroPython 206

Versão:22.8.23

SumárioCaelum

Page 8: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

.

Page 9: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO1

Muitoslivros,aopassardoscapítulos,mencionamtodososdetalhesdalinguagem,juntamentecomseusprincípios básicos. Isso acaba criandomuita confusão, em especial porque o estudante não conseguediferenciarexatamenteoqueéessencialaprendernoinício,daquiloquepodeserdeixadoparaestudarmaistarde.

Se uma classe abstrata deve ou não ter ao menos um método abstrato, se o if somente aceitaargumentosbooleanosetodososdetalhessobreclassesinternas,realmentenãodevemserpreocupaçõespara aquele cujoobjetivoprimário é aprenderPython.Esse tipode informação será adquirida comotempoenãoénecessárianoinício.

Nestecurso,separamosessasinformaçõesemquadrosespeciais, jáquesãoinformaçõesextras.Ouentão,apenascitamosemalgumexercícioedeixamosparaoleitorprocurarinformaçõesadicionais,sefordeseuinteresse.

Porfim,faltamencionaralgosobreaprática,quedevesertratadaseriamente:todososexercíciossãomuito importantes e os desafios podem ser feitos após o término do curso. De qualquer maneira,recomendamosaosalunosestudarememcasaepraticarembastantecódigoevariações.

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

COMOAPRENDERPYTHON

1.1OQUEÉREALMENTEIMPORTANTE?

Seuslivrosdetecnologiaparecemdoséculopassado?

.

Page 10: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Os exercícios do curso variam, de práticos até pesquisas na internet, ou mesmo consultas sobreassuntosavançadosemdeterminadostópicos,paraincitaracuriosidadedoaprendiznatecnologia.

Existe também, em determinados capítulos, uma série de desafios. Eles focammais no problemacomputacionalquenalinguagem,porémsãoumaexcelenteformadetreinarasintaxee,principalmente,familiarizar o aluno com as bibliotecas padrões do Python, além de proporcionar um ganho navelocidadededesenvolvimento.

Paratirardúvidasdeexercícios,oudePythonemgeral,recomendamosofórumdoGUJRespostas:

http://www.guj.com.br

Lásuadúvidaserárespondidaprontamente.OGUJfoifundadopordesenvolvedoresdaCaelumehojecontacommaisdeummilhãodemensagens.

Oprincipalrecursooficialparaencontrardocumentação,tutoriaiseatémesmolivrossobrePythonéaPythonSoftwareFoundation(PSF):

https://www.python.org/

DestacamostambémapáginadacomunidadenoBrasil:

https://python.org.br/

Hátambémfórunsoficiaisdacomunidade:

https://python-forum.io/(inglês)

https://python.org.br/lista-de-discussoes/(português)

Foraisso,sinta-seàvontadeparaentraremcontatocomseuinstrutorparatirartodasasdúvidasquesurgiremduranteocurso.

Seoquevocêestábuscandosãolivrosdeapoio,sugerimosconheceraeditoraCasadoCódigo:

https://www.casadocodigo.com.br/

Hátambémcursosonlinequevãoajudá-loairalém,commuitainteraçãocomosinstrutores:

https://www.alura.com.br/

1.2SOBREOSEXERCÍCIOS

1.3TIRANDODÚVIDASEINDOALÉM

.

Page 11: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO2

Python é uma linguagem de programação interpretada, orientada a objetos, de alto nível e comsemânticadinâmica.AsimplicidadedoPythonreduzamanutençãodeumprograma.Pythonsuportamódulosepacotes,queencorajaaprogramaçãomodularizadaereusodecódigos.

É uma das linguagens que mais tem crescido devido sua compatibilidade (roda na maioria dossistemasoperacionais)ecapacidadedeauxiliaroutras linguagens.ProgramascomoDropbox,Reddit eInstagramsãoescritosemPython.Pythontambéméalinguagemmaispopularparaanálisededadoseconquistouacomunidadecientífica.

Masantesquevocêsepergunteoquecadaumadessascoisasrealmentesignifica,vamoscomeçaradesbravar o mundo Python e entender como funciona essa linguagem de programação que temconquistadocadavezmaisadeptos.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Pythonfoicriadaem1990porGuidoVanRossumnoCentrodeMatemáticaStichting(CWI,vejahttp://www.cwi.nl) naHolanda como uma sucessora da linguagemABC. Guido é lembrado como oprincipalautordePythonmasoutrosprogramadoresajudaramcommuitascontribuições.

AlinguagemABCfoidesenhadaparausodenãoprogramadores,maslogodeiníciomostroucertas

OQUEÉPYTHON

2.1PYTHON

Agoraéamelhorhoradeaprenderalgonovo

2.2BREVEHISTÓRIA

.

Page 12: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

limitaçõeserestrições.Amaiorreclamaçãodosprimeirosalunosnãoprogramadoresdessa linguagemera a presença de regras arbitrárias que as linguagens de programação haviam estabelecidotradicionalmente-muitacoisadebaixonívelaindaerafeitaenãoagradouopúblico.

Guidoentãoselançounatarefadecriarumalinguagemdescriptsimplesquepossuíssealgumasdasmelhores propriedades da ABC. Listas Python, dicionários, declarações básicas e uso obrigatório deindentação-conceitosqueaprenderemosnestecurso-diferenciamPythondalinguagemABC.Guidopretendia que Python fosse uma segunda linguagem para programadores C ou C++ e não umalinguagemprincipalparaprogramadores-oquemaistardesetornouparaosusuáriosdePython.

Em1995,GuidocontinuouseutrabalhoemPythonnaCorporationforNationalResearchInitiatives(CNRI, veja http://www.cnri.reston.va.us/) in Reston, Virginia onde ele lançou outras versões dalinguagem.

Emmaiode2000,GuidoeotimeprincipaldePythonsemudaramparaaBeOpen.comparaformarotimeBeOpenPythonLabs.Emoutubrodomesmoano,otimedaPythonLabssemoveuparaaDigitalCreations(hoje,ZopeCorporation,vejahttp://www.zope.org/).Em2001,aPythonSoftwareFoundation(PSF,vejahttp://www.python.org/psf/),umaorganizaçãosemfinslucrativos,foiformadaespecialmenteparamanteralinguagemehojepossuisuapropriedadeintelectual.AZopeCorporationéummembropatrocinadordaPSF.

TodososlançamentosdePythonsãodecódigoaberto(vejahttp://www.opensource.org).

VocêprovavelmentejáouviuouleuemalgumlugarquePythonéumalinguageminterpretadaouuma linguagem de script. Em certo sentido, também é verdade que Python é tanto uma linguageminterpretada quanto uma linguagem compilada. Um compilador traduz linguagem Python emlinguagemdemáquina-códigoPythonétraduzidoemumcódigointermediárioquedeveserexecutadoporumamáquinavirtualconhecidacomoPVM(PythonVirtualMachine).ÉmuitosimilaraoJava-háaindaumjeitodetraduzirprogramasPythonembytecodeJavaparaJVM(JavaVirtualMachine)usandoaimplementaçãoJython.

O interpretador faz esta 'tradução' em tempo real para códigodemáquina, ou seja, em tempodeexecução. Jáocompilador traduzoprogramainteiroemcódigodemáquinadeumasóvezeentãooexecuta,criandoumarquivoquepodeserrodado(executável).Ocompiladorgeraumrelatóriodeerros(casoselesexistam)eointerpretadorinterrompeatraduçãoquandoencontraumprimeiroerro.

Em geral, o tempo de execução de um código compilado émenor que um interpretado já que ocompilado é inteiramente traduzido antes de sua execução. Enquanto o interpretado é traduzidoinstrução por instrução. Python é uma linguagem interpretadamas, assim como Java, passa por umprocessodecompilação.UmcódigofonteJavaéprimeiramentecompiladoparaumbytecodeedepois

2.3INTERPRETADOR

.

Page 13: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

interpretadoporumamáquinavirtual.

Masdevemoscompilar scriptPython?Comocompilar?Normalmente,nãoprecisamos fazernadadisso porque o Python está fazendo isso para nós, ou seja, ele faz este passo automaticamente. Naverdade,éointerpretadorPyhton,oCPython.AdiferençaéqueemJavaémaisclaraessaseparação,oprogramadorcompilaedepoisexecutaocódigo.

CPythonéumaimplementaçãodalinguagemPython.Parafacilitaroentendimento,imaginequeéumpacote que vem comumcompilador e um interpretadorPython (no caso, umaMáquinaVirtualPython) além de outras ferramentas para usar e manter o Python. CPython é a implementação dereferência(aquevocêinstaladositehttp://python.org).

Para quem está começando, a primeira dúvida na hora da instalação é qual versão do Pythondevemosbaixar.Aqui,dependedoquesedeseja fazer.OPython3aindapossuialgumasdesvantagensemrelaçãoaversão2comoosuportedebibliotecas(queémaisreduzido)epelo fatodamaioriadasdistribuições Linux e oMacOS aindautilizarema versão 2 comopadrão em seus sistemas. Porém, oPython3émaismaduroemaisrecomendávelparaouso.

ExistemcasosqueexigemoPython2aoinvésdoPython3comoimplementaralgoemumambientequeoprogramadornãocontrolaouquandoprecisautilizar algumpacote/módulo específicoquenãopossui versão compatível com Python3. Vale ressaltar para quem deseja utilizar uma implementaçãoalternativa do Python, como o IronPython ou Jython, que o suporte ao Python3 ainda é bastantelimitado.

Atualmenteexisteaferramenta2to3quepermitequecódigoPython3sejageradoapartirdecódigoPython2. Há também a ferramenta 3to2, que visa converter o código Python3 de volta ao códigoPython2. No entanto, é improvável que o código que faz uso intenso de recursos do Python3 sejaconvertidocomsucesso.

2.4QUALVERSÃOUTILIZAR?

.

Page 14: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

PARASABERMAIS:MÓDULOFUTURE

O módulo future do Python2 contém bibliotecas que fazem uma ponte entre as versõesanterioreseasmaisrecentes.Bastaimportarebibliotecafuture:

>>>import__future__

Paraqueváriasferramentasdisponíveisnaversão3funcionemnaversão2,ouseja,omódulo__future__ permite usar funcionalidades do Python3 no Python2. Mas cuidado, algumasfuncionalidades são sobrescritas e é importante sempre checar a documentação:https://docs.python.org/3/library/\_\_future\_\_.html

Optamos pelo uso da versão mais recente para este curso, a versão 3.6, e vamos introduzir asdiferençasdaversãoPython2emcomentáriosduranteoscapítulosenosapêndicesdaapostila.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

Comoditoacima,oPythonjáveminstaladonossistemasLinuxeMacOSmasseránecessáriofazerodownloaddaúltimaversão(Python3.6)paraacompanharaapostila.OPythonnãoveminstaladoporpadrãonoWindows e o downloaddeverá ser feito no site https://www.python.org/ além de algumasconfiguraçõesextras(vejaapêndicedestaapostilasobreinstalação).

ExistemoutrasimplementaçõesdalinguagemcomooJythoneoIronPython.Adiferençaéqueestasimplementações são apenas os compiladores.O bytecode gerado pelo Jython é interpretado por uma

EditoraCasadoCódigocomlivrosdeumaformadiferente

2.5DOWNLOAD

2.6CPYTHON,JYTHON,IRONPYTHON?

.

Page 15: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

JVM(JavaVirtualMachine)eobytecodedoIronPythonporumaVirtualMachine.NET.

Outra implementação que vem crescendo é o PyPy, uma implementação escrita em Python quepossuiumaVirtualMachinePython.ÉmaisvelozdoqueoCPythonevemcomatecnologiaJIT(JustInTime)quejá"traduz"ocódigofonteemcódigodemáquina.

OCompiladorPythontraduzumprograma.pyparabytecode -elecriaumarquivocorrespondentechamadoprograma.cpy. Se quisermos ver obytecode pelo terminal, basta usar omódulodisassembler(dis)quesuportaanálisedobytecodedoCPython,desmontando-o.Vocêpodechecaradocumentaçãoaqui:https://docs.python.org/3/library/dis.html.

PEP,PythonEnhancementProposalsouPropostasparaMelhoramentonoPython,comoonomedizsão propostas de aprimoramento ou de novas funcionalidades para a linguagem.Qualquer um podeescrever uma proposta e a comunidade Python testa, avalia e decide se deve ou não fazer parte dalinguagem.Casoaprovado,orecursoéliberadoparaaspróximasversões.

NositeoficialdoPython(https://www.python.org/)vocêpodechecartodasasPEPsdalinguagem.APEP 0 é aquela que contém o índice de todas as propostas de aprimoramento do Python e pode seracessadaaqui:https://www.python.org/dev/peps.

Ao longo do curso, de acordo com a aprendizagem e uso de certas funcionalidades, citaremosalgumasPEPsmaisimportantes.

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

Python é uma linguagem de propósito geral. Muitas vezes precisamos lidar com tarefas laterais:

2.7PEP-OQUESÃOEPRAQUESERVEM

JáconheceoscursosonlineAlura?

2.8ONDEUSAREOBJETIVOS

.

Page 16: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

buscardadosemumbancodedados,lerumapáginanainternet,exibirgraficamenteosresultados,criarplanilhasetc.EPythonpossuiváriosmódulosprontospararealizaressastarefas.

PoresseeoutrosmotivosquePythonganhougrandepopularidadenacomunidadecientífica.Alémdisso, Python é extremamente legível e uma linguagem expressiva, ou seja, de fácil compreensão.Asciências,poroutrolado,possuemraciocínioessencialmentecomplicadoeseriaumproblemaadicionalparacientistasconhecerem,alémdeseuassuntodepesquisa,assuntoscomplexosdeumprogramadecomputador como alocação de memória, gerenciamento de recursos etc. Python faz issoautomaticamentedemaneiraeficienteepossibilitandoocientistaseconcentrarnoproblemaestudado.

Vamosparanossoprimeirocódigo!Umprogramaqueimprimeumamensagemsimples.

Paramostrarumamensagemespecífica,fazemos:

print('MinhaprimeiraaplicaçãoPython!')

Certo,masondedigitaressecomando?ComorodarumainstruçãoPython?

Iremos,primeiro,aprenderomodointerativoutilizandooterminal(LinuxeMacOS)ouopromptdecomando(Windows)pararodaroprogramaacima.Abraoterminaledigite:

dev@caelum:~$python3.6

IssovaiabriromodointerativodoPythonnaversão3.6dalinguagem,tambémchamadodeconsoledoPython.Apósdigitarestecomando,asseguinteslinhasirãoaparecernoseuconsole:

Python3.6.4(default,Jan282018,00:00:00)[GCC4.8.4]onlinuxType"help","copyright","credits"or"license"formoreinformation.>>>

AprimeiralinhaindicaqueaversãoutilizadadoPythonéaversão3.6.4.Asegundaindicaosistemaoperacional(nocaso,oLinux).Aterceiramostraalgumaspalavraschavesdointerpretadorparaacessaralgumasinformações-digitealgumadelaseaperteENTERparatestar.

O'>>>'indicaqueentramosnomodointerativodoPythonebastacomeçaraescreveroscomandos.VamosentãoescrevernossoprimeiroprogramaPython:

>>>print('MinhaprimeiraaplicaçãoPython!')

AoapertarENTER,temos:

>>>print('MinhaprimeiraaplicaçãoPython!')MinhaprimeiraaplicaçãoPython!

2.9PRIMEIROPROGRAMA

2.10MODOINTERATIVO

.

Page 17: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Oprint()éumafunçãodoPythonutilizadaparaimprimiralgumamensagemnatela.Maisdetalhessobre funções são tratados em um capítulo específico desta apostila. Neste momento, entenda umafunçãocomoumafuncionalidadeprontaquealinguagemfornece.

Umamensagemdeveestardelimitadaentreaspassimples('')ouduplas(""),comofeitonoexemploacimacomamensagem:'MinhaprimeiraaplicaçãoPython!'.Ointerpretador,nomodointerativo,jávaimostrarasaídadestecomandonoconsole,logoabaixodele.

Maseseumprogramapossuir1.000linhasdecódigo?Teremosquedigitaressasmillinhastodasasvezes para rodar o programa? Isso, obviamente, seria um problema. Existe outro modo dedesenvolvimentonoPython,maisutilizado,queevitadigitarumprogramalongonoconsole todavezqueprecisarexecutá-lo.

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

Omodo interativo émais utilizado para testes enquanto que omodo script é mais comumenteutilizado na hora de desenvolver. No modo script isolamos o código Python em um arquivo comextensão.py.Dessamaneira,ocódigoéescritoumaúnicavezeexecutadopelointerpretadoratravésdocomandopython3(ouocomandopythonseestiverutilizandooPython2).

Abraumeditordetextodesuapreferênciaeescrevaoprogramaanteriornele:

print('MinhaprimeiraaplicaçãoPython!')

Salveoarquivocomoprograma.py.Paraexecutá-lo,abraoterminal,navegueatéodiretórioondeseencontraoarquivoprograma.pyedigite:

dev@caelum:~$python3programa.py

AoapertarENTER,vaiaparecernoconsole:

dev@caelum:~$python3programa.py

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

2.11MODOSCRIPT

.

Page 18: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

MinhaprimeiraaplicaçãoPython!

Vejaqueagora isolamosocódigoemumaarquivoeoexecutamosatravésdocomandopython3.MasnãodevemoscompilarscriptPython?Comocompilar?

NormalmentenãoprecisamosfazernadadissoporqueoPythonestáfazendoissonosbastidores,ouseja, ele faz este passo automaticamente. Se por algum motivo você queira compilar um programaPythonmanualmente,vocêdeveusaromódulopy_compilenoconsoledoPython:

>>>importpy_compile>>>py_compile.compile('programa.py')'__pycache__/programa.cpython-34.pyc'

O comando import importa o módulo py_compile que disponibiliza a função compile(). Oupodemosobteromesmoresultadoutilizandooseguintecomandonoterminal:

dev@caelum:~$python3-mpy_compileprograma.py

Também é possível compilar todos os arquivos Python de uma única vez usando o módulocompileall:

dev@caelum:~$python3-mcompileall

Mas nada disso é necessário. O processo de compilação é feito automaticamente e não é precisorepetirtodoesteprocessopararodarumprogramaPython.

Apenas rodando o programa, sem precisar compilá-lo, note que uma nova pasta chamada"__pycache__"écriada(casoelanãoexista)nomesmodiretórioqueoprogramafoiexecutado.Dentrodestapastaécriadoumarquivoprograma.cpython-34.pyc-estaéaversãocompiladadoprograma,ocódigobytecodegeradopeloCPython.

SemprequeumprogramaPythonéchamado,oPythonchecaráseexisteumaversãocompiladacoma extensão .pyc - este arquivodeve sermais novodo que o de extensão .py (se o arquivo existir).OPythonvai carregar obytecode, o que vai acelerar o script. Senão existir a versãobytecode, oPythoncriaráoarquivobytecodeantesde iniciaraexecuçãodoprograma.ExecuçãodeumprogramaPythonsignificaaexecuçãodeumcódigobytecodenaPythonVirtualMachine.

.

Page 19: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

TodavezqueumscriptPythoné executado,umcódigobytecode é criado. Seum scriptPython éimportadocomoummódulo,obytecodevaiarmazenarseuarquivo.pyccorrespondente.

Portanto,opassoseguintenãocriaráoarquivobytecodejáqueointerpretadorvaiverificarquenãoexistenenhumaalteração:

dev@caelum:~$pythonprograma.pyMinhaprimeiraaplicaçãoPython!dev@caelum:~$

1. Altereoprogramaparaimprimirumamensagemdiferente.

2. Altereseuprogramaparaimprimirduaslinhasdecódigoutilizandoafunçãoprint().

3. Sabendo que os caracteres\n representam uma quebra de linha, imprima duas linhas de textousandoumaúnicalinhadecódigo.

Nem sempre as coisas acontecem como esperado. O Python tem uma sintaxe própria, umvocabulário próprio. Digitar algo que o interpretador não entende causará um erro no programa.Vejamosalgunsexemplos:

>>>printMinhaprimeiraaplicaçãoPython!Traceback(mostrecentcalllast):File"<stdin>",line1print'MinhaprimeiraaplicaçãoPython!'^SyntaxError:Missingparenthesesincallto'print'.Didyoumeanprint('MinhaprimeiraaplicaçãoPython!')?

Nãoseassustecomamensagem.Vamosentenderoqueelaquerdizer.NaprimeiralinhaapareceapalavraTracebackquesignificaalgocomo:"Oqueoprogramaestavafazendoquandoparouporquealgodeerradoaconteceu?".Éporestemotivoqueamensagemmostrecentcalllast (chamadamaisrecente)émostrada.

ATracebackfazreferênciaaumarquivo-queéonomedoarquivoPythonchamadoacimapelonomedestdinquepossuimétodosparaleitura,ondeoprogramalêaentradadoteclado.Oprogramaacusaqueesteerroestánaprimeiralinhadoprograma:File"<stdin>",line1.

Logo em seguida é mostrado exatamente a parte do código que gerou o erro: print 'Minha

primeiraaplicaçãoPython!'.Apróximalinhaéamensagemdeerro:SyntaxError.Sevocênãofaz a menor ideia do que esta mensagem significa é um bom começo e uma boa prática durante a

2.12EXERCÍCIO:MODIFICANDOOPROGRAMA

2.13OQUEPODEDARERRADO?

Esquecerosparênteses

.

Page 20: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

aprendizagempesquisararespeitodelanainternet,assimcomodemaiserrosquepossamsurgir.

Nestecaso,éumSyntaxError,ouseja,ErrodeSintaxe - oPythonnão entendeuoque foidigitado.Amensagemdizquefaltamosparênteses!Então,éfácilacharumerroquandoeleacontece.

AlgumasvezesvocêveráapalavraExceptionemumamensagemdeerro.UmaExceptionéumproblema que ocorre enquanto o código está sendo executado. Já o SyntaxError é um problemadetectadoquandooPythonverificaocódigoantesdeexecutá-lo,ouseja,emtempodecompilação.

O interpretador vai aguardar (continuar imprimindo reticências cada vez que a teclaENTER forapertada)atéqueoparêntesesejafechado:

>>>print('MinhaprimeiraaplicaçãoPython!'.........

Nestecasonãoéumaexceçãoouerro,anãoserquevocêdigitequalqueroutracoisaquenãoumfechamentodeparênteseeaperteateclaENTER.

>>>print(MinhaprimeiraaplicaçãoPython!)File"<stdin>",line1print(MinhaprimeiraaplicaçãoPython!)^SyntaxError:invalidsyntax

Maisumavezacusaerrodesintaxe.

Estes foram alguns erros que o programa pode gerar por desatenção do programador. Sãomaiscomunsdeacontecerdoqueseimagina.Outroserrosserãoabordadosemumcapítuloespecíficodestaapostila. Neste momento iremos aprender outros recursos que a linguagem Python oferece e sefamiliarizarcomsuasintaxe.

Esquecerdefecharosparênteses

Esquecerdecolocaramensagementreaspas(simplesouduplas)

.

Page 21: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Seuslivrosdetecnologiaparecemdoséculopassado?

.

Page 22: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO3

NestecapítulovamosconhecerostiposdabibliotecapadrãodoPython.Osprincipaistiposinternossãonúmeros,sequências,mapas,classes,objetoseexceções,masiremosfocarprimeiramentenosnúmerosesequênciasdetexto(strings).Sãoobjetosnativosdalinguagem,recursosquejávêmprontosparausoechamadosdebuilt-ins.

Neste iníciodaaprendizagemtrabalharemoscomomodo interativoeao finalproduziremosumapequenaaplicaçãoemumscript.

Umvalor,comoumnúmerooutexto,éalgocomumemumprograma.Porexemplo,'Hello,World!',1,2,todossãovalores.Estesvaloressãodediferentestipos:1e2sãonúmerosinteirose'HelloWorld!'éum texto, tambémchamadodeString. Podemos identificar strings porque sãodelimitadaspor aspas(simplesouduplas)-eéexatamentedessamaneiraqueointerpretadorPythontambémidentificaumastring.

Afunçãoprint()utilizadanocapítuloanteriortambémtrabalhacominteiros:

>>>print(2)2

Veja que aqui não é necessário utilizar aspas por se tratar de umnúmero. Caso você não tenhacertezaqualéotipodeumvalor,podeusarafunçãotype()parachecar:

>>>type('HelloWorld')<class'str'>

>>>type(2)<class'int'>

Stringssãodotipostr(abreviaçãoparastring)einteirosdotipoint (abreviaçãopara integer).Ignore a palavraclass por enquanto, teremos um capítulo especial para tratar dela. Veremos quefunçõescomotype()eprint()tambémsãotiposembutidosnoPython.

OutrotipoqueexistenoPythonsãoosnúmerosdecimaisquesãodotipofloat(pontoflutuante):

>>>type(3.2)<class'float'>

VARIÁVEISETIPOSEMBUTIDOS

3.1TIPOSEMBUTIDOS(BUILT-INS)

.

Page 23: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Equalseráotipodevalorescomo'2'e'3.2'?Elesseparecemcomnúmerosmassãodelimitadosporaspascomostrings.Utilizeafunçãotype()parafazeraverificação:

>>>type('2')<class'str'>

>>>type('3.2')<class'str'>

Comoestãodelimitadosporaspas,ointerpretadorvaientenderessesvalorescomostrings,ouseja,comotexto.

O Python também possui um tipo específico para números complexos. Números complexos sãodefinidospordoisvalores:aparterealeaparteimaginária.NoPythonéescritonaformareal+imagj.Nocaso,onúmeroimaginário(definidopelaraizde-1echamadode'i'namatemática)édesignadopelaletrajnoPython.Porexemplo:

>>>2+3j>>>type(2+3j)<class'complex'>

2éapartereale3aparteimagináriadonúmerocomplexo.Utilizandoafunçãotype()podemosnoscertificarqueseutipoécomplex.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

PodemospedirparaoPython lembrardeumvalorquequeiramosutilizaremoutromomentodoprograma.OPythonvaiguardarestevaloremumavariável.Variáveléumnomequefazreferênciaaumvalor.É comouma etiqueta que colocamosnaquele valor e quandoprecisarmosusar, chamamospelonomequefoidadonaetiqueta.

Umcomandodeatribuição(osinaldeigualdade=)criaumanovavariáveleatribuiumvaloraela:

EditoraCasadoCódigocomlivrosdeumaformadiferente

3.2VARIÁVEIS

.

Page 24: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>mensagem='oi,python''oi,python'

>>>numero=55

>>>pi=3.143.14

Trêsatribuiçõesforamfeitasnestecódigo.Atribuímosavariávelmensagemumastring;avariávelnumero um inteiro e a variável pi um valor aproximado do número pi. No modo interativo, ointerpretadormostraoresultadoapóscadaatribuição.

Pararecuperaressesvalores,bastachamarpelosnomesdasvariáveisdefinidasanteriormente:

>>>mensagemoi,python

>>>numero5

>>>pi3.14

Utilizeafunçãotype()paraverificarseustipos:

>>>type(mensagem)<class'str'>

>>>type(numero)<class'int'>

>>>type(pi)<class'float'>

Programadores escolhem nomes para variáveis que sejam semânticos e que ao mesmo tempodocumentem o código. Esses nomes podem ser bem longos, podem conter letras e números. É umaconvenção entre os programadores Python começar a variável com letras minúsculas e utilizar ounderscore(_)parasepararpalavrascomo:meu_nome,numero_de_cadastro, telefone_residencial.Essepadrãoé chamadode snake case.Variáveis tambémpodemcomeçar comunderscore (_)masdeveserevitadoeutilizadoemcasosmaisespecíficos.

Senomearmosnossasvariáveiscomumnomeilegal,ointerpretadorvaiacusarumerrodesintaxe:

>>>1nome='python'File"<stdin>",line11nome='python'^SyntaxError:invalidsyntax

>>>numero@=10File"<stdin>",line1numero@=10

3.3PARASABERMAIS:NOMESDEVARIÁVEIS

.

Page 25: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

^SyntaxError:invalidsyntax

>>>class='oi'File"<stdin>",line1class=oi^SyntaxError:invalidsyntax

1nome é ilegalporquecomeçacomumnúmero,numero@ é ilegalporquecontémumcaractereespecial(o@)consideradoilegalparavariáveis.EclasséilegalporqueclasséumapalavrachaveemPython.Ointerpretadorutilizapalavraschavescomopalavrasreservadasdalinguagem,comoumvocabuláriopróprio.

Pythonpossui33palavrasreservadas:

anddelfromNoneTrueaselifglobalnonlocaltryassertelseifnotwhilebreakexceptimportorwithclassFalseinpassyieldcontinuefinalyisraisedefforlambdareturn

Portanto,nãopodemosutilizaressaspalavrasparanomearnossasvariáveis.

Umainstrução(oucomando)éumaunidadedecódigoqueoPythonpodeexecutar.Porexemplo,afunçãoprint()paraimprimirumamensagemnatelaéumcomando:

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

Quando executamos um comando no modo interativo, o interpretador Python apresenta oresultado,casoexista,destecomando.Umscriptcontémumasequênciadeinstruções.Seexistirmaisdeumcomando,osresultadosvãoaparecendoduranteaexecuçãodoprograma:

print(1)x=2print(x)

Eproduzasaída:

12

PararodarumscriptemPythonéprecisoconcentraressescomandosemummesmolugarepedirpara o interpretador executá-los. Criamos um arquivo de extensão .py com estes comandos, comoaprendemosnocapítuloanterior.

Arquivoprograma.py:

3.4INSTRUÇÕES

.

Page 26: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Notequedevemosutilizarafunçãoprint()paraexibirosresultadosnatelajáqueomodoscript,diferentedomodointerativo,nãoexibeosresultadosapósadeclaraçãodevariáveis.

Navegueatéodiretórioondeseencontraoarquivoprograma.pyedigiteocomandonoterminal:

dev@caelum:~$python3programa.py

Quevaigerarasaída:

dev@caelum:~$python3programa.pyoi,python53.14

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

Operadores são símbolos especiais que representam cálculos como adições emultiplicações. Parafazercálculoscomnúmerosutilizamososoperadores+, -, *, /e**querepresentam,respectivamente,adição,subtração,multiplicação,divisãoepotenciação.

Umaexpressãoéumacombinaçãodevalores,variáveiseoperadorescomox+17,1+1 etc.Quando digitamos uma expressão no modo interativo, o interpretador vai calcular e imprimir oresultado:

>>>1+1

JáconheceoscursosonlineAlura?

3.5OPERADORESARITMÉTICOS

.

Page 27: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

2

>>>2*36

Tambémpodemosusarvariáveis:

>>>x=1>>>y=3>>>x+y4

>>>x-y-2

>>>x*y3

>>>x/y0.3333333333333333

>>>x**y1

Alémdosoperadorescomentados,temostambémooperador//querepresentaadivisãointeira:

>>>7//23

Eooperadormódulo%queresultanorestodadivisãoentredoisnúmerosinteiros:

>>>7%31

7dividopor3é2egeraresto iguala1.Esseoperadorébemútilquandoqueremoschecarseumnúmeroédivisívelporoutro.

Osprincipaisoperadoressão:

Operação Nome Descrição

a+b adição Somaentreaeb

a-b subtração Diferençaentreaeb

a*b multiplicação Produtoentreaeb

a/b divisão Divisãoentreaeb

a//b divisãointeira Divisãointeiraentreaeb

a%b módulo Restodadivisãoentreaeb

a**b exponenciação aelevadoapotênciadeb

Ooperador+tambémfuncionacomstringsdeumamaneiradiferentedosnúmeros.Elefunciona

3.6STRINGS

.

Page 28: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

concatenandostrings,ouseja,juntandoduasstrings:

>>>texto1='oi'>>>texto2='Python'texto1+texto2oiPython

Ooperador*tambémfuncionacomstrings,multiplicandoseuconteúdoporuminteiro.Vamoschecaresseresultado:

>>>texto1='python'>>>texto1*3pythonpythonpython

Aomultiplicarpor 3 oPython replica a string três vezes.Strings possuemmuitas funcionalidadesprontaschamadasdemétodos.Ométodoupper(),porexemplo,retornaotextoemletrasmaiúsculas.Jáométodocapitalize()retornaotextocapitalizado(comaprimeiraletraemmaiúscula):

>>>texto1.upper()'PYTHON'

>>>texto1.capitalize()'Python'

Outrasfuncionalidadesdestringsestãopresentesnadocumentaçãoquepodeseracessadanestelink:https://docs.python.org/3/library/stdtypes.html#string-methods

Agora vamos criar mais interatividade e pedir para o usuário entrar com um valor digitado doteclado.

OPythonpossuiuma funçãoquecapturaa entradadevalores: a funçãoinput().Quando essafunçãoéchamada,oprogramaparaeesperaousuáriodigitaralgumacoisa.QuandoousuárioapertaateclaENTER,oprogramaprocessaeimprimeovalordigitadoemformadestring:

>>>entrada=input()'oipyhton'

>>>print(entrada)'oipython'

Masoidealépediralgoespecíficoaousuárioedizerqualdadoqueremosreceber.Podemospassarumastringparaafunçãoinput():

>>>nome=input("digiteseunome:\n")digiteseunome:caelum

>>>print(nome)caelum

O\nnofinalrepresentaumanovalinhaeointerpretadorvaiquebrarumalinhaapósimprimira

3.7ENTRADADOUSUÁRIO

.

Page 29: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

string.Porestemotivo,ovalordigitadopelousuárioaparecenapróximalinha.

Com o conteúdo aprendido até aqui já é possível começar a escrever o primeiro script. Crie umarquivoprograma2.pyeacrescenteumcódigoquevaipedirqueousuárioentrecomalgumvalore,emseguida,oprogramadeveimprimirestevalor.

Arquivoprograma2.py:

numero=input('Digiteumnúmero:\n')print(numero)

PodemosmelhorareimprimirumamensagemcomoOnúmerodigitadofoi:

numero=input('Digiteumnúmero:\n')print('Onúmerodigitadofoi'+numero)

Concatenamosastringcomavariávelnumeroutilizandoooperador+.Agora,seousuáriodigitaro número 2, a saída será O número digitado foi 2. Outra maneira mais elegante é usar a funçãoformat():

print('Onúmerodigitadofoi{}'.format(numero))

Afunçãoformat() vai substituiro{} pela variávelnumero.Aprincípio, podeparecerumaalternativa pior já que escrevemos mais código para conseguir o mesmo resultado. Mas a funçãoformat()fornecemaisfacilidades.Suponhaqueoprogramarecebadoisvaloresdigitadospelousuárioeosimprimaemumaúnicamensagem:

nome=input('Digiteseunome'+nome)idade=input('Digitesuaidade'+idade)print('Seunomeé{}esuaidadeé{}'.format(nome,idade))

Vejaqueessaformafacilitaaimpressãoeformataçãodosdadosumavezquenãoquebraastringemváriaspartescomoaconcatenaçãofaz.Alémdoque,comooperador+,sempretemosquelembrardosespaçoembrancoentreaspalavras:

print('Seunomeé'+nome+'esuaidadeé'+idade)

Nestecasoafunçãoformat()émaisrecomendadaefacilitanaimpressãodemensagensnatela.Agoraoscriptestámelhorepodemosexecutá-lopeloterminal:

dev@caelum:~$python3programa2.py

Asaída:

digiteseunome:caelumdigitesuaidade:20Seunomeécaelumesuaidadeé20

.

Page 30: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

PARASABERMAIS:AFUNÇÃOFORMAT()

Afunçãoformat() fazpartedeumconjuntode funçõesde formataçãodestrings chamadaFormatter. Para mais detalhes acesse a documentação:https://docs.python.org/3/library/string.html#string.Formatter.

Háoutrasfunçõesdeformataçãoeaformat()éaprincipaldelaseamaisutilizada.Podemospassarqualquertipodeparâmetroeelaéespecialmenteútilparaformatarnúmerospassandoseuformat code. Por exemplo, podemos arredondar o número flutuante 245.2346 para duas casasdecimaisatravésdocódigodeformatação:.2f:

>>>x=245.2346>>>print('{:.2f}'.format(x))245.23

O:.2fdizquequeremosapenasduascasasdecimaisparaavariávelx.Nadocumentaçãooficial do Python você acessa os códigos de formatação ou através da PEP 3101:https://www.python.org/dev/peps/pep-3101/.

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

OPython possui poucas constantes embutidas. Asmais utilizadas sãoTrue,False eNone. Essastambémsãopalavras chavesdoPython,portantopalavras reservadasquenãopodemosutilizar comonomesdevariáveis.

TrueeFalse são valoresbooleanos que representam, respectivamente,verdadeiro e falso.OPythontambémpossuiafunçãobool()queretornaTruequandooargumentopassadoéverdadeiroeretornaFalse,casocontrário.

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

3.8CONSTANTES

.

Page 31: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

PodemosrepresentarTrueeFalse atravésde expressões.Por exemplo "Onúmero1 é igual astring'1'?".VamosperguntaraoPython:

>>>1=='1'False

print(1=='1')

Ooperador==éusadoparaverificarsealgoéigualaoutro.Nãoconfundircomo=queatribuiumvaloraumavariável.Tambémpodemosverificarseumnúmeroémaior,utilizandoooperador>,oumenor(<)doqueoutro:

>>>2>1True

>>>2<1False

Podemostambémutilizarafunçãobool()parafazeraverificação:

>>>bool(3>5)False

>>>bool(1==1)True

Ocomandobool()nãorecebeapenasexpressões,elepodereceberqualquercoisaevairespondersetalvaloréconsideradoTrueouFalse:

>>>bool(0)False

>>>bool('')False

>>>bool(None)False

>>>bool(1)True

>>>bool(-100)True

>>>bool(13.5)True

>>>bool('teste')True

>>>bool(True)True

Repare que a função resulta False em strings vazias, quando um número é zero ou quando éNone.Aindanão falamosoqueoNone representa.ÉumvalordotipoNoneType e é usadopararepresentar a abstençãodeumvalor - comoquandoumargumentopadrãonão é passadopara umafunção(queveremosemoutrocapítulo).

.

Page 32: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

type(None)<class'NoneType'>

EmoutraslinguagensdeprogramaçãoécomumutilizarapalavraNullpararepresentaraabstençãodevalor.ParaprogramadoresmaisexperientesecomalgumconhecimentoemlinguagenscomoJavaeC#,éimportanteobservarquediferentedoNull,oNoneocupaespaçonamemória,éumobjetocomreferência.

No exemplo acima foramutilizados três operadoresdiferentesdaqueles já vistos anteriormente: o== (igual),o> (maiordoque) eo< (menordoque).Estes operadoresnão são aritméticos, sãoconhecidosporoperadoresdecomparação.OPythonpossuimaisoperadoresdestetipo:

Operação Descrição

a==b aigualab

a!=b adiferentedeb

a<b amenordoqueb

a>b amaiordoqueb

a<=b amenorouigualab

a>=b amaiorouigualab

Outrosoperadoresqueretornamvaloresbooleanossão:

Operação Descrição

aisb Trueseaebsãoidênticos

aisnotb Trueseaebnãosãoidênticos

ainb Trueseaémembrodeb

anotinb Trueseanãoémembrodeb

Éimportantesaberqueosoperadores==eis funcionamdemaneiradiferente.Vamosusar oexemplodeduaslistasechecarseelassãoiguais:

>>>x=[1,2,3]>>>y=[1,2,3]>>>x==yTrue

>>>xisyFalse

Ooperador==checaseoconteúdodasvariáveissãoiguaiseseucomportamentopodevariardeinterpretador para interpretador - o exemplo acima é o comportamento padrão do CPython. Já ooperadorischecaseaebsãoomesmoobjeto.Falaremosdeobjetosemumoutrocapítulo,maséimportante ter emmente que tudo em Python é um objeto e cada objeto possui uma referência namemória.Ooperadorisvaichecarexatamentesexeysãoomesmoobjeto,ouseja,sepossuema

.

Page 33: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

mesmareferência.

Esequisermosapresentarumamensagemdiferenteparaousuáriodependendodovalordeentrada?Vamos atribuir um valor para uma variável numero e pedir para o usuário entrar com um valor.Devemos verificar se os valores são iguais como um jogo de adivinhação em que o usuário deveadivinharonúmerodefinido.

numero=42chute=input('Digiteumnúmero:')

Atéaqui,nenhumanovidade.Agoradevemosmostraramensagem"Vocêacertou"casoonumeroseja igualaochute, e "Você errou" casoonumero seja diferentedochute. Emportuguês, seriaassim:

Sechuteigualanúmero:"Vocêacertou"Sechutediferentedenúmero:"Vocêerrou"

Oumelhor:

Sechuteigualanúmero:"Vocêacertou"Senão:"Vocêerrou"

Podemos traduzir isso para código Python. O Python possui o operador condicional pararepresentarapalavrasequeéoifeapalavrasenãoqueéoelse.Asintaxeficaria:

ifchute==numero:print('Vocêacertou')else:print('Vocêerrou')

EstecódigoaindanãofuncionaporqueoPythonentendeasinstruçõesifeelsecomoblocoseosblocosdevemseguirumaindentação.Comoprint('Vocêacertou') éa instruçãoquedeveserexecutadacasoaverificaçãodoif sejaverdadeira,devemos terumrecuoparaadireita emquatrosespaços:

ifchute==numero:print('Vocêacertou')else:print('Vocêerrou')

Casocontrário,ointerpretadorvaiacusarerrodesintaxe.Dessamaneiraocódigoficamaislegíveleoqueemoutraslinguagenséumaescolhadoprogramador,oPythonteobrigaafazer-forçando,destamaneira, a organizar o código.Tudoque estiver no blocoda primeira condição (doif) deve estarindentado,ouseja,recuadoparadireita.Assimcomoasinstruçõesqueestiveremnoblocodoelse.

Nofim,nossoprograma,quesalvaremosemumarquivochamadoadivinhacao.pyfica:

numero=42chute=input('Digiteumnúmero:')

3.9COMANDOIF

.

Page 34: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

ifchute==numero:print('Vocêacertou')else:print('Vocêerrou')

Eexecutamosnoterminal:

dev@caelum:~$python3adivinhacao.pyDigiteumnúmero:25Vocêerrou

Notequeacondiçãodeumifdeveserumbooleano,ouseja,TrueouFalse.Passamosaexpressãochute==numeroquevaichecarseelaéverdadeiraounão.Casosejaverdadeira,vaiexecutarocódigodentrodoblocodoif,senão,vaiexecutarocódigodentrodoelse.Agoravamoschutaronúmero42everificarsetudoestáfuncionando:

dev@caelum:~$python3adivinhacao.pyDigiteumnúmero:42Vocêerrou

Algodeerradoaconteceu!Digitamosonúmerocorretoemesmoassimoprogramanãofuncionoucomoesperado.Vamosentenderoqueaconteceu.

Afunçãoinput()lêovalordigitadopelousuáriocomoumastring.

chute=input('Digiteumnúmero:')

Seousuáriodigitaronúmero42,avariávelchutevaiguardarovalor"42",ouseja,umtexto.Podemoschecar issoatravésda funçãotype() que retornao tipodavariável.Vamos testar issonoterminal:

>>>chute=input('Digiteumnúmero:')Digiteumnúmero:42>>>type(chute)<class'str'>

Agora fica mais claro porque o programa não está funcionando como o esperado. Quando ointerpretadorverificarchute==numero vai retornarFalse já que"42" (texto) é diferentede 42(número).

Parafuncionar,precisamosconverterastring"42"paraumnúmerointeiro.Ointtambémfuncionacomoumafunção(maisparafrenteentenderemosquenãoérealmenteumafunção)quepodereceberumastringeretornarointeirocorrespondente:

>>>numero_em_texto='12''12'>>>type(numero_em_texto)<class'str'>

3.10CONVERTENDOUMASTRINGPARAINTEIRO

.

Page 35: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>numero=int(numero_em_texto)12>>>type(numero)<class'int'>

Masdevemostomarcuidado,nemtodastringpodeserconvertidaparaumnúmerointeiro:

>>>texto='caelum'>>>numero=int(texto)Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>ValueError:invalidliteralforint()withbase10:'caelum'

OinterpretadoracusaumValueErrordizendoqueovalorpassadoparaint()éinválido,ouseja,éumtextoquenãorepresentaumnúmerointeiro.

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Podemosmelhoraraindamaisojogo:casoochutenãosejaigualaonúmerosecreto,podemosdarumapistaparaousuárioseelefoimaioroumenordoqueochuteinicial.Ouseja,devemosacrescentaressetratamentocasoousuárioerreochute:

Sechute=número:"Vocêacertou!"Senão:Sechutemaiordoquenúmero_secreto:"Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto"Senão"Vocêerrou!Oseuchutefoimenorqueonúmerosecreto"

JásabemostraduzirissoparaPython:

if(chute==numero_secreto):print('Vocêacertou!')else:if(chute>numero_secreto):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')

Seuslivrosdetecnologiaparecemdoséculopassado?

3.11OCOMANDOELIF

.

Page 36: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

else:print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

Masnestecasopodemosfazerumelsecomumacondiçãodeentrada,oelif.Vamosutilizá-loparadeixarocódigomaissemântico,jáquenapráticanãohádiferença:

if(numero_secreto==chute):print('Vocêacertou!')elif(chute>numero_secreto):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(chute<numero_secreto):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

Podemos melhorar ainda mais a legibilidade do código para que os outros programadores, quepodemajudaradesenvolvê-lonofuturo,entendammelhor.Vamosdeixarnossascondiçõesmaisclaras.chute==numero_secreto quer dizer que o usuário acertou. Então, extraímos essa condiçãoparaumavariável:

acertou=chute==numero_secreto

if(acertou):print('Vocêacertou!')

#restantedocódigo

Avariávelacertouguardaumaexpressãoe,portantoédotipobooleano epodemosusarcomocondiçãonocomandoif.Agoraacondiçãoifficaumpoucomaisclara.Vamosfazeramesmacoisaparaasoutrasduascondições:

acertou=chute==numero_secretomaior=chute>numero_secretomenor=chute<numero_secreto

if(acertou):print('Vocêacertou!')elif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

1. Crieumarquivochamadoadivinhacao.pyemumapastachamadajogosdentrododiretóriohome:

|_home|_jogos|_adivinhacao.py

2. Abra o arquivo no editor de texto de sua preferência e comece a escrever um cabeçalho para ousuáriosaberdoquesetrataoprograma:

print('******************************')print('*Jogodaadivinhação*')print('******************************')

3.12EXERCÍCIOS-JOGODAADIVINHAÇÃO

.

Page 37: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

3. Vamosdefiniravariávelnumero_secretoquevaiguardarovaloraseradivinhadopelousuário:

print('******************************')print('*Jogodaadivinhação*')print('******************************')

numero_secreto=42

4. Captureaentradadousuáriousandoafunçãoinput():

print('******************************')print('*Jogodaadivinhação*')print('******************************')

numero_secreto=42

chute=input('Digiteoseunúmero:')print('Vocêdigitou:',chute)

5. Compareovalordigitadopelousuáriocomonumero_secreto.Seosvaloresforemiguaismostreumamensagemdeacerto,casocontrário,mostreumamensagemdeerro:

print('******************************')print('*Jogodaadivinhação*')print('******************************')

numero_secreto=42

chute=input('Digiteoseunúmero:')print('Vocêdigitou:',chute)

if(numero_secreto==chute):print('Vocêacertou!')else:print('Vocêerrou!')

6. Rodeocódigoacimapeloterminaletesteojogochutandoonúmero42:

dev@caelum:~$python3jogos/adivinhacao.py

7. O chute42não funciona comoesperado.Esquecemosde convertero chutedigitadopelousuárioparaumnúmerointeiro.Modifiqueocódigoeutilizea funçãoint()para recebera entradadousuário:

chute=int(input('Digiteoseunúmero:'))

8. Rodeocódigonovamentecomaentradaiguala42evejaqueagorafuncionacomoesperado.

9. Vamosapresentarumapistaparaousuárioeimprimirumamensagemdizendoseochutefoimaioroumenordoqueonúmerosecreto.Paraissousaremosoelif:

if(numero_secreto==chute):print('Vocêacertou!')elif(chute>numero_secreto):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(chute<numero_secreto):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

.

Page 38: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

10. Agoravamosmelhoraralegibilidadedocódigoextraindoascondiçõesparavariáveis:

acertou=chute==numero_secretomaior=chute>numero_secretomenor=chute<numero_secreto

if(acertou):print('Vocêacertou!')elif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

11. Rodeoprogramaetestecomtodasassituaçõespossíveis.

Queremosdarmaisdeumaoportunidadeparaousuáriotentaracertaronúmerosecreto, jáqueéumjogodeadivinhação.Aprimeiraideiaérepetirocódigo,desdeafunçãoinput()atéoblocodoelif. Ou seja, para cada nova tentativa que quisermos dar ao usuário, copiaríamos esse códigonovamente.

Só que copiar código sempre é umamá prática, queremos escrever o código apenas uma vez. Sequeremosrepetirocódigo,fazemosumlaço,ouumloop,quedeverepetirainstruçãodentrodeblocoenquantoelaforverdadeira.Olaçoquedevemosfazeré:

Enquantoaindahátentativas,faça:chute_str=input('Digiteoseunúmero:')print('Vocêdigitou:',chute_str)chute=int(chute_str)

acertou=numero_secreto==chutemaior=chute>numero_secretomenor=chute<numero_secreto

if(acertou):print('Vocêacertou!')elif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

print('FimdoJogo!')

Como dito anteriormente, o Python não entende português e assim como o if ele tem umcomandoquesubstituiráapalavraenquantodonossoexemplo.Owhileéessecomandoque,assimcomooif,recebeumacondição.Adiferençaéqueoif, casoacondiçãosejaverdadeira,executaapenasumavezocódigodeseubloco, jáowhileexecutaenquanto a condição for verdadeira, porexemplo:

x=5enquantoxformaiordoque1,faça:imprime(x)x=x-1

3.13COMANDOWHILE

.

Page 39: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

QueemPython,éequivalentea:

>>>x=5>>>while(x>1):...print(x)...x=x-15432

Mastomecuidado,oqueaconteceseesquecermosessalinhadocódigox=x-1?

>>>x=5>>>while(x>1):...print(x)55555...

Oprogramavaiimprimironúmero5infinitamente,jáqueacondiçãopassadaésempreverdadeiraenãomudadentrodobloco.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

1. Daremosaousuáriodo jogoumnúmeromáximodetentativas.Abraoarquivoadivinhacao.py napasta jogos e inicie a variável total_de_tentativas com 3 e acrescente o bloco do comandowhile:

numero_secreto=42total_de_tentativas=3

while(aindahátotal_de_tentativas):#executaocódigo

Agoraéamelhorhoradeaprenderalgonovo

3.14EXERCÍCIOS-JOGOCOMWHILE

.

Page 40: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

2. Restaagoraaexpressãoaindahá.Aideiaéqueousuáriotenha3tentativas,representadanocódigopela variáveltotal_de_tentativas. A cada rodada subtraímos 1 do valor dessa variável, até ovalorchegara0,queéquandodevemossairdowhile.Logo,vamosexecutá-loenquantoavariáveltotal_de_tentativasformaiordoque0:

numero_secreto=42total_de_tentativas=3

while(total_de_tentativas>0):chute=int(input('Digiteoseunúmero:'))print('Vocêdigitou:',chute)

acertou=chute==numero_secretomaior=chute>numero_secretomenor=chute<numero_secreto

if(acertou):print('Vocêacertou')elif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

total_de_tentativas=total_de_tentativas-1

OBS:Nãoesqueçadeindentarocódigodentrodoblocowhileparanãorecebererrodesintaxe.

3. Alémdastentativas,podemosapresentarqualonúmerodarodadaqueousuárioestájogandoparadeixarclaroquantastentativaseletêm.Paraissovamoscriaravariávelrodada,quecomeçacomovalor1:

total_de_tentativas=3rodada=1

4. Evamosimprimi-laantesdousuáriodigitaroseuchute:

total_de_tentativas=3rodada=1

while(total_de_tentativas>0):print('Tentativa{}de{}'.format(rodada,total_de_tentativas))chute=int(input('Digiteoseunúmero:'))print('Vocêdigitou:',chute)

#restantedocódigoaqui

5. Eparaavariáveltotal_de_tentativascontinuarcomovalor3,nãovamosmaissubtrair1doseuvalor,esimadicionar1aovalordavariávelrodada:

total_de_tentativas=3rodada=1

while(total_de_tentativas>0):print('Tentativa{}de{}'.format(rodada,total_de_tentativas))

chute=int(input('Digiteoseunúmero:'))print('Vocêdigitou:',chute)

.

Page 41: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

acertou=numero_secreto==chutemaior=chute>numero_secretomenor=chute<numero_secreto

if(acertou):print('Vocêacertou!')elif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

rodada=rodada+1

print('Fimdojogo')

6. Por fim,precisamosmodificar a condição. Já queototal_de_tentativas permanecerá com ovalor3,ocódigoprecisaficarexecutandoenquantoovalordarodadaformenorouigualaototaldetentativas:

total_de_tentativas=3rodada=1

while(rodada<=total_de_tentativas):print('Tentativa{}de{}'.format(rodada,total_de_tentativas))chute_str=input('Digiteoseunúmero:')

#restantedocódigo

Agoraconseguimosimprimirparaousuárioquantastentativasrestanteselepossui!Testechamandoseuarquivoadivinhacao.pycomocomando'python3'.

7. Falta arrumar uma coisa: quando o usuário acerta, o jogo continua pedindo um novo chute.Queremosterminaraexecuçãodoprogramaquandoousuárioacerta.Paraissousamosocomandobreak.Quandoointerpretadorencontrarocomandobreakeleparaaexecuçãodoprograma.vamosacrescentar issoquandoousuário acertar, ou seja,noprimeiro comandoif após a exibiçãodamensagemdeacerto:

if(acertou):print('Vocêacertou!')breakelif(maior):#restantedocódigo

8. Testeoprogramaevejasetudoestáfuncionandocomooesperado.

Ainda no código do jogo da adivinhação, implementamos o loop while, no qual temos umavariávelrodadaquecomeçacomovalor1,eéincrementadadentrodoloop,queporsuaveztemumacondiçãodeentrada,queéarodadasermenorouigualaototaldetentativas,queé3.

Ouseja,arodadatemumvalorinicial,queé1,evaiaté3.Fazemosumlaçocomeçandocomum

3.15COMANDOFOR

.

Page 42: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

valorinicial,atéumvalorfinal,sempreincrementandoessevaloracadaiteração.Masseesquecermosdeincrementararodada,entramosemumloopinfinito.

Em casos como esse, existe um outro loop que simplifica essa ideia de começar com um valor eincrementá-loatéchegaremumvalorfinal:oloopfor.

Paraentenderoloop,oulaçofor,podemosiratéoconsoledoPythonparaveroseufuncionamento.A ideia é definirmos o valor inicial e o valor final, que o loop o incrementa automaticamente. Paradefinir o valor inicial e final, utilizamos a função embutida range(), passando-os por parâmetro,definindoassimasériedevalores.Asintaxeéaseguinte:

Paravariávelemumasériedevalores:Façaalgo

Isso,emPython,podeficarassim:

forrodadainrange(1,10):

Orange(1,10)vaigerarointervalodenúmerosinteirosde1a9.Naprimeiraiteração,ovalordavariávelrodada será 1, depois 2 e até chegar ao valor final da funçãorange()menos 1, isto é, osegundoparâmetrodafunçãonãoéinclusivo.Noexemploacima,asériedevaloreséde1a9.PodemosconfirmarissoimprimindoovalordavariávelrodadanoconsoledoPython:

>>>forrodadainrange(1,10):...print(rodada)...123456789

Comafunçãorange()podemosdefinirumstep(umpasso),queéointervaloentreoselementos.Porpadrãoostep temvalor iguala1maspodemosalterarestevalorpassandoumterceiroparâmetroparaafunção:

>>>forrodadainrange(1,10,2):...print(rodada)...13579

Vejaqueointervaloentrecadaelementodasériaagoraé2,acadaiteraçãoolaçopuladoispassos(incrementa2).Masnãonecessariamenteprecisamosusarafunçãorange()nofor,podemospassarosvaloresdasequênciamanualmenteconseguindoomesmoresultado:

.

Page 43: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>forrodadain[1,2,3,4,5]:...print(rodada)...12345

Tantoowhilequantooforpodemserusadosnojogo.Conseguiremosomesmoresultadomasocódigoficamaisverbosocomowhile,alémdecorrermosoriscodeesquecerdeincrementararodada(rodada=rodada+1)enossocódigoentraremumloopinfinito.Nestecasos,épreferívelutilizarocomandofor.

1. Substituaocomandowhilepeloforcomeçandono1eindoatéototal_de_tentativas.Nãoesqueçaderemoveradeclaraçãodavariávelrodadaeoseuincrementodentrodoloop:

numero_secreto=42total_de_tentativas=3

forrodadainrange(1,total_de_tentativas):print('Tentativa{}de{}'.format(rodada,total_de_tentativas))

chute=int(input('Digiteoseunúmero:'))print('Vocêdigitou:',chute)

acertou=numero_secreto==chutemaior=chute>numero_secretomenor=chute<numero_secreto

if(acertou):print('Vocêacertou!')elif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')

print('Fimdojogo!')

2. Éimportantesaberqueofornãoéobrigadoaterparênteses.Podemostestareverqueoprogramadáapenas2tentativas.Issoporque,comofoifaladoanteriormente,osegundoparâmetrodafunçãorange não é inclusivo, no caso do nosso jogo, range(1,3) irá gerar a série 1 e 2 somente.Portanto,vamossomar1aototal_de_tentativasdentrodafunçãorange:

forrodadainrange(1,total_de_tentativas+1):

3. Testenovamenteojogoevejaquetudoestáfuncionandoperfeitamente!

4. (opcional)Crieumníveldedificuldadeparaojogo.Crieumavariávelchamadanívelepeçaparaousuário escolher emqualnível ele deseja jogar.Onível émensurável de acordo como total detentativas:nível1(tentativas=20),nível2(tentativas=10)enível3(tentativas=5).

3.16EXERCÍCIOS-UTILIZANDOOFORNOJOGO

.

Page 44: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

5. (opcional)Acrescenteumtotaldepontosaojogadorquedeveiniciarcom1000eacadachuteerradodevesersubtraídodototaldepontosumvalorquecorrespondeadiferençaentreochuteeonúmerosecreto.Paraesteexercíciovocêvaiprecisardafunçãoabs().VejanadocumentaçãodoPythoncomoelafunciona.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

EditoraCasadoCódigocomlivrosdeumaformadiferente

.

Page 45: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO4

Nocapítulopassadocriamosojogodaadivinhação,agoravamoscriarojogodaForca.Vamoscomeçar,com os conhecimentos que temos até aqui, para estruturar nosso jogo. Vamos criar um arquivochamadoforca.pynapastajogos:

|_home|_jogos|_adivinhacao.py|_forca.py

Como no jogo da adivinhação, devemos adivinhar uma palavra secreta, nada mais justo do quedefini-laemumavariável.Porenquanto,apalavraseráfixa,comovalorbanana:

print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

palavra_secreta='banana'

print('Fimdojogo')

Maisàfrentedeixaremosessapalavrasecretamaisdinâmica.

Como estamos tratandodeum jogoda forca, o usuário deve acertar umapalavra e chutar letras.Além disso, precisa saber se o usuário acertou ou errou e saber se foi enforcado ou não. Entãoprecisaremosde2variáveisbooleanasenforcoueacertou para guardar esta informação e o jogocontinuaráatéumadelasforTrue;paratalacrescentamosumlaçowhile:

acertou=Falseenforcou=False

while(notacertouandnotenforcou):print('Jogando...')

Ousuáriodojogotambémvaichutarletras.Alémdisso,seochuteforigualaumaletracontidanapalavra_secreta,querdizerqueousuárioencontrouumaletra.Podemosutilizarumlaçoforparatratarisso,assimcomofizemosnojogodaadivinhaçãoparaapresentarastentativaserodadas:

while(notacertouandnoterrou):chute=input('Qualletra?')

posicao=0forletrainpalavra_secreta:if(chute==letra):print('Encontreialetra{}naposição{}'.format(letra,index))

ESTRUTURADEDADOS

.

Page 46: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

posicao=posicao+1

print('Jogando...')

Comoumastringéumasequênciadeletras,oloopforvaiiterarporcadaletra.

Nossapalavra_secretaé'banana'.Eseousuáriochutaraletra'A'aoinvésde'a'?Vamostestar:

>>>$python3jogos/forca.py************************************BemvindoaojogodaForca!************************************Qualletra?AJogando...Qualletra?

OPythonécase-sensitive,ouseja'a'e'A'sãodistintosparaointerpretador.Seráprecisoacrescentarestetratamentoefazerojogoaceitarcomoacertotanto'a'como'A'.String(str)éumtipoembutidonoPythonquepossuialgumasfunçõesprontaseumadelasvainosajudarnesteproblema.

Existe uma função chamada upper() que devolve uma string com todas as letras maiúsculas.Tambémpossuialower()quedevolveumastringcomtodasasletrasminúsculas:

>>>texto='python'>>>texto.upper()'PYTHON'>>>>>>texto='PYTHON'>>>texto.lower()'python'

Agora precisamos modificar a condição chute == letra do if para chute.upper() ==

letra.upper():

if(chute.upper()==letra.upper()):print('Encontreialetra{}naposição{}'.format(letra,index))

Dessamaneira,o jogadorpode chutar tanto 'a' como 'A'queo tratamentodoif vai considerartodascomomaiúsculas.

Agorapodemostestarnovamentecomchuteiguala'A'(ou'a')evemosoprogramafuncionarcomooesperado:

************************************BemvindoaojogodaForca!************************************Qualletra?AEncontreialetraanaposição1Encontreialetraanaposição3Encontreialetraanaposição5Jogando...Qualletra?

Atualmente,jádizemosaojogadoremqueposiçãoaletraqueelechutouestánapalavrasecreta,casoaletraexistanapalavra.Masemumjogorealdeforca,ojogadorvêquantasletrashánapalavrasecreta.

.

Page 47: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Algocomo:

Qualletra?______

Eseeleencontraralgumaletra,amesmatemasualacunapreenchida.Aodigitaraletra"a",ficaria:

_a_a_a

Muito mais intuitivo, não? Vamos implementar essa funcionalidade. Para exibir as letras dessaforma,precisamosguardaroschutescertosdousuário,mascomofazerisso?

Paratal,oPythonnosofereceumtipodeestruturadedadosquenospermiteguardarmaisdeumvalor.Essaestruturaéalist(lista).Paracriarumalista,utilizamoscolchetes([]):

>>>valores=[]>>>type(valores)<class'list'>

Assimcomoa string,list tambéméuma sequênciadedados.Podemos ver suadocumentaçãoatravésdafunçãohelp():

>>>help(list)Helponclasslistinmodulebuiltins:classlist(object)|list()->newemptylist|list(iterable)->newlistinitializedfromiterable'sitems||Methodsdefinedhere:||__add__(self,value,/)|Returnself+value.||__contains__(self,key,/)|Returnkeyinself.||__delitem__(self,key,/)|Deleteself[key].||__eq__(self,value,/)|Returnself==value.||__ge__(self,value,/)|Returnself>=value.

#códigoomitido

Vemosoquepodemos fazer comuma lista.Podemos,por exemplo, verificaro seuvalormínimocommineoseumáximocommax.Nossalistaaindaestávaziamasjápodemosiniciá-lacomalgunsvaloreseutilizaressasfunçõesparaverificaroseusvaloresmáximoemínimo:

>>>valores=[0,1,2,3]>>>min(valores)0>>>max(valores)3

Para acessar um valor específico, podemos acessá-lo através do seu índice (posição). O primeiro

.

Page 48: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

elementodalistapossuiíndice0,osegundopossuiíndice1eassimpordiante:

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

Paramodificarumvalor,bastausarooperadordeatribuiçãoemumadeterminadaposição:

>>>valores[0]=4>>>valores[4,1,2,3]

É possível saber o tamanho da lista com a função len e verificar se determinado valor estáguardadonelacomocomandoin:

>>>valores=[0,1,2,3]>>>len(valores)4>>>0invaloresTrue>>>6invaloresFalse

Além disso, existem funções específicas da lista, que podem ser acessadas na documentação:https://docs.python.org/3.6/library/stdtypes.html#mutable-sequence-types.

Podemos adicionar elementos ao final da lista com a função append(), exibir e remover umelementodedeterminadaposiçãocomafunçãopop(),entrediversasoutrasfuncionalidades.

Agoraquesabemoscomoguardarvaloresemumalista,podemosvoltaraonossojogoeguardarosacertosdousuário.Comoqueremosexibirosespaçosvaziosprimeiro,criaremosumalistacomeles,namesmaquantidadedeletrasdapalavrasecreta:

palavra_secreta='banana'letras_acertadas=['_','_','_','_','_','_']

Já temos a posição da letra (também chamado de índice). Logo, caso o chute seja correto, bastaguardaraletradentrodalista,nasuaposiçãocorretaeimprimiralistaapósolaçofor:

posicao=0

forletrainpalavra_secreta:if(chute.upper()==letra.upper()):letras_acertadas[posicao]=letraposicao=posicao+1

print(letras_acertadas)

Ouseja,paracadaletranapalavrasecreta,oprogramavaiverificarsechuteéigualaletra.Emcasoafirmativo,adicionaaletranaposiçãocorretaeincrementaaposicaoapósoblocodoif.

Aoexecutarojogoechutaralgumasletras,temos:

.

Page 49: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

$python3jogos/forca.py************************************BemvindoaojogodaForca!************************************Qualletra?b['b','_','_','_','_','_']Jogando...Qualletra?a['b','a','_','a','_','a']Jogando...Qualletra?

Asaídaaindanãoestávisualmenteagradável.Paraficaraindamelhor,vamosexibiralistanoiníciodojogotambémeexcluiroprint('Jogando...')paraocódigoficarmaislimpo.

print(letras_acertadas)

while(notacertouandnoterrou):chute=input('Qualletra?')

#códigoomitido

Nesteexercício,vamosaproveitarnossonovoconhecimentoemlistasparafazercomqueojogodaforcaselembredasletrasacertadaspelojogador.

1. Crieumarquivochamadoforca.pynapastajogos:

|_home|_jogos|_adivinhacao.py|_forca.py

2. Primeiro,precisamosmostrarparao jogadoramensagemdeabertura, similar aoque foi feitonojogodaadivinhação:

print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

3. Crieavariávelpalavra_secretaqueseráiniciadacomovalor'banana'eumalistapararepresentarasletrasacertadas.

palavra_secreta='banana'letras_acertadas=['_','_','_','_','_','_']

4. Crieasvariáveisbooleanasacertoueerrou que vamosutilizarno laçowhile. E a variávelerrosqueguardaremosonúmerodeerrosdousuário:

acertou=Falseenforcou=Falseerros=0

while(notacertouandnotenforcou):#código

4.1EXERCÍCIOS:JOGODAFORCA

.

Page 50: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

5. Crieavariávelchutequevaiguardarentradadousuário.

while(notacertouandnotenforcou):chute=input('Qualletra?')

6. Dentrodowhilecrieum loopforparaquevaichecarsea letraexistenapalavrasecreta.Seochute for igual a letra digitada pelo jogador, vamos adicionar a letra na nossa listaletras_acertadasnaposiçãocorreta

while(notacertouandnotenforcou):chute=input('Qualletra?')

posicao=0forletrainpalavra_secreta:if(chute==letra):letras_acertadas[posicao]=letraposicao+=1

7. Modifique a condição do if para considerarmos apenas letras maiúsculas utilizando a funçãoupperdestrings.Eatualizeavariávelchute

if(chute.upper()==letra.upper()):

8. Agoraprecisamosincrementaravariávelerros casoo jogadornãoacertea letra.Seochuteéumaletradentrodepalavra_secreta,querdizerqueo jogadoracertou,casocontrário incrementamosavariávelerros.Paraisso,teremosmaisumblocoif/else:

if(chuteinpalavra_secreta):posicao=0forletrainpalavra_secreta:if(chute.upper()==letra.upper()):letras_acertadas[index]=letraposicao+=1else:erros+=1

9. Atualizeavariávelacertou.Setodasasletrasaindanãoforamacertadas,querdizerqueousuárioainda não finalizou o jogo, ou seja, letrasacertas ainda contém espaços vazios (''). Dentro o loopwhile,apósocomandofor,vamosatualizaravariávelacertoueutilizarooperadornotin:

acertou='_'notinletras_acertadas.

Podemoslerocódigoacimacomo"'_'nãoestácontidoemletras_acertadas".

10. Vamostambématualizaravariávelenforcou.Vamosconsiderarqueseojogadorerrar7vezeseleperde o jogo.Como a variável inicia com0 (zero), quer dizer que quando ela for igual a 6 ele seenforca.Atualizeavariáveldentrodoloopwhileapósavariávelacertou:

acertou="_"notinletras_acertadas.enforcou=erros==6

11. Paraqueojogadoracompanheoresultadoacadachutequeeleder,aofinaldolaçowhileimprimatambémalistaletras_acertadasparaqueelevejacomoeleestáindonojogo:

.

Page 51: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

while(notenforcouandnotacertou):

#códigoomitido

print(letras_acertadas)

12. Eclaro,paradarumadicaaonossojogadordequantasletrasapalavratem,vamoscolocaracimadowhileumprintinicialparaqueelevejadeinícioqualotamanhodapalavra:

print(letras_acertadas)

while(notacertouandnotenforcou):...

13. Porfim,vamosimprimirumamensagemde"Vocêganhou!"seousuárioadivinharaletrae"Vocêperdeu"casotenhacometido7erros.Apósolaçowhile,foradele,acrescente:

if(acertou):print('Vocêganhou!!')else:print('Vocêperdeu!!')

print('Fimdojogo')

14. Façaotesteevejanarespostaseseucódigofuncionando.

$python3jogos/forca.py

Nofinal,seucódigodeveestarparecidocomeste:

defjogar():print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

palavra_secreta='banana'letras_acertadas=['_','_','_','_','_','_']

enforcou=Falseacertou=Falseerros=0

print(letras_acertadas)

while(notenforcouandnotacertou):

chute=input("Qualletra?")

if(chuteinpalavra_secreta):posicao=0forletrainpalavra_secreta:if(chute.upper()==letra.upper()):letras_acertadas[posicao]=letraposicao=index+1else:erros+=1

enforcou=erros==6acertou='_'notinletras_acertadasprint(letras_acertadas)

.

Page 52: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

if(acertou):print('Vocêganhou!!')else:print('Vocêperdeu!!')print('Fimdojogo')

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

DesenvolvemosumnovojogoeconhecemosumnovotipodedadodoPythonquesãoaslistas.UmalistaéumasequênciadevaloreseoPythonpossuioutrostiposdedadosquetambémsãosequências.Nestemomento,conheceremosumpoucodecadaumadelas.

Sequênciassãocontainers,umtipodedadoquecontémoutrosdados.Existemtrêstiposbásicosdesequência:list(lista),tuple(tupla)erange(objetodeintervalo).Outrotipodesequênciafamosoquejávimossãoasstringsquesãosequênciasdetexto.

Sequências podem ser mutáveis ou imutáveis. Sequências imutáveis não podem ter seus valoresmodificados.Tuplas,stringserangessãosequênciasimutáveis,enquantolistassãosequênciasmutáveis.

As operações na tabela a seguir são suportadas pela maioria dos tipos de sequência, mutáveis eimutáveis.Natabelaabaixo,setsãosequênciasdomesmotipo,n,i,jeksãointeirosexéumobjetoarbitrárioqueatendeaqualquertipoerestriçõesdevalorimpostaspors.

Operação Resultado

xins Trueseumitemdeséigualax

xnotins Falseseumitemdeséigualax

s+t Concatenaçãodeses

snouns Equivalenteaadicionarsasimesmonvezes

s[i] Elementonaposiçãoides

EditoraCasadoCódigocomlivrosdeumaformadiferente

4.2SEQUÊNCIAS

.

Page 53: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

s[i:j] Fatiasdeiparaj

s[i:j:k] Fatiasdeiparajcomopassok

len(s) Comprimentodes

min(s) Menoritemdes

max(s) Maioritemdes

s.count(x) Númerototaldeocorrênciasdexems

Listas

Umalistaéumasequênciadevaloresondecadavaloréidentificadoporumíndiceiniciadopor0.Sãosimilaresastrings(coleçãodecaracteres)excetopelofatodequeoselementosdeumalistapodemserdequalquertipo.Asintaxeésimples,listassãodelimitadasporcolcheteseseuselementosseparadosporvírgula:

>>>lista1=[1,2,3,4]>>>lista1[1,2,3,4]>>>>>>lista2=['python','java','c#']>>>lista2['python','java','c#']

Oprimeiro exemplo éuma lista com4 inteiros,o segundoéuma lista contendo três strings.Maslistasnãoprecisamnecessariamenteconterelementosdemesmotipo.Podemosterlistasheterogêneas:

>>>lista=[1,2,'python',3.5,'java']>>>lista[1,2,'python',3.5,'java']

Nossalistapossuielementosdotipoint,floatestr. Se queremos selecionarumelementoespecíficoutilizamosooperador[]passandoaposição:

>>>lista=[1,2,3,4]>>>lista[0]1>>>lista[1]2>>>lista[2]3>>>lista[3]4>>>lista[4]Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>IndexError:listindexoutofrange

Quandotentamosacessaraposição4fazendolista[4],apareceoerroIndexErrordizendoquealistaexcedeuseulimitejáquenãoháumquintoelemento(índice4).

OPythonpermitepassarvaloresnegativoscomoíndicequevaidevolverovalornaquelaposiçãodeformareversa:

.

Page 54: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>lista=[1,2,3,4]>>>lista[-1]4>>>lista[-2]3

Também é possível usar a funçãolist() para criar uma lista passando um tipo que pode seriterávelcomoumastring:

>>>lista=list('python')>>>lista['p','y','t','h','o','n']

Listassãomuitoúteis,porexemplo:

meses=['Janeiro','Fevereiro','Março','Abril','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro']

n=1

while(n<4):mes=input("Escolhaummês(1-12):")if1<=mes<=12:print('Omêsé{}'.format(mes[mes-1]))n+=1

Etestamos:

>>>Escolhaummês(1-12):4OmêséAbril>>>Escolhaummês(1-12):11OmêséNovembro>>>Escolhaummês(1-12):6OmêséJunho

Primeiro criamos um lista, relacionamos seus índices com os meses do ano, recuperamos seusvaloresatravésdaentradadousuárioe imprimimosnatelaomêsescolhido(mes[mes-1]) indexadoalistaapartirdozero.Usamosumlaçowhilequefaznossoprogramaentrarem loopeserrodado3vezes.

Alémdeacessarumvalorespecíficoutilizandooíndice,podemosacessarmúltiplosvaloresatravésdofatiamento.Tambémutilizamoscolchetesparaofatiamento.Suponhaquequeremosacessarosdoisprimeiroselementosdeumalista:

>>>lista=[2,3,5,7,11]>>>lista[0:2][2,3]

Podemosteromesmocomportamentofazendo:

>>>lista[:2][2,3]

Sequeremostodososvaloresexcluindoosdoisprimeiros,fazemos:

>>>lista[2:][5,7,11]

.

Page 55: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Ouutilizamosínidcesnegativos:

>>>lista[-3:][5,7,11]

Tambémpodemosfatiarumalistademodoapegarelementosemumintervaloespecífico:

>>>lista[2:4][5,7]

As listas também possuem funcionalidades prontas e podemos manipulá-las através de funçõesembutidas.Alistatemumafunçãochamadaappend()queadicionaumdadonalista:

>>>lista=[]>>>lista.append('zero')>>>lista.append('um')>>>lista['zero','um']

Afunçãoappend()sóconsegueinserirumelementoporvez.Sequisermosinserirmaiselementospodemossomaroumultiplicarlistas,ouentãoutilizarafunçãoextend():

>>>lista=['zero','um']>>>lista.extend(['dois','três',])>>>lista+=['quatro','cinco']>>>lista+['seis']['zero','um','dois','três','quatro','cinco','seis']>>>lista*2['zero','um','dois','três','quatro','cinco','seis','zero','um','dois','três','quatro','cinco','seis']

Isso é possível já que listas são sequênciasmutáveis, ou seja conseguimos adicionar, remover emodificarseuselementos.Paraimprimiroconteúdodeumalistautilizamosocomandofor:

forvalorinlista:...print(valor)...zeroumdoistrêsquatrocinco

Tuplas

Uma tupla é uma lista imutável, ou seja, uma tupla é uma sequência que não pode ser alteradadepoisdecriada.Umatuplaédefinidadeformaparecidacomumalistacomadiferençadodelimitador.Enquantolistasutilizamcolchetescomodelimitadores,astuplasusamparênteses:

>>>dias=('domingo','segunda','terça','quarta','quinta','sexta','sabado')>>>type(dias)<class'tuple'>

Podemosomitirosparênteseseinseriroselementosseparadosporvírgula:

>>>dias='domingo','segunda','terça','quarta','quinta','sexta','sabado'

.

Page 56: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>type(dias)>>><class'tuple'>

Noteque,naverdade,éavírgulaquefazumatupla,nãoosparênteses.Osparêntesessãoopcionais,excetonocasodatuplavazia,ouquandosãonecessáriosparaevitarambigüidadesintática.

Assimcomoaslistas,tambémpodemosusarumafunçãoparacriarumatuplapassandoumtipoquepodeseriterávelcomoumastringouumalista.Essafunçãoéatuple():

>>>texto='python'>>>tuple(texto)('p','y','t','h','o','n')>>>lista=[1,2,3,4]>>>tuple(lista)(1,2,3,4)

Asregrasparaosíndicessãoasmesmasdaslistas,excetoparaelementostambémimutáveis.Comosãoimutáveis,umavezcriadasnãopodemosadicionarnemremoverelementosdeumatupla.Ométodoappend()dalistanãoexistenatupla:

>>>dias.append('sabado2')Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>AttributeError:'tuple'objecthasnoattribute'append'>>>>>>dias[0]'domingo'>>>>>>dias[0]='dom'File"<stdin>",line1,in<module>TypeError:'tuple'objectdoesnotsupportitemassignment

Nãoépossívelatribuirvaloresaositensindividuaisdeumatupla,noentanto,épossívelcriartuplasquecontenhamobjetosmutáveis,comolistas.

>>>lista=[3,4]>>>tupla=(1,2,lista)>>>tupla(1,2,[3,4])>>>lista=[4,4]>>>tupla(1,2,[4,4])>>>tupla[2]=[3,4]Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:'tuple'objectdoesnotsupportitemassignment

Astuplassãoimutáveisegeralmentecontêmumasequênciaheterogêneadeelementosjáaslistassãomutáveiseseuselementosgeralmentesãohomogêneosesãoacessados pela iteraçãoda lista,mas issonãoéumaregra.

Quandoénecessárioarmazenarumacoleçãodedadosquenãopodeseralterada,prefirausartuplasalistas.Outravantageméquetuplaspodemserusadascomochavesdedicionários.

TuplassãofrequentementeusadasemprogramasPython.Umusobastantecomumsãoemfunções

.

Page 57: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

querecebemmúltiplosvalores.Astuplasimplementamtodasasoperaçõesdesequênciacomuns.

Range

O range é um tipo de seqüência imutável de números e é comumente usado para looping de umnúmeroespecíficodevezesemumcomandoforjáquerepresentamumintervalo.Ocomandorangegeraumvalorcontendonúmerosinteirossequenciais,obedecendoasintaxe:

range(inicio,fim)

Onúmerofinalizador,ofim,nãoéincluídonasequência.Vejamosumexemplo:

>>>sequencia=range(1,3)>>>print(sequencia)range(1,3)

Orangenão imprimeos elementosda sequência, ele apenasarmazena seu início e seu final.Paraimprimirseuselementosprecisamosdeumlaçofor:

>>>forvalorinrange(1,3):...print(valor)...12

Observequeelenãoincluiosegundoparâmetrodafunçãorangenasequência.Outracaracterísticadestecomandoéadepodercontrolaropassodasequênciaadicionandoumterceiroparâmetro,istoé,avariaçãoentreumnúmeroeoseusucessor:

>>>forvalorinrange(1,10,2):...print(valor)...13579

Os intervalos implementam todas as operações de seqüência comuns, exceto concatenação erepetição(devidoaofatodequeobjetosdeintervalosópodemrepresentarsequênciasqueseguemumpadrãoestritoearepetiçãoeaconcatenaçãogeralmenteviolamessepadrão).

O Python também inclui um tipo de dados para conjuntos. Um conjunto, diferente de umasequência,éumacoleçãonãoordenadaequenãoadmiteelementosduplicados.

Chavesouafunçãoset()podemserusadosparacriarconjuntos.

>>>frutas={'laranja','banana','uva','pera','laranja','uva','abacate'}>>>frutas>>>{'uva','abacate','pera','banana','laranja'}>>>type(frutas)

4.3CONJUNTOS

.

Page 58: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

<class'set'>

Usos básicos incluem testes de associação e eliminação de entradas duplicadas. Os objetos deconjunto também suportam operações matemáticas como união, interseção, diferença e diferençasimétrica.Podemostransformarumtextoemumconjuntocomafrunçãoset()etestarosoperações:

>>>a=set('abacate')>>>b=set('abacaxi')>>>a{'a','e','c','t','b'}>>>b{'a','x','i','c','b'}>>>a-b#diferença{'e','t'}>>>a|b#união{'c','b','i','t','x','e','a'}>>>a&b#interseção{'a','c','b'}>>>a^b#diferençasimétrica{'i','t','x','e'}

Notequepara criarumconjuntovaziovocê temqueusarset(), não{}; o segundo criaumdicionáriovazio,umaestruturadedadosquediscutiremosnapróximaseção.

>>>a=set()>>>aset()>>>b={}>>>b{}>>>type(a)<class'set'>>>>type(b)<class'dict'>

Vimosquelist,tuple,rangeestrsãosequênciasordenadasdeobjetosesetssãocoleçõesdeelementosnãoordenados.DicionárioéoutraestruturadedadosemPythoneseuselementos,comoos conjuntos, não são ordenados. Essa não é a principal diferença com as listas, os dicionários sãoestruturaspoderosasemuitoutilizadasjáquepodemosacessarseuselementosatravésdechavesenãodesuaposição.Emoutraslinguagensestetipoéconhecidocomo"matrizesassociativas".

Qualquer chave de um dicionário é associada (ou mapeada) a um valor. Os valores podem serqualquertipodedadodoPython.Portanto,osdicionáriossãoparesdechave-valornãoordenados.

Osdicionáriospertencemaotipodemapeamentointegradoenãosequenciaiscomoaslistas,tuplasestrings.Vamosvercomoissofuncionanocódigoecriarumdicionáriocomdadosdeumapessoa:

>>>pessoa={'nome':'João','idade':25,'cidade':'SãoPaulo'}>>>pessoa'nome':'João','idade':25,'cidade':'SãoPaulo'

4.4DICIONÁRIOS

.

Page 59: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Osdicionáriossãodelimitadosporchaves({})esuaschaves('nome','idade'e'cidade')poraspas.Jáosvalorespodemserdequalquertipo,noexemploacimatemosduasstringseumint.

Oqueseráqueacontecesetentarmosacessarseuprimeiroelemento?

>>>pessoa[0]Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>KeyError:0

Nãoépossívelacessarumelementodeumdicionárioporumíndicecomonalista.Devemosacessarporsuachave:

>>>pessoa['nome']'João'>>>pessoa['idade']25

Seprecisarmosadicionaralgumelemento,porexemplo,opaís,bastafazermos:

>>>pessoa1['país']='Brasil'>>>pessoa1{'nome':'João','idade':25,'cidade':'SãoPaulo','país':'Brasil'}

Comosempreacessamosseuselementosatravésdechaves,odicionáriopossuiummétodochamadokeys()quedevolveoconjuntodesuaschaves:

>>>pessoa1.keys()dict_keys(['nome','idade','cidade','pais'])

Assimcomoummétodochamadovalues()queretornaseusvalores:

>>>pessoa1.values()dict_values(['João',25,'SãoPaulo','Brasil'])

Note que as chaves de umdicionárionãopodem ser iguais paranão causar conflito.Alémdisso,somentetiposdedadosimutáveispodemserusadoscomochaves,ouseja,nenhumalistaoudicionáriopodeserusado.Casoissoaconteça,recebemosumerro:

>>>dic={[1,2,3]:'valor'}Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:unhashabletype:'list'

Jáastuplas,comochaves,sãopermitidas:

>>>dic={(1,2,3):'valor'}>>>dic{(1,2,3):'valor'}

Tambémpodemoscriardicionáriosutilizandoafunçãodict():

>>>a=dict(um=1,dois=2,três=3)>>>a{'três':3,'dois':2,'um':1}

.

Page 60: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

1. Dadaalista=[12,-2,4,8,29,45,78,36,-17,2,12,8,3,3,-52]façaumprogramaque:

a)imprimaomaiorelemento

b)imprimaomenorelemento

c)imprimaosnúmerospares

d)imprimaonúmerodeocorrênciasdoprimeiroelementodalista

e)imprimaamédiadoselementos

f)imprimaasomadoselementosdevalornegativo

2. Faça umprogramaque leia dados do usuário (nome, sobrenome, idade) adicione emuma lista eimprimaseuselementosnatela.

3. Façaumprogramaqueleia4notas,mostreasnotaseamédianatela.

4. Façaumprogramautilizandoumdictqueleiadadosdeentradadousuário.Ousuáriodeveentrarcomosdadosdeumapessoa comonome, idade e cidadeondemora (fique livrepara acrescentaroutros).Apósisso,vocêdeveimprimirosdadoscomooexemploabaixo:

nome:Joãoidade:20cidade:SãoPaulo

5. (Opcional)Utilizeoexercícioanterioreadicioneapessoaemumalista.Pergunteaousuárioseeledeseja adicionarumanovapessoa.Após adicionardadosde algumaspessoas, vocêdeve imprimirtodososdadosdecadapessoadeformaorganizada.

JáconheceoscursosonlineAlura?

4.5EXERCÍCIOS:ESTRUTURADEDADOS

.

Page 61: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

.

Page 62: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO5

Objetivos:

entenderoconceitodefunçãosabereusaralgumasfunçõesembutidasdalinguagemcriarumafunção

Oconceitode função éumdosmais importantesnamatemática.Emcomputação,uma função éuma sequênciade instruções que computaumoumais resultadosque chamamosdeparâmetros.NocapítuloanteriorutilizamosalgumasfunçõesjáprontasdoPythoncomooprint(),input(),format()etype().

Tambémpodemoscriarnossasprópriasfunções.Porexemplo,quandoqueremoscalculararazãodoespaçopelotempopodemosdefinirumafunçãorecebendoestesparâmetros:

f(espaco,tempo)=espaco/tempo

Essarazãodoespaçopelotempoéoquechamamosdevelocidademédianafísica.Podemosentãodarestenomeanossafunção:

velocidade(espaco,tempo)=espaco/tempo

Se um carro percorreu uma distância de 100 metros em 20 segundos podemos calcular suavelocidademédia:

velocidade(100,20)=100/20=5m/s

OPythonpermitedefinirmos funçõescomoessadavelocidademédia.Asintaxeémuitoparecidacomadamatemática.ParadefinirmosumafunçãonoPythonutilizamosocomandodef:

defvelocidade(espaco,tempo):pass

Logoapósodefvemonomeda funçãoeentreparêntesevêmosseusparâmetros.Umafunçãotambémtemumescopo,umblocodeinstruçõesemquecolocamososcálculoseestesdevemseguiraidentaçãopadrãodoPython(4espaçosadireita).

Comonossafunçãoaindanãofaznada,utilizamosapalavrachavepassparadizeraointerpretador

FUNÇÕES

5.1OQUEÉUMAFUNÇÃO?

.

Page 63: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

quedefiniremososcálculodepois.Apalavrapassnãoéusadaapenasemfunções,podemosusaremqualquerblocodecomandoscomonasinstruçõesif,whileefor,porexemplo.

Vamossubstituirapalavrapasspeloscálculosquenossafunçãodeveexecutar:

defvelocidade(espaco,tempo):v=espaco/tempoprint('velocidade:{}m/s'.format(v))

Nossa função faz o cálculo da velocidade média e utiliza a função print() do Python paraimprimirnatela.Vamostestarnossafunção:

>>>velocidade(100,20)velocidade:5m/s

Demaneirageral,umafunçãoéumestruturaparaagruparumconjuntodeinstruçõesquepodemser reutilizadas. Agora qualquer parte do nosso programa pode chamar a função velocidade quandoprecisarcalcularavelocidademédiadeumveículo,porexemplo.Epodemoschamá-lamaisdeumavez,oquesignificaquenãoprecisamosescreveromesmocódigonovamente.

Funções são conhecidas por diversos nomes em linguagens de programação como subrotinas,rotinas,procedimentos,métodosesubprogramas.

Podemosterfunçõessemparâmetros.Porexemplo,podemosterumafunçãoquediz'oi'natela:

>>>defdiz_oi():...print("oi")>>>>>>diz_oi()oi

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

Umconjuntodeparâmetrosconsisteemumalistacomnenhumoumaiselementosquepodemser

JáconheceoscursosonlineAlura?

5.2PARÂMETROSDEFUNÇÃO

.

Page 64: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

obrigatóriosouopcionais.Paraumparâmetroseropcionalatribuímosumvalorpadrão(default)paraele-omaiscomuméutilizarNone.Porexemplo:

defdados(nome,idade=None):print('nome:{}'.format(nome))if(idadeisnotNone):print('idade:{}'.format(idade))else:print('idade:nãoinformada')

O código da função acima recebe uma idade como parâmetro e faz uma verificação com umainstruçãoif:seaidadefordiferentedeNoneelavaiimprimiraidade,casocontráriovaiimprimiridadenãoinformada.Vamostestarpassandoosdoisparâmetrosedepoisapenasonome:

>>>dados('joão',20)nome:joãoidade:20

Agorapassandoapenasonome:

>>>dados('joão')nome:joãoidade:nãoinformada

Eoqueacontecesepassarmosapenasaidade?

>>>dados(20)nome:20idade:nãoinformada

VejaqueoPythonobedeceaordemdosparâmetros.Nossaintençãoerapassaronúmero20comoidademasointerpretadorvaientenderqueestamospassandoonomeporquenãoavisamosissoàele.Casoqueiramospassarapenasaidade,devemosnomearoparâmetro:

>>>dados(idade=20)File"<stdin>",line1,in<module>TypeError:dados()missing1requiredpositionalargument:'nome'

Ointerpretadorvaiacusarumerrojáquenãopassamosoatributoobrigatórionome.

Eseaoinvésdeapenasmostraroresultado,quisermosutilizaravelocidademédiaparafazeroutrocálculo como calcular a aceleração? Da maneira como está, nossa função velocidade() nãoconseguimosutilizarseuresultadofinalparacálculos.

Exemplo:aceleracao=velocidade(parametros)/tempo

Paraconseguirmosestecomportamento,precisamosquenossafunçãoretorneovalorcalculadoporela.NoPython,utilizamosocomandoreturn:

defvelocidade(espaco,tempo):v=espaco/tempo

5.3FUNÇÃOCOMRETORNO

.

Page 65: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

returnv

Testando:

>>>velocidade(100,20)5.0

Ouainda,podemosatribuiraumavariável:

>>>resultado=velocidade(100,20)>>>resultado5.0

Econseguimosutilizarnocálculodaaceleração:

>>>aceleracao=velocidade(100,20)/200.25

Umafunçãopodecontermaisdeumcomandoreturn.Porexemplo,nossafunçãodados() queimprimeonomeeaidade,podeagoraretornarumastring.Repareque,nestecaso,temosduassituaçõespossíveis:aqueaidadeépassadaporparâmetroeaqueelanãoépassada.Aqui,teremosdoiscomandosreturn:

defdados(nome,idade=None):if(idadeisnotNone):return('nome:{}\nidade:{}'.format(nome,idade))else:return('nome:{}\nidade:nãoinformada'.format(nome))

Apesardafunçãopossuirdoiscomandosreturn,elatemapenasumretorno--vairetornarumouooutro.Quandoafunçãoencontraumcomandoreturnelanãoexecutamaisnadaquevierdepoisdeledentrodeseuescopo.

Apesar de uma função executar apenas um retorno, em Python podemos retornarmais de umavalor.Vamos fazer uma função calculadora que vai retornar os resultados de operações básicas entredoisnúmeros:adição(+)esubtração(-),nestaordem.

Pararetornarmúltiplosvalores,retornamososresultadosseparadosporvirgula:

defcalculadora(x,y):returnx+y,x-y

>>>calculadora(1,2)(3,-1)

Qualseráotipoderetornodestafunção?Vamosperguntaraointerpretadoratravésdafunçãotype:

>>>type(calculadora(1,2))<class'tuple'>

Damaneiraquedefinimosoretorno,afunçãodevolveumatupla.Nestecasoespecífico,poderíamos

5.4RETORNANDOMÚLTIPLOSVALORES

.

Page 66: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

retornarumdicionárioeusarumlaçoforparaimprimirosresultados:

>>>defcalculadora(x,y):...return{'soma':x+y,'subtração':x-y}...>>>resultados=calculadora(1,2)>>>forkeyinresultados:...print('{}:{}'.format(key,resultados[key]))...soma:3subtração:-1

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

1. Definaumafunçãochamadavelocidade_media()emumscriptchamadofuncoes.py que recebedoisparâmetros:adistânciapercorrida(emmetros)eotempo(emsegundos)gasto.

defvelocidade_media(distancia,tempo):pass

2. Agoravamos inseriras instruções,ouseja,oquea funçãodeve fazer.Vamos inseriroscomandosparacalcularavelocidademédiaeguardaroresultadoemumavariávelvelocidade:

defvelocidade_media(distancia,tempo):velocidade=distancia/tempo

3. Vamosfazerafunçãoimprimirovalordavelocidademédiacalculada:

defvelocidade_media(distancia,tempo):velocidade=distancia/tempoprint(velocidade)

4. Teste o seu código chamando a função para os valores abaixo e compare os resultados com seuscolegas:

distância:100,tempo=20distância:150,tempo=22

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

5.5EXERCÍCIOS:FUNÇÕES

.

Page 67: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

distância:200,tempo=30distância:50,tempo=3

5. Modifiqueafunçãovelocidade_media()demodoqueelaretorneoresultadocalculado.

6. Definaumafunçãosoma()querecebedoisnúmeroscomoparâmetrosecalculaasomaentreeles.

7. Definaumafunçãosubtracao()querecebedoisnúmeroscomoparâmetrosecalculaadiferençaentreeles.

8. Agora façauma funçãocalculadora() que recebedoisnúmeros comoparâmetros e retornaoresultadodasomaedasubtraçãoentreeles.

9. Modifiqueafunçãocalculadora()doexercícioanteriorefaçaelaretornartambémoresultadodamultiplicaçãoedivisãodosparâmetros.

10. Chameafunçãocalculadora()comalgunsvalores.

11. (opcional)Definauma funçãodivisao() que recebedoisnúmeros comoparâmetros, calcula eretorna o resultado da divisão do primeiro pelo segundo. Modifique a funçãovelocidade_media() utilizando a função divisao() para calcular a velocidade. Teste o seucódigochamandoafunçãovelocidade_media()comovaloresabaixo:a.distância:100,tempo=20b.distância:-20,tempo=10c.distância:150,tempo=0

Podemos passar um número arbitrário de parâmetros em uma função. Utilizamos as chamadasvariáveismágicasdoPython: *args e **kwargs.Muitosprogramadores temdificuldades ementenderessasvariáveis.Vamosentenderoqueelassão.

Nãoénecessárioutilizarexatamenteestesnomes:*argse**kwargs.Apenasoasterisco(*),oudoisdeles(**),seránecessário.Podemosoptar,porexemplo,emescrever*vare**vars.Mas*argse**kwargséumaconvençãoentreacomunidadequetambémseguiremos.

Primeiro aprenderemos a usar o *args. É usado, assim como o **kwargs, em definições defunções.*argse**kwargspermitempassarumnúmerovariáveldeargumentosdeumafunção.Oque a variável significa é que o programador ainda não sabe de antemão quantos argumentos serãopassadosparasuafunção,apenasquesãomuitos.Então,nestecasousamosapalavrachave*args.

Vejaumexemplo:

defteste(arg,*args):print('primeiroargumentonormal:{}'.format(arg))forarginargs:print('outroargumento:{}'.format(arg))

teste('python','é','muito','legal')

5.6NÚMEROARBITRÁRIODEPARÂMETROS(*ARGS)

.

Page 68: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Quevaigerarasaída:

primeiroargumentonormal:pythonoutroargumento:éoutroargumento:muitooutroargumento:legal

O parâmetro arg é como qualquer outro parâmetro de função, já o *args recebe múltiplosparâmetros.Viucomoéfácil?Tambémpoderíamosconseguiromesmoresultadopassandoumlistoutupledeargumentos,acrescidodoasterisco:

lista=["é","muito","legal"]teste('python',*lista)

Ouainda:

tupla=("é","muito","legal")teste('python',*tupla)

O*argsentãoéutilizadoquandonãosabemosdeantemãoquantosargumentosqueremospassarparaumafunção.Oasterisco(*)executaumempacotamentodosdadosparafacilitarapassagemdeparâmetros,eafunçãoquerecebeestetipodeparâmetroécapazdefazerodesempacotamento.

O**kwargspermitequepassemosotamanhovariáveldapalavra-chavedosargumentosparaumafunção.Vocêdeveusaro**kwargssequisermanipularargumentosnomeadosemumafunção.Vejaumexemplo:

defminha_funcao(**kwargs):forkey,valueinkwargs.items():print('{0}={1}'.format(key,value))

>>>minha_funcao(nome='caelum')nome=caelum

Tambémpodemospassarumdicionárioacrescidodedoissímbolosasteriscojáquesetratadechaveevalor:

dicionario={'nome':'joao','idade':25}minha_funcao(**dicionario)idade=25nome=joao

Adiferençaéqueo*argsesperaumatupladeargumentosposicionaisenquantoo**kwargsumdicionáriocomargumentosnomeados.

5.7NÚMEROARBITRÁRIODECHAVES(**KWARGS)

.

Page 69: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

1. Crieumarquivocomumafunçãochamadateste_args_kwargs()querecebetrêsargumentoseimprimecadaumdeles:

defteste_args_kwargs(arg1,arg2,arg3):print("arg1:",arg1)print("arg2:",arg2)print("arg3:",arg3)

2. Agoravamoschamarafunçãoutilizandoo*args:

args=('um',2,3)teste_args_kwargs(*args)

Quegeraasaída:

arg1:umarg2:2arg3:3

3. Testeamesmafunçãousandoo**kargs.Paraissocriaremosumdicionáriocomtrêsargumentos:

kwargs={'arg3':3,'arg2':'dois','arg1':'um'}teste_args_kwargs(**kwargs)

Quedevegerarasaída:

arg1:umarg2:doisarg3:3

4. (Opcional)Tentechamaramesmafunçãomasadicionandoumquartoargumentonavariávelargsekwargsdosexercíciosanteriores.Oqueaconteceseafunçãorecebemaisdoque3argumentos?

5. Dequemaneiravocêresolveriaoproblemadoexercícioanterior?

Seuslivrosdetecnologiaparecemdoséculopassado?

5.8EXERCÍCIO-*ARGSE**KWARGS

.

Page 70: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Discutacomoinstrutoreseuscolegasquandousar*argse**kwargs.

1. Vamos começar definindo uma função jogar que conterá toda lógica do jogo da forca. Abra oarquivoforca.pyecoloqueocódigodojogoemumafunçãojogar():

defjogar():#códigodojogoaqui

2. Vamostentarexecutarnossojogopeloterminal.Navegueatéapastajogoseexecuteforca.pyatravésdocomandopython3:

$cdjogos$python3forca.py$

Vejaquenadaaconteceu jáqueprecisamoschamara funçãojogar() do arquivo forca.py.Parafazer isso temos que importar o arquivo forca.py dentro do interpretador do python através docomandoimport:

$python3.6>>>importforca

Echamarafunçãoatravésdoarquivo'forca':

>>>forca.jogar()"*********************************""***BemvindoaojogodaForca!***""*********************************"['_','_','_','_','_','_']Qualletra?

Agoranossojogofuncionacomoesperado.

3. Façaomesmocomojogodaadivinhaçãoeexecuteojogo.

Aoimportaroarquivoforca.pyestamosimportandoummódulodenossoprograma,quenadamaisédoqueumarquivo.Vamosverificarotipodeforca:

>>>type(forca)<class'module'>

Vejaqueotipoéummódulo.Antesdecontinuarmoscomnossojogo,vamosaprenderumpoucomais sobre arquivos e módulos. Vamos melhorar ainda mais nosso jogo da Forca e utilizar o queaprendemosdefunçõesparaorganizarnossocódigo.

5.9EXERCÍCIO-FUNÇÃOJOGAR()

5.10MÓDULOSEOCOMANDOIMPORT

.

Page 71: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Agoraéamelhorhoradeaprenderalgonovo

.

Page 72: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO6

Umafuncionalidadequeaindanosatrapalhanojogodaforcaéapalavrasecreta,queatualmenteestáfixa.Sequeremosqueapalavrasejadiferente,devemosmodificá-lanocódigo.

A nossa ideia é ler palavras de um arquivo de texto, e dentre elas escolhemos uma palavraaleatoriamente,queseráapalavrasecretadojogo

Paraabrirumarquivo,oPythonpossuiafunçãoopen().Elarecebedoisparâmetros:oprimeiroéonomedo arquivo a ser aberto, e o segundoparâmetro é omodoque queremos trabalhar comessearquivo-sequeremoslerouescrever.Omodoépassadoatravésdeumastring:"w"paraescritae"r"paraleitura.

Nojogo,faremosaleituradeumarquivo.Antes,vamostestarcomofuncionaaescritanoterminaldoPython3:

>>>arquivo=open('palavras.txt','w')

Omodoéopcionaleomodopadrãoéo"r"deleitura(reading)queveremosmaisadiante.

Oarquivocriadosechama'palavras.txt'eestánomododeescrita.Éimportantesaberqueomodode escrita sobrescreve o arquivo, se o mesmo existir. Se a intenção é apenas adicionar conteúdo aoarquivo,utilizamosomodo"a"(abreviaçãoparaappend).

Agoraquetemosoarquivovamosaprenderaescreveralgumconteúdonele.Bastachamarapartirdoarquivoafunçãowrite(),passandoparaelaoquesequerescrevernoarquivo:

>>>arquivo.write('banana')6>>>arquivo.write('melancia')8

Oretornodessafunçãoéonúmerodecaracteresdecadatextoadicionadonoarquivo.

ARQUIVOS

6.1ESCRITADEUMARQUIVO

.

Page 73: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Quando estamos trabalhando com arquivos, devemos nos preocupar em fechá-lo. Para fechá-lousamosafunçãoclose():

>>>arquivo.close()

Apósisso,podemosverificaroconteúdodoarquivo.ReparequeelefoicriadonamesmapastaemqueocomandoparaabriroconsoledoPython3foiexecutado.Sevocêtentarfecharumarquivoquejáestáfechadonãovaisurtirefeitoalgum,nemmesmoumerro.Abraoarquivonapastacriadaeverifiqueseuconteúdo:

bananamelancia

Aspalavrasforamescritasemumamesmalinha.Mascomoescreverumanovalinha?

Aprimeiracoisaquedevemosfazeréabriroarquivonovamente,dessavezutilizandoomodo'a',deappend:

arquivo=open('palavras.txt','a')

Vamosescrevernovamentenoarquivo,masdessavezcomapreocupaçãodecriarumanovalinhaapóscadaconteúdoescrito.Pararepresentarumanova linhaemcódigoadicionamoso\naofinaldoquequeremosescrever:

>>>arquivo.write('morango\n')8>>>arquivo.write('manga\n')

Aofecharoarquivoeverificarnovamenteoseuconteúdo,vemos:

bananamelanciamorango

Agoraéamelhorhoradeaprenderalgonovo

6.2FECHANDOUMARQUIVO

6.3ESCREVENDOPALAVRASEMNOVASLINHAS

.

Page 74: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

manga

Apalavramorangoaindaficounamesmalinha,mascomoespecificamosnasuaadiçãoqueapósapalavradeveráterumaquebradelinha,apalavramangafoiadicionadaabaixo,emumanovalinha.

Porfim,vamosmoverestearquivoparanossoprojetoeajeitarsuaspalavrasquebrandoaslinhas.

1. VamosabriroterminalenavegaraténossapastajogosdentrodehomeeiniciarointerpretadordoPython3:

$cdjogos$python3

Lembrandoquenossaestruturadearquivosestáassim:

|_home|_jogos|_advinhacao.py|_forca.py

2. Crieumarquivochamadopalavras.txtnomodoescrita. Insiraocódigo logoapósamensagemdeabertura:

>>>arquivo=open("palavras.txt","w")

Abraapasta\home\jogosevejaseoarquivofoicriadocomoesperado:

|_home|_jogos|_advinhacao.py|_forca.py|_palavras.txt

3. Vamoscomeçaraescrevernonossoarquivoutilizandoafunçãowrite()aspalavrasqueusaremosnonossojogodaforca:

>>>arquivo.write('banana\n')7>>>arquivo.write('melancia\n')9>>>arquivo.write('morango\n')8>>>arquivo.write('manga\n')6

Note que ao final de cada palavra temos que acrescentar o "\n" para a quebra de linha, que vaifacilitarnahoradaleitura.

4. Éumaboapráticafecharoarquivodepoisdeutilizá-lo,assimoutrosprogramasouprocessospodemteracessoaoarquivoeelenãoficapresoapenasaonossoprogramaPython.

>>>arquivo.close()

6.4EXERCICIOS

.

Page 75: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

PARASABERMAIS

Alémdor,wea existeomodificadorbqueéutilizadoquandosedeseja trabalharnomodobinário.Paraabrirumaimagemnomodoleituradevemosusar:

imagem=open('foto.jpg','rb')

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

AindanoterminaldoPython3,veremosofuncionamentodaleituradeumarquivo.Comoagoraoarquivopalavras.txtestánapastadoprojetojogos,devemosexecutarocomandoqueabreoterminaldoPython3napastadoprojeto.

$cdjogos$python3

Vamosentãoabriroarquivonomododeleitura,bastapassaronomedoarquivoealetra"r"paraafunçãoopen(),comojávistoanteriormente.

arquivo=open('palavras.txt','r')

Diferentedomodo"w",abrirumarquivoquenãoexistenomodo"r"nãovaicriarumarquivo.Se"palavras.txt"nãoexistir,oPythonvailançaroerroFileNotFoundError:

>>>arquivo.open('frutas.txt','r')Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>FileNotFoundError:[Errno2]Nosuchfileordirectory:'frutas.txt'

Comooarquivofrutas.txtnãoexistenapastajogos,oPyhtonnãoconsegueencontrareacusaque

EditoraCasadoCódigocomlivrosdeumaformadiferente

6.5LENDOUMARQUIVO

.

Page 76: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

nãoexistenenhumarquivooudiretóriocomestenomenapastaraiz.

Comoabrimosoarquivonomododeleitura,afunçãowrite()nãoésuportada:

>>>arquivo.write("oi")Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>io.UnsupportedOperation:notwritable

Paraleroarquivointeiro,utilizamosafunçãoread():

>>>arquivo.read()'banana\nmelancia\nmorango\nmanga\n'

Masaoexecutarafunçãonovamente,seráretornadoumastringvazia:

>>>arquivo.read()''

Issoaconteceporqueoarquivoécomoumfluxodelinhas,quecomeçanoiníciodoarquivocomosefosse um cursor. Ele vai descendo e lendo o arquivo.Após ler tudo, ele fica posicionado no final doarquivo.Equandochamamosafunçãoread()novamentenãohámaisconteúdopoiseletodojáfoilido.

Portanto,paraleroarquivonovamente,devemosfechá-loeabrí-looutravez:

>>>arquivo.close()>>>arquivo=open('palavras.txt','r')>>>arquivo.read()

Nãoqueremoslertodooconteúdodoarquivomaslerlinhaporlinha.Comojáfoivisto,umarquivoéumfluxodelinhas,ouseja,umasequênciadelinhas.Sendoumasequênciapodemosutilizarumlaçoforparalercadalinhadoarquivo:

>>>arquivo=open('palavras.txt','r')>>>forlinhainarquivo:...print(linha)...banana

melancia

morango

manga

Reparequeexisteumalinhavaziaentrecadafruta.Issoaconteceporqueestamosutilizandoafunçãoprint() que também acrescenta, por padrão, um \n . Agora vamos utilizar outra função, areadline(),quelêapenasumalinhadoarquivo:

>>>arquivo=open('palavras.txt','r')>>>linha=arquivo.readline()

6.6LENDOLINHAPORLINHADOARQUIVO

.

Page 77: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>linha'banana\n'

Háum\n ao final de cada linha, de cada palavra,mas queremos somente a palavra. Para tirarespaçosembranconoinícioenofimdastring,bastautilizarafunçãostrip(),quetambémremovecaracteresespeciais,comoo\n-paramaisinformaçõesconsulteadocumentaçãodestrings.Sabendodissotudo,jápodemosimplementarafuncionalidadedeleituradearquivononossojogo:

arquivo=open('palavras.txt','r')palavras=[]

forlinhainarquivo:linha=linha.strip()palavras.append(linha)

arquivo.close()

Agorajátemostodasaspalavrasnalista,mascomoselecionarumadelasaleatoriamente?

Sabemosquecadaelementodalistapossuiumaposiçãoevimosnotreinamentoanteriorcomogerarumnúmeroaleatório.Abibliotecaquesabegerarumnúmeroaleatórioéarandom.Vamostestá-lanoterminaldoPython3,primeiroimportando-a:

>>>importrandom

Para gerar o número aleatório utilizamos a biblioteca e chamamos a funçãorandrange(), querecebe o intervalo de valores que o número aleatório deve estar. Então vamos passar o valor 0(equivalente à primeira posição da nossa lista) e 4 (lembrando que o número é exclusivo, ou seja, onúmeroaleatórioseráentre0e3,equivalenteàúltimaposiçãodanossalista):

>>>importrandom>>>random.randrange(0,4)0>>>random.randrange(0,4)1>>>random.randrange(0,4)3>>>random.randrange(0,4)1>>>random.randrange(0,4)3

Sabendodisso,vamosimplementaressecódigononossojogo.

6.7GERANDOUMNÚMEROALEATÓRIO

.

Page 78: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

1.Vamos começar abrindo o arquivo "palavras.txt" no nosso script forca.py que criamos noexercícioanterior.Éimportantejáacrescentarocomandoparafechá-loparanãoesquecernofuturo:

defjogar():print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

arquivo=open('palavras.txt','r')arquivo.close()

#restantedocódigo

1. Agoravamoscriarumalistachamadapalavrasefazerumlaçoforparaacessarcadalinhaparaguardarnalista:

arquivo=open('palavras.txt','r')palavras=[]

forlinhainarquivo:palavras.append(linha)

arquivo.close()

2. Comoprecisamosremovero\naofinaldalinha,usaremosafunçãostrip()emcadalinha:

defjogar():

arquivo=open('palavras.txt','r')palavras=[]

forlinhainarquivo:linha-linha.strip()palavras.append(linha)

arquivo.close()

JáconheceoscursosonlineAlura?

6.8EXERCÍCIOS-LEITURADEARQUIVOS

.

Page 79: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

3. Devemos importar a biblioteca random para gerar um número que vai de 0 até a quantidade depalavrasdanossalista.Usaremosafunçãolen()parasaberotamanhodalistaearandrange()paragerarumnúmerorandômicodeumintervaloespecífico:

importrandom

print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

arquivo=open('palavras.txt','r')palavras=[]

forlinhainarquivo:linha=linha.strip()palavras.append(linha)

arquivo.close()

numero=random.randrange(0,len(palavras))

4. Agoraquetemosonúmeroaleatório,vamosutilizá-locomoíndiceparaacessaralistaeatribuiressapalavraàvariávelpalavra_secreta:

importrandom

print("*********************************")print("***BemvindoaojogodaForca!***")print("*********************************")

arquivo=open("palavras.txt","r")palavras=[]

forlinhainarquivo:linha=linha.strip()palavras.append(linha)

arquivo.close()

numero=random.randrange(0,len(palavras))

palavra_secreta=palavras[numero].upper()letras_acertadas=['_'forletrainpalavra_secreta]

5. Porfim,temosquedeixarnossavariávelletras_acertadasdinâmica,comnúmerode letrasdeacordocomnossapalavra_secreta.Vamosutilizarumfor dentroda lista para gerarum '_'paracadaletradeacordocomotamanhodapalavra_secreta:

letras_acertadas=['_'forletrainpalavra_secreta]

6. Como já garantimos que a palavra_secreta está toda em letras maiúsculas com o códigopalavras[numero].upper(),modificaremosochuteparaoprimeiroifcontinuarfuncionando

chute=input('Qualaletra?')chute=chute.strip().upper()

Podemosexecutarojogoenotarqueapalavraéselecionadaaleatoriamente!

.

Page 80: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Masagoraanossafunçãocresceubastante,comváriasfuncionalidadeseresponsabilidades.Então,nopróximocapítulo,organizaremosmelhoronossocódigo,separando-oemfunçõesedeixando-omaisfácildeentender.

Já falamosda importânciade fechar o arquivo, certo?Veja o código abaixoque justamenteusa afunçãoclose():

arquivo=open('palavras.txt','r')palavras=logo.read()arquivo.close()

Imaginequealgumproblemaaconteçanahoradaleituraquandoafunçãoread()échamada.Seráqueoarquivoéfechadoquandooerroocorre?

Se foralgumerrograve,oprogramapodepararaexecuçãosemter fechadooarquivoe istoseriabastanteruim.ParaevitaressetipodesituaçãoexistenoPythonumasintaxeespecialparaaberturadearquivo:

withopen('palavras.txt')asarquivo:forlinhainarquivo:print(linha)

Repareocomandowithusaafunçãoopen()masnãoafunçãoclose(). Issonão serámaisnecessáriojáqueocomandowithvaiseencarregardefecharoarquivoparanósmesmoqueaconteçaalgumerronocódigodentrodeseuescopo.Muitomelhornão?

Noscapítulosanteriorescriamosdoisjogos,avançamosnojogodaForcaeimplementamosleituradepalavrasemumarquivo.Agoravamosutilizaroqueaprendemosdefunçõesparaencapsularnossocódigo edeixá-lomais organizado.Vamos começar, comos conhecimentosque temos até aqui, paraestruturarnossojogodaForca.

A função jogar() possui um código muito complexo, com muitas funcionalidades eresponsabilidades.

Entre as funcionalidades que o código possui, está a apresentação do jogo, leitura do arquivo einicializaçãodapalavra secreta, entreoutras.Vamosentão separaras responsabilidadesdocódigoemfunções,melhorandoasualegibilidadeeorganização.

Vamoscomeçarcomamensagemdeapresentaçãodonossojogoeexportarocódigoparaafunçãoimprime_mensagem_abertura(). Não podemos nos esquecer de chamar essa função no início dafunçãojogar():

6.9PARASABERMAIS-COMANDOWITH

6.10MELHORANDONOSSOCÓDIGO

.

Page 81: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

importrandom

defjogar():imprime_mensagem_abertura()

#códigoomitido

defimprime_mensagem_abertura():print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

Aquinãoimportaolocaldafunção,elapodeserdeclaradaantesoudepoisdafunçãojogar().

Oquefizemosfoirefatorarnossocódigo.Refatoraçãoéoprocessodemodificarumprogramaparamelhorar a estrutura interna do código sem alterar seu comportamento externo. Veja que seexecutarmosnossojogodaForca,tudofuncionacomoantes:

$python3>>>importforca>>>forca.jogar()*********************************)***BemvindoaojogodaForca!************************************['_','_','_','_','_','_']Qualletra?

Nopróximoexercíciovamosrefatorarasdemaispartesdonossocódigo

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

1. Crieafunçãoimprime_mensagem_aberturaquevaiisolaramensagemdeaberturadojogo:

importrandom

defjogar():imprime_mensagem_abertura()

#códigoomitido

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

6.11EXERCÍCIO-REFATORANDOOJOGODAFORCA

.

Page 82: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

defimprime_mensagem_abertura():print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')

2. Agora,vamossepararocódigoquerealizaaleituradoarquivoeinicializaapalavrasecretanafunçãocarrega_palavra_secreta():

defcarrega_palavra_secreta():arquivo=open('palavras.txt','r')palavras=[]

forlinhainarquivo:linha=linha.strip()palavras.append(linha)

arquivo.close()

numero=random.randrange(0,len(palavras))palavra_secreta=palavras[numero].upper()

Sóqueafunçãojogar()iráreclamarqueapalavra_secretanãoexiste.Oquequeremoséque,aoexecutarafunçãocarrega_palavra_secreta(),queelaretorneapalavrasecretaparanós,assimpoderemosguardá-laemumavariável:

importrandom

defjogar():

imprime_mensagem_abertura()

palavra_secreta=carrega_palavra_secreta()

letras_acertadas=["_"forletrainpalavra_secreta]

#restantedocódigoomitido

Só que como faremos a função carrega_palavra_secreta() retornar um valor, no caso a palavra_secreta ? A palavra_secreta já existe, mas só dentro da funçãocarrega_palavra_secreta().Paraqueelasejaretornada,utilizamosapalavra-chavereturn:

defcarrega_palavra_secreta():arquivo=open('palavras.txt','r')palavras=[]

forlinhainarquivo:linha=linha.strip()palavras.append(linha)

arquivo.close()

numero=random.randrange(0,len(palavras))palavra_secreta=palavras[numero].upper()

returnpalavra_secreta

3. Agoravamoscriarumafunçãoqueinicializaalistadeletrasacertadascomocaractere'_'.Criaremos

.

Page 83: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

afunçãoinicializa_letras_acertadas():

importrandom

defjogar():

imprime_mensagem_abertura()

palavra_secreta=carrega_palavra_secreta()

letras_acertadas=inicializa_letras_acertadas()

#códigoomitido

definicializa_letras_acertadas():return['_'forletrainpalavra_secreta]

4. Masafunçãoinicializa_letras_acertadas()precisateracessoàpalavra_secreta,poiselanãoexistedentroda função, jáqueuma funçãodefineumescopo, e asvariáveisdeclaradasdentrodeuma função só estão disponíveis dentro dela. Então, ao chamar a funçãoinicializa_letras_acertadas(),vamospassarpalavra_secretaparaelaporparâmetro:

importrandom

defjogar():

imprime_mensagem_abertura()

palavra_secreta=carrega_palavra_secreta()

letras_acertadas=inicializa_letras_acertadas(palavra_secreta)

#restantedocódigoomitido

definicializa_letras_acertadas(palavra):return["_"forletrainpalavra]

5. Vamoscontinuarrefatorandonossocódigo.Criaremosafunçãopede_chute(),queficarácomocódigoquepedeochutedousuário,removeosespaçosantesedepois,eocolocaemcaixaalta.Nãopodemosnosesquecerderetornarochute:

defjogar():#códigoomitido

while(notacertouandnotenforcou):chute=pede_chute()#códigoomitido

#códigoomitido

defpede_chute():chute=input('Qualletra?')chute=chute.strip().upper()returnchute

6. Aindatemosocódigoquecolocaochutenaposiçãocorreta,dentrodalista.Vamoscolocá-lodentrodafunçãomarca_chute_correto():

.

Page 84: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

while(notacertouandnotenforcou):

chute=pede_chute()

if(chuteinpalavra_secreta):marca_chute_correto()else:erros+=1

enforcou=erros==6acertou='_'notinletras_acertadasprint(letras_acertadas)

#códigoomitido

defmarca_chute_correto():posicao=0forletrainpalavra_secreta:if(chute==letra):letras_acertadas[posicao]=letraposicao+=1

Mas a função marca_chute_correto() precisa ter acesso a três valores: palavra_secreta ,chuteeletras_acertadas.Entãovamospassaressesvaloresporparâmetro

if(chuteinpalavra_secreta):marca_chute_correto(chute,letras_acertadas,palavra_secreta)

E modificamos nossa função para receber esses parâmetros: ```python defmarca_chute_correto(chute,letras_acertadas,palavra_secreta):

posicao=0forletrainpalavra_secreta:if(chute==letra):letras_acertadas[posicao]=letraposicao+=1

1.Porfim,vamosremoveramensagemdefimdejogoeexportaroscódigosqueimprimemasmensagensdevencedoreperdedordojogo:```pythonif(acertou):imprime_mensagem_vencedor()else:imprime_mensagem_perdedor()

Ecriarasfunções:

defimprime_mensagem_vencedor():print('Vocêganhou!')

defimprime_mensagem_perdedor():print('Vocêperdeu!')

Agoraonossocódigoestámuitomaisorganizadoelegível.Aochamartodasasfunçõesdentrodafunçãojogar(),nossocódigoficaráassim:

defjogar():imprime_mensagem_abertura()palavra_secreta=carrega_palavra_secreta()

.

Page 85: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

letras_acertadas=inicializa_letras_acertadas(palavra_secreta)print(letras_acertadas)

enforcou=Falseacertou=Falseerros=0

while(notenforcouandnotacertou):

chute=pede_chute()

if(chuteinpalavra_secreta):marca_chute_correto(chute,letras_acertadas,palavra_secreta)else:erros+=1

enforcou=erros==6acertou="_"notinletras_acertadas

print(letras_acertadas)

if(acertou):imprime_mensagem_vencedor()else:imprime_mensagem_perdedor()

Por fim, podemos executar o nosso código, para verificar que o mesmo continua funcionandonormalmente.

$python3>>>importforca>>>forca.jogar()************************************BemvindoaojogodaForca!************************************['_','_','_','_','_','_']Qualletra?

1. (opcional)Comamelhororganizaçãodonossocódigo,vamosmelhoraraexibição,aapresentaçãodaforca,deixandoojogomaisamigável.Vamoscomeçarcomamensagemdeperdedor,alterandoafunçãoimprime_mensagem_perdedor.Elaficaráassim:

defimprime_mensagem_perdedor(palavra_secreta):print('Puxa,vocêfoienforcado!')print('Apalavraera{}'.format(palavra_secreta))print("_______________")print("/\")print("/\")print("//\/\")print("\|XXXXXXXX|/")print("|XXXXXXXX|/")print("|XXXXXX|")print("||")print("\__XXX__/")print("|\XXX/|")print("||||")print("|IIIIIII|")print("|IIIIII|")print("\__/")

.

Page 86: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

print("\__/")print("\_______/")

Precisamospassarapalavra_secretaparafunçãoimprime_mensagem_perdedor():

if(acertou):imprime_mensagem_vencedor()else:imprime_mensagem_perdedor(palavra_secreta)

Emodificamosocódigodeimprime_mensagem_vencedor()pra:

defimprime_mensagem_vencedor():print('Parabéns,vocêganhou!')print("___________")print("'._==_==_=_.'")print(".-\\:/-.")print("|(|:.|)|")print("'-|:.|-'")print("\\::./")print("'::..'")print(")(")print("_.''._")print("'-------'")

Vá até a pasta do curso e copie o código destas funções que estão em um arquivo chamadofuncoes_forca.py.

2. (opcional)Porfim,crieafunçãodesenha_forca(),queirádesenharumapartedaforca,baseadonoserrosdousuário.Comoelaprecisaacessaroserros,passe-oporparâmetroparaafunção:

defdesenha_forca(erros):pass

Ecopieoconteúdodocódigodafunçãodesenha_forca()doarquivofuncoesforca.pynapastadocursoparasuafunção.

3. Parafinalizar,chameafunçãodesenha_forcaquandoojogadorerrareaumenteolimitedeerrospara7.

if(chuteinpalavra_secreta):marca_chute_correto(chute,letras_acertadas,palavra_secreta)else:erros+=1desenha_forca(erros)

enforcou=erros==7acertou="_"notinletras_acertadas

4. Tentefazeromesmocomojogodaadivinhação,refatorepartesdocódigoeisoleemfunções.Alémdisso,usesuacriatividadeparacustomizarmensagensparaousuáriodoseujogo.

Nesteexercíciopraticamosbastantedoqueaprendemosnocapítulodefunçãoefinalizamosojogodaforca.

.

Page 87: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Vocêpodeestarseperguntandoporqueencapsulamosumasimpleslinhadecódigoemumafunção.Fizemos issosomenteparadeixarclarooqueestamosfazendo,melhorandoa legibilidadedocódigo.Masprecisamostomarcuidadocomacriaçãode funções,poiscriar funçõesdesnecessariamentepodeaumentaracomplexidadedocódigo.

.

Page 88: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO7

Considereumprogramaparaumbancofinanceiro.Éfácilperceberqueumaentidadeimportanteparaonosso sistema será uma conta. Primeiramente suponhaque você temuma contanesse banco comasseguintes características: titular, número, saldo e limite. Vamos começar inicializando essascaracterísticas:

>>>numero='123-4'>>>titular="João">>>saldo=120.0>>>limite=1000.0

Eseanecessidadederepresentarmaisdeumacontasurgir?Vamoscriarmaisuma:

>>>numero1='123-4'>>>titular1="João">>>saldo1=120.0>>>limite1=1000.0>>>>>>numero2='123-5'>>>titular2="José">>>saldo2=200.0>>>limite2=1000.0

Nossobancopodevir a crescer e termilharesde contas e,damaneiraque estáoprograma, seriamuitotrabalhosodarmanutenção.

Ecomoutilizarosdadosdeumadeterminadacontaemoutroarquivo?Podemosutilizaraestruturadodicionárioqueaprendemosanteriormenteeagruparessascaracterísticas.Issovaiajudaraacessarosdadosdeumacontaespecífica:

conta={"numero":'123-4',"titular":"João","saldo":120.0,"limite":1000.0}

Agoraépossívelacessarosdadosdeumacontapelonomedachave:

>>>conta['numero']'123-4'>>>conta['titular']'João'

Paracriarumasegundaconta,crieoutrodicionário:

conta2={"numero":'123-5',"titular":"José","saldo":200.0,"limite":1000.0}

Avançamos em agrupar os dados de uma conta,mas ainda precisamos repetir seguidamente essalinhadecódigoacadacontacriada.Podemosisolaressecódigoemumafunçãoresponsávelporcriar

ORIENTAÇÃOAOBJETOS

.

Page 89: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

umaconta:

defcria_conta():conta={"numero":'123-4',"titular":"João","saldo":120.0,"limite":1000.0}returnconta

Masaindanãoéoidealjáquequeremoscriarcontascomoutrosvaloresetornaracriaçãodinâmica.Vamos,então,receberessevalorescomoparâmetrosdafunçãoeporfimretornamosaconta:

defcria_conta(numero,titular,saldo,limite):conta={"numero":numero,"titular":titular,"saldo":saldo,"limite":limite}returnconta

Destamaneiraépossívelcriarváriascontascomdadosdiferentes:

>>>conta1=cria_conta('123-4','João',120.0,1000.0)>>>conta2=cria_conta('123-5','José',200.0,1000.0)

Paraacessaronúmerodecadaumadelas,fazemos:

>>>conta1['numero']'123-4'>>>conta2['numero']'123-5'

Já descrevemos as características de uma conta e nosso próximo passo será descrever suasfuncionalidades.Oquefazemoscomumaconta?Ora,podemosdepositarumvaloremumaconta,porexemplo.Vamoscriarumafunçãopararepresentarestafuncionalidade.Alémdovaloraserdepositado,precisamossaberqualcontareceberáestevalor:

defdeposita(conta,valor):conta['saldo']=conta['saldo']+valor

Veja que estamos repetindo conta['saldo'] duas vezes nessa linha de código. O Python permiteescreveramesmacoisadeumamaneiramaiseleganteutilizandoo'+=':

defdeposita(conta,valor):conta['saldo']+=valor

Podemosfazeralgosemelhantecomafunçãosaca():

defsaca(conta,valor):conta['saldo']-=valor

Antesdetestaressasfuncionalidades,crieoutraquemostraoextratodaconta:

defextrato(conta):print("numero:{}\nsaldo:{}".format(conta['numero'],conta['saldo']))

Oextratoimprimeasinformaçõesdacontautilizandoafunçãoprint().Agorapodemostestarocódigo(supondoqueomesmoestejaemumarquivochamadoteste.py):

>>>fromtesteimportcria_conta,deposita,saca,extrato

7.1FUNCIONALIDADES

.

Page 90: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

>>>>>>conta=cria_conta('123-4','João',120.0,1000.0)>>>deposita(conta,15.0)>>>extrato(conta)numero:'123-4'saldo:135.0>>>saca(conta,20.0)>>>extrato(conta)numero:'123-4'saldo115.0

Ótimo!Nossocódigofuncionoucomooesperado.Aplicamosalgumasfunçõescomodeposita()esaca()eaofinalpudermoschecarosaldofinalcomafunçãoextrato().

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

1. Crieumapastachamadaooemsuaworkspaceecrieumarquivochamadoteste_conta.py

2. Crieafunçãochamadacria_conta(),querecebecomoargumentonumero,titular,saldoelimite:

defcria_conta(numero,titular,saldo,limite):

3. Dentrodecria_conta(), crieumavariáveldo tipodicionário chamadaconta comas chavesrecebendoosvaloresdosparâmetros(numero,titular,saldoelimite)eaofinalretorneaconta:

defcria_conta(numero,titular,saldo,limite):conta={"numero":numero,"titular":titular,"saldo":saldo,"limite":limite}returnconta

4. Crieuma funçãochamadadeposita() nomesmoarquivoteste_conta.py que recebe comoargumentoumacontaeumvalor.Dentrodafunçãoadicioneovaloraosaldodaconta:

defdeposita(conta,valor):conta['saldo']+=valor

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

7.2EXERCÍCIO:CRIANDOUMACONTA

.

Page 91: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

5. Crie outra função chamada saca() que recebe como argumento uma conta e um valor.Dentrodafunçãosubtraiaovalordosaldodaconta:

defsaca(conta,valor):conta['saldo']-=valor

6. E por fim, crie uma função chamada extrato(), que recebe como argumento uma conta eimprimeonumeroeosaldo:

defextrato(conta):print("numero:{}\nsaldo:{}".format(conta['numero'],conta['saldo']))

7. Navegue até a pasta oo pelo terminal, abra o console do Python3, importe o script e testes asfuncionalidades:

>>>fromteste_contaimportcria_conta,deposita,saca,extrato>>>conta=cria_conta('123-7','João',500.0,1000.0)>>>deposita(conta,50.0)>>>extrato(conta)numero:'123-7'saldo:550.0>>>saca(conta,20.0)>>>extrato(conta)numero:'123-7'saldo530.0

8. (Opcional)Acrescenteumadocumentaçãoparaoseumóduloteste_conta.pyeutilizeafunçãohelp()paratestá-la.

Nesteexercíciocriamosumacontaejuntamossuascaracterísticas(número,titular,limite,saldo)efuncionalidades (sacar,depositar, tirarextrato)nummesmoarquivo.Masoque fizemosatéagora foibaseadonoconhecimentoproceduralquetínhamosdoPython3.

Pormaisquetenhamosagrupadoosdadosdeumaconta,essaligaçãoéfrágilnomundoproceduralesemostralimitada.Precisamospensarsobreoqueescrevemosparanãoerrar.Oparadigmaorientadoaobjetosvemparasanaressaeoutrasfragilidadesdoparadigmaproceduralqueveremosaseguir.

Ninguémdeveriateracessoaosaldodiretamente.Alémdisso,nadanosobrigaavalidaressevalorepodemos esquecer disso cada vez que utilizá-lo. Nosso programa deveria obrigar o uso das funçõessaca()edeposita()paraalterarosaldoenãopermitiralterarovalordiretamente:

conta3['saldo']=100000000.0

ouentão:

conta3['saldo']=-3000.0

Devemosmanipularosdadosatravésdas funcionalidadessaca() edeposita() e proteger osdadosdaconta.Pensandonomundoreal,ninguémpodemodificarosaldodesuacontaquandoquiser,

7.3CLASSESEOBJETOS

.

Page 92: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

anãoserquandovamosfazerumsaqueouumdepósito.Amesmacoisadeveaconteceraqui.

Para isso, vamos primeiro entender o que é classe e objeto , conceitos importantes doparadigmaorientadoaobjetosedepoisveremoscomoissofuncionanaprática.

Quando preparamos um bolo, geralmente, seguimos uma receita que define os ingredientes e omododepreparação.Anossacontaéumobjetoconcretoassimcomooboloque tambémprecisadeuma receita pré-definida. E a "receita" no mundo OO recebe o nome de classe. Ou seja, antes decriarmosumobjetodefiniremosumaclasse.

Outraanalogiaquepodemosfazeréentreoprojetodeumacasa(aplantadacasa)eacasaemsi.Oprojeto é a classe e a casa, construída a partir desta planta, é oobjeto.O projeto da conta, isto é, adefiniçãodaconta,éaclasse.Oquepodemosconstruir(instanciar)apartirdessaclasse,ascontasdeverdade,damosonomedeobjetos.

Pode parecer óbvio,mas a dificuldade inicial do paradigma da orientação a objetos é justamentesaber distinguir o que é classe e o que é objeto. É comum o iniciante utilizar, obviamente de formaerrada,essasduaspalavrascomosinônimos.

OpróximopassoserácriarnossaclasseContadentrodeumnovoarquivoPython,quereceberáonomedeconta.py.CriarumaclasseemPythonéextremamentesimplesemtermosdesintaxe.Vamoscomeçar criando uma classe vazia. Depois criaremos uma instância, um objeto dessa classe, eutilizaremosafunçãotype()paraanalisaroresultado:

classConta:pass

>>>fromcontaimportConta>>>conta=Conta()>>>type(conta)<class'conta.Conta'>

VemosporqueestamosutilizandoomodointerativopeloterminaleomóduloondeseencontraaclasseContaécontaouoarquivoconta.py.AgoratemosumaclasseConta.

ComoPython é uma linguagemdinâmica, podemosmodificar esse objetoconta em tempo deexecução.Porexemplo,podemosacrescentaratributosaele:

>>>conta.titular="João">>>print(conta.titular)'João'>>>conta.saldo=120.0>>>print(conta.saldo)120.0

Maso problemado código é que aindanão garantimos que toda instância deConta tenha umatributotitularousaldo. Portantoqueremosuma formapadronizadada contademaneiraquepossamoscriarobjetoscomdeterminadasconfiguraçõesiniciais.

.

Page 93: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Emlinguagensorientadasaobjetosexisteumamaneirapadronizadadecriaratributosdeumobjeto.Geralmente fazemos isso através de uma função construtora - algo parecido com nossa funçãocria_conta()doexercícioanterior.

EmPython,algunsnomesdemétodosestãoreservadosparaousodapróprialinguagem.Umdessesmétodos é o __init__() que vai inicializar o objeto. Seu primeiro parâmetro, assim como todométododeinstância,éaprópriainstância.Porconvençãochamamosesteargumentodeself.Vejamosumexemplo:

classConta:def__init__(self,numero,titular,saldo,limite):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite

Agora, quando uma classe é criada, todos os seus atributos serão inicializados pelo método__init__().Apesardemuitosprogramadoreschamaremestemétododeconstrutor,elenãocriaumobjeto conta. Existe outro método, o __new__() que é chamado antes do __init_() pelointerpretadordoPython.Ométodo__new__()érealmenteoconstrutoreéquemrealmentecriaumainstânciadeConta.Ométodo__init__()éresponsávelporinicializaroobjeto,tantoéquejárecebeaprópriainstância(self)criadapeloconstrutorcomoargumento.EdessamaneiragarantimosquetodainstânciadeumaContatenhaosatributosquedefinimos.

Agora,seexecutarmosalinhadecódigoabaixo,vaiacusarumerro:

>>>fromcontaimportConta>>>conta=Conta()Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:__init__()missing4requiredpositionalarguments:'numero','titular','saldo',and'limite

Oerroacusaafaltade4argumentosnahoradecriarumaConta.AclasseContaagoranosobrigaapassar4atributos(numero,titular,saldoelimite)paracriarumaconta:

>>>conta=Conta('123-4','João',120.0,1000.0)

Vejaque emnenhummomento chamamosométodo__init__().Quemestá fazendo issopordebaixodospanoséopróprioPythonquandoexecutaconta=Conta().Não só, comovimos, elechama o método __new__() que devolve um instância do objeto e em seguida chama o método__init__() toda vez que criamos uma conta. Podemos ver isto funcionando imprimindo umamensagemdentrodométodo__init__():

def__init__(self,titular,numero,saldo,limite):print("inicializandoumaconta")self.titular=titular

7.4CONSTRUTOR

.

Page 94: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

self.numero=numeroself.saldo=saldoself.limite=limite

etestarnovamente:

>>>fromcontaimportConta>>>conta=Conta('123-4','João',120.0,1000.0)inicializandoumaconta

Ao criar umaConta, estamos pedindo para o Python criar uma nova instância de Conta namemória,ouseja,oPythonalocarámemóriasuficienteparaguardartodasas informaçõesdaContadentro da memória do programa. O __new__(), portanto, devolve uma referência, uma seta queapontaparaoobjetoemmemóriaeéguardadanavariávelconta.

Paramanipularmosnossoobjetocontaeacessarseusatributosutilizamosooperador"."(ponto):

>>>conta.titular'João'>>>conta.saldo120.0

Comooselféareferênciadoobjeto,elechamaself.titulareself.saldodaclasseConta.

Agora, além de funcionar como esperado, nosso código não permite criar uma conta sem osatributosquedefinimosanteriormente.Discutacomseuscolegaseinstrutorasvantagensdaorientaçãoaobjetosatéaqui.

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Como vimos, além dos atributos, nossa conta deve possuir funcionalidades. No arquivoteste_conta.py criamosas funçõessaca(),deposita() eextrato().Noparadigmaorientado aobjetosasfuncionalidadesdeumobjetosãochamadosdemétodos-dopontodevistadocódigo,sãoas

Seuslivrosdetecnologiaparecemdoséculopassado?

7.5MÉTODOS

.

Page 95: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

funçõesdentrodeumaclasse.

Vamoscriarométododeposita()naclasseConta.Aqui,assimcomoométodo__init__(),ométododeposita()devereceberainstânciadoobjeto(self)alémdovaloraserdepositado:

classConta:

#método__init__()omitido

defdeposita(self,valor):self.saldo+=valor

Issoaconteceporqueométodoprecisa saberqualobjetocontaeledevemanipular,qualcontavaidepositarumdeterminadovalor-epodemostermuitascontascriadasnonossosistema.

Utilizamosooperador'.'(ponto)atravésdoobjetocontaparachamarométododeposita:

>>>conta.deposita(20.0)

Ointerpretador,aoleressecódigo,associaoobjetocontaaoargumentoselfdométodo-notequenãoprecisamospassaracontacomoargumento,issoéfeitopordebaixodospanospeloPython.

Faremosomesmoparaosmétodossaca()eextrato():

classConta:

#outrosmétodosomitidos

defsaca(self,valor):self.saldo-=valor

defextrato(self):print("numero:{}\nsaldo:{}".format(self.numero,self.saldo))

Agoravamostestarnossosmétodos:

>>>fromcontaimportConta>>>>>>conta=Conta('123-4','João',120.0,1000.0)>>>conta.deposita(20.0)>>>conta.extrato()numero:'123-4'saldo:140.0>>>conta.saca(15)>>>conta.extrato()numero:'123-4'saldo:125.0

O saldo inicial era de 120 reais. Depositamos 20 reais, sacamos 15 reais e tiramos o extrato queresultouem125reais.

Porfim,ocódigodenossaContavaificarassim:

classConta:

def__init__(self,numero,titular,saldo,limite):self.numero=numero

.

Page 96: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

self.titular=tituarself.saldo=saldoself.limite=limite

defdeposita(self,valor):self.saldo+=valor

defsaca(self,valor):self.saldo-=valor

defextrato(self):print("numero:{}\nsaldo:{}".format(self.numero,self.saldo))

EmoutraslinguagenscomoC++eJava,ummétodosempretemquedefiniroqueretorna,nemquedefinaquenãoháretorno.Comovimosnocapítulosobre funções,noPython issonãoénecessário -mas podemos retornar algo no método saca(), por exemplo, indicando se a operação foi bemsucedidaounão.Nestecasopodemosretornarumvalorbooleano:

defsaca(self,valor):if(self.saldo<valor):returnFalseelse:self.saldo-=valorreturnTrue

Vejaqueadeclaraçãodométodonãomudoumasagoraelenosretornaalgo(umboolean).Apalavrachavereturnindicaqueométodovaiterminarali,retornandotalinformação.

Exemplodeuso:

>>>fromcontaimportConta>>>minha_conta.saldo=1000>>>consegui=minha_conta.saca(2000)>>>if(consegui):...print(“conseguisacar”)...else:...print(“nãoconseguisacar”)>>>'nãoconseguisacar'

Ouentão,podemoseliminaravariáveltemporária,sedesejado:

>>>fromcontaimportConta>>>minha_conta.saldo=1000>>>if(minha_conta.saca(2000)):...print(“conseguisacar”)...else:...print(“nãoconseguisacar”)>>>'nãoconseguisacar'

Maisadiante,veremosquealgumasvezesémaisinteressantelançarumaexceção(exception)nessescasos.

7.6MÉTODOSCOMRETORNO

.

Page 97: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

OprogramapodemanternamemórianãoapenasumaConta,masmaisdeuma:

>>>fromcontaimportConta>>>minha_conta=Conta()>>>minha_conta.saldo=1000>>>>>>meu_sonho=Conta()>>>meu_sonho.saldo=1500000

Quando criamos uma variável para associar a um objeto, na verdade, essa variável não guarda oobjeto,esimumamaneiradeacessá-lo,chamadadereferência(oself).

>>>c1=Conta()

Ao fazer isso, já sabemos que o Python está chamando os métodos mágicos __new__() e__init__()quesãoresponsáveisporconstruireiniciarumobjetodotipoConta.

Ocorretoédizerquec1serefereaumobjeto.Nãoécorretodizerquec1éumobjeto,poisc1éumavariável referência, apesarde,depoisdeumtempo,osprogramadores falarem“tenhoumobjetoc1dotipoConta”,masapenasparaencurtarafrase“Tenhoumareferênciac1 aumobjeto tipoConta”.

Vamosanalisarocódigoabaixo:

>>>fromcontaimportConta>>>c1=Conta('123-4','João',120.0,1000.0)>>>c2=c1>>>c2.saldo120.0>>>c1.deposita(100.0)>>>c1.saldo220.0>>>c2.deposita(30.0)>>>c2.saldo250.0>>>c1.saldo250.0

Oqueaconteceuaqui?Ooperador“=”copiaovalordeumavariável.Masqualéovalordavariávelc1? É o objeto?Não. Na verdade, o valor guardado é a referência (endereço) de onde o objeto seencontranamemóriaprincipal.

7.7OBJETOSSÃOACESSADOSPORREFERÊNCIA

.

Page 98: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Aofazerc2=c1,c2 passa a fazer referênciaparaomesmoobjetoquec1 referencianesseinstante.Quandoutilizamosc1ouc2,nestecódigo,estamosnosreferindoaoMESMOobjeto–sãoduasreferênciasqueapontamparaomesmoobjeto.

Podemosnotarissoatravésdafunçãointernaid()queretornaareferênciadeumobjeto:

>>>id(c1)140059774918104>>>id(c2)140059774918104

Internamente,c1ec2vãoguardarumnúmeroqueidentificaemqueposiçãodamemóriaaquelaConta seencontra.Dessamaneira,aoutilizarmoso“.”(ponto)paranavegar,oPythonvaiacessaraConta que se encontranaquelaposiçãodememória, enãoumaoutra conta.Paraquemconhece, éparecidocomumponteiro,porémvocênãopodemanipulá-lo.

Outra maneira de notar esse comportamento é que o interpretador Python chamou os métodos__new__() e __init__() apenas uma vez (na linha c1 = Conta('123-4', 'João', 120.0,1000.0)),entãosópodehaverumobjetoContanamemória.Compará-lascomooperador“==”vainosretornarTrue,poisovalorqueelascarregaméomesmo:

>>>id(c1)==id(c2)True>>>c1==c2True

Podemosentãoveroutrasituação:

>>>c1=Conta("123-4","Python",500.0,1000.0)>>>c2=Conta("123-4","Python",500.0,1000.0)>>>if(c1==c2):...print(“contasiguais”)>>>

Ooperador"=="comparaoconteúdodasvariáveis,masessasvariáveisnãoguardamoobjeto,esim

.

Page 99: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

oendereçoemqueeleseencontra.Comoemcadaumadessasvariáveisguardamosduascontascriadasdiferentemente,elasestãoemespaçosdiferentesdamemória,oquefazotestenoifvalerFalse.Ascontas podem ser equivalentes no nosso critério de igualdade, porém elas não são omesmo objeto.Quandosetratadeobjetos,podeficarmaisfácilpensarqueo"=="comparaseosobjetos(referências,naverdade)sãoomesmo,enãosepossuemvaloresiguais.

Para saber se dois objetos têm omesmo conteúdo, você precisa comparar atributo por atributo.Futuramente,veremosumasoluçãomaiseleganteparaissotambém.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

E a funcionalidade que transfere dinheiro entre duas contas? Podemos ficar tentados a criar ummétodoquerecebedoisparâmetros:conta1econta2dotipoConta.Cuidado:jásabemosqueosmétodosdenossaclasseContasemprerecebemareferência,oself-portantoométodorecebeapenasumparâmetrodotipoConta,acontadestino(alémdovalor):

Agoraéamelhorhoradeaprenderalgonovo

7.8MÉTODOTRANSFERE

.

Page 100: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

classConta:

#códigoomitido

deftransfere(self,destino,valor):self.saldo-=valordestino.saldo+=valor

Para deixar o código mais robusto, poderíamos verificar se a conta possui a quantidade a sertransferidadisponível.Paraficaraindamais interessante,vocêpodechamarosmétodosdeposita esacajáexistentesparafazeressatarefa:

classConta:

#códigoomitido

deftransfere(self,destino,valor):retirou=self.saca(valor)if(retirou==False):returnFalseelse:destino.deposita(valor)returnTrue

QuandopassamosumaContacomoargumento,oqueseráqueacontecenamemória?Seráqueoobjetoéclonado?

NoPython,apassagemdeparâmetrofuncionacomoumasimplesatribuiçãocomonousodo“=”.Então,esseparâmetrovaicopiarovalordavariáveldotipoContaqueforpassadocomoargumentopara a variável destino. E qual é o valor de uma variável dessas? Seu valor é um endereço, umareferência,nuncaumobjeto.Porissonãohácópiadeobjetosaqui.

Esseúltimocódigopoderiaserescritocomumasintaxemuitosucinta.Como?

TRANSFEREPARA

Perceba que o nome deste método poderia ser transfere_para() ao invés de sótransfere().Achamadadométodoficamuitomaisnatural,épossívellerafraseemportuguêsqueelatemumsentido:

conta1.transfere_para(conta2,50.0):

Aleituradestecódigoseria"conta1transfereparaconta250reais".

Os atributosdeumaclassepodemreceberumvalorpadrão - assimcomoos argumentosdeumafunção. Nosso banco pode ter um valor de limite padrão para todas as contas e apenas em casos

7.9CONTINUANDOCOMATRIBUTOS

.

Page 101: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

específicospodeatribuirumvalorlimitediferente.

Paraaplicarmosessa regradenegócio,podemosatribuirumvalorpadrãoao limite,porexemplo,1000.0reais:

classConta:

def__init__(self,numero,titular,saldo,limite=1000.0):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite

Epodemosinicializarumaconta:

>>>conta=Conta('123-4','joão',120.0)

Vejaqueagoranãosomosobrigadosapassarovalordolimitejáqueelepossuiumvalorpadrãode1000.0epodemosacessá-lopelaconta:

>>>conta.limite1000.0

Quando declaramos as variáveis na classe Conta, aprendemos que podemos atribuir um valorpadrão para cada uma delas. Imagine que comecemos a aumentar nossa classe Conta e adicionarnome, sobrenome e cpf do titular da conta.Começaríamos a termuitos atributos... e, se você pensardireito,umaContanãotemnome,nemsobrenomenemcpf,quemtemessesatributoséumcliente.Então podemos criar uma nova classe e fazer uma agregação - agregar um cliente a nossa conta.Portanto,nossaclasseContatemumCliente.

OatributosdeumaContatambémpodemserreferênciasparaoutrasclasses.SuponhaaseguinteclasseCliente:

classCliente:

def__init__(self,nome,sobrenome,cpf):self.nome=nomeself.sobrenome=sobrenomeself.cpf=cpf

classConta:

def__init__(self,numero,cliente,saldo,limite):self.numero=numeroself.titular=clienteself.saldo=saldoself.limite=limite

EquandocriarmosumConta,precisamospassarumClientecomotitular:

>>>fromcontaimportConta,Cliente>>>cliente=Cliente('João','Oliveira','1111111111-1')>>>minha_conta=Conta('123-4',cliente,120.0,1000.0)

Aquiaconteceuumaatribuição,ovalordavariávelclienteécopiadoparaoatributotitulardo

.

Page 102: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

objeto ao qualminha_conta se refere. Em outras palavras, minha_conta tem uma referência aomesmoClientequeclienteserefere,epodeseracessadoatravésdeminha_conta.titular.

Vocêpoderealmentenavegarsobretodaestruturadeinformação,sempreusandooponto:

>>>minha_conta.titular<__main__.Clienteobjectat0x7f83dac31dd8>

VejaqueasaídaéareferênciaaumobjetodotipoCliente,maspodemosacessarseusatributosdeumaformamaisdiretaeatémaiselegante:

>>>minha_conta.titular.nome'João'

Pythonéumalinguagemtotalmenteorientadaaobjetos.TudoemPythonéumobjeto!Semprequeutilizamosumafunçãooumétodoquerecebeparâmetrosestamospassandoobjetoscomoargumentos.Não é diferente com nossas classes. Quando uma conta recebe um cliente como titular, ele estárecebendoumainstânciadeCliente,ouseja,umobjeto.

Omesmoacontececomnumero,saldoelimite.StringsenúmerossãoclassesnoPython.Porestemotivo que aparece a palavra class quando pedimos para o Python nos devolver o tipo de umavariávelatravésdafunçãotype:

>>>type(conta.numero)<class'str'>>>>type(conta.saldo)<class'float'>>>>type(conta.titular)<class'__conta__.Cliente'>

Umsistemaorientadoaobjetoséumgrandeconjuntodeclassesquevaisecomunicar,delegandoresponsabilidadesparaquemformaisaptoarealizardeterminadatarefa.AclasseBancousaaclasseConta que usa a classe Cliente, que usa a classe Endereco, etc... Dizemos que esses objetoscolaboram, trocandomensagensentre si.Por issoacabamos tendomuitasclassesemnosso sistema,eelascostumamterumtamanhorelativamentecurto.

7.10TUDOÉOBJETO

.

Page 103: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

Fizemos, no ponto anterior, uma agregação. Agora nossa classe Conta tem um Cliente eassociamos estas duas classes. Mas nossa classe Cliente existe independente da classe Conta .Suponha agoraquenossaConta possuaumhistórico, contendo adatade aberturada conta e suastransações.Podemoscriarumaclassepararepresentarohistórico,comonoexemploabaixo:

importdatetime

classHistorico:

def__init__(self):self.data_abertura=datetime.datetime.today()self.transacoes=[]

defimprime(self):print("dataabertura:{}".format(self.data_abertura))print("transações:")fortinself.transacoes:print("-",t)

AgoraprecisamosmodificarnossaclasseContademodoqueelatenhaumHistorico.Masaqui,diferenteda relaçãodoclientecomumaconta, a existênciadeumhistóricodependedaexistênciadeumaConta:

classConta:

def__init__(self,numero,cliente,saldo,limite=1000.0):self.numero=numeroself.cliente=clienteself.saldo=saldoself.limite=limiteself.historico=Historico()

Epodemos,emcadamétodoparamanipularumaConta,acrescentaraoperaçãonastransaçõesdeseuHistorico:

EditoraCasadoCódigocomlivrosdeumaformadiferente

7.11COMPOSIÇÃO

.

Page 104: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

classConta:

#códigoomitido

defdeposita(self,valor):self.saldo+=valorself.historico.transacoes.append("depósitode{}".format(valor))

defsaca(self,valor):if(self.saldo<valor):returnFalseelse:self.saldo-=valorself.historico.transacoes.append("saquede{}".format(valor))

defextrato(self):print("numero:{}\nsaldo:{}".format(self.numero,self.saldo))self.historico.transacoes.append("tirouextrato-saldode{}".format(self.saldo))

deftransfere_para(self,destino,valor):retirou=self.saca(valor)if(retirou==False):returnFalseelse:destino.deposita(valor)self.historico.transacoes.append("transferenciade{}paraconta{}".format(valor,destino.numero))returnTrue

Etestamos:

$python3.6>>>fromcontaimportConta,Cliente>>>cliente1=Cliente('João','Oliveira','11111111111-11')>>>cliente2=Cliente('José','Azevedo','222222222-22')>>>conta1=Conta('123-4',cliente1,1000.0)>>>conta2=Conta('123-5',cliente2,1000.0)>>>conta1.deposita(100.0)>>>conta1.saca(50.0)>>>conta1.transfere_para(conta2,200.0)>>>conta1.extratonumero:123-4saldo:850.0>>>conta1.historico.imprime()dataabertura:2018-05-1019:44:07.406533transações:-depósitode100.0-saquede50.0-saquede200.0-transferenciade200.0paraconta123-5-tirouextrato-saldode850.0>>>conta2.historico.imprime()dataabertura:2018-05-1019:44:07.406553transações:-depósitode200.0

Quandoaexistênciadeumaclassedependedeoutraclasse,comoéarelaçãodaclasseHistóricocomaclasseConta,dizemosqueaclasseHistoricocompõeaclasseConta.EstaassociaçãochamamosComposição.

.

Page 105: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Mas,esedentrodanossaContanãocolocássemosself.historico=Historico()etentasseacessá-lodiretamente?Fazalgumsentidofazerhistorico=Historico()?

Quandooobjetoéinicializado,elevaireceberovalordefaultquedefinimosnaclasse:

classConta:

def__init__(self,numero,cliente,saldo,limite):#iniciandooutrosparâmetrosself.historico=Historico()

Comessecódigo,todanovaContacriadajáteráumnovoHistoricoassociado,semnecessidadedeinstanciá-lologoemseguidadainstanciaçãodeumaConta.

Atenção:paraquemnãoestáacostumadocomreferências,podeserbastanteconfusopensarsempreem como os objetos estão namemória para poder tirar as conclusões de o que ocorrerá ao executardeterminado código, por mais simples que ele seja. Com o tempo, você adquire a habilidade derapidamente saber o efeito de atrelar as referências, sem ter de gastar muito tempo para isso. Éimportante,nessecomeço,vocêestarsemprepensandonoestadodamemória.Erealmentelembrarque,noPython“umavariávelnuncacarregaumobjeto,esimumareferênciaparaele”facilitamuito.

Ointerpretadoradicionaalgunsatributosespeciaissomenteparaleituraaváriostiposdeobjetosdeumaclasseeumdeleséo__dict__.

Isso acontece porque a classe Conta possui alguns métodos, dentre eles o __init__() e o__new__() que são chamados para criar e inicializar umobjeto desta classe, respectivamente.CasovocêqueirasaberquaisoutrosmétodossãoimplementadospelaclasseContavocêpodeusarafunçãoembutidadir()quevailistartodosmétodoseatributosqueaclassepossui.

>>>dir(Conta)['__class__','__delattr__','__dict__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__module__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','__weakref__','extrato','deposita','limite','numero','saca','saldo','transfere_para','titular']

Dessalista,jáconhecemoso__init__(),o__new__()eosmétodoseatributosquedefinimosquandoconstruímosaclasseConta.Naverdade,quandousamosa funçãodir(), o interpretadorchamaoatributo__dir__dessalista.Umoutroatributobastanteútiléo__dict__queretornaumdicionáriocomosatributosdaclasse

>>>cliente=Cliente('João','Oliveira','111111111-11')>>>conta=Conta('123-4',cliente,1000.0)>>>conta.__dict__{'saldo':1000.0,'numero':'123-4','titular':<__main__.Clienteobjectat0x7f0b6d028f28>,'limite':1000.0}

7.12PARASABERMAIS:OUTROSMÉTODOSDEUMACLASSE

.

Page 106: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Mas não é comum acessá-lo dessa maneira. Estes métodos iniciados e terminados com doisunderscores são chamados pelo interpretador e são conhecidos comométodosmágicos. Existe outrafunçãoembutidadoPython,a funçãovars(), que chama exatamenteo__dict__ deuma classe.Obtemosomesmoresultadousandovars(conta):

>>>vars(conta){'saldo':1000.0,'numero':'123-4','titular':<__main__.Clienteobjectat0x7f0b6d028f28>,'limite':1000.0}

Reparequeo__dict__ e ovars() retornamexatamenteumdicionáriode atributosdeumacontacomotínhamosmodeladono iníciodestecapítulo.Portanto,nossasclassesutilizamdicionáriosparaarmazenarinformaçõesdaprópriaclasse.

Osdemaismétodosmágicosestãodisponíveisparausoenãoutilizaremosporenquanto.Voltaremosafalardelesemumoutromomento.

1. Crieumarquivochamadoconta.pynapastaoocriadanoexercícioanterior.

2. CrieaclasseContasemnenhumatributoesalveoarquivo.

classConta:pass

3. Abraoterminaleváatéapastaondeseencontraoarquivoconta.py.AbraoconsoledoPython3noterminaleimporteaclasseContadomóduloconta.

>>>fromcontaimportConta

4. Crieuma instância (objeto)daclasseConta e utilize a funçãotype() para verificar o tipodoobjeto:

>>>conta=Conta()>>>type(conta)<class'conta.Conta'>

Alémdisso,criealgunsatributosetenteacessá-los.

1. Abra novamente o arquivo conta.py e escreva o método __init__() recebendo os atributosanteriormentedefinidospornósquetodacontadeveter(numerotitular,saldoelimite):

classConta:

def__init__(self,numero,titular,saldo,limite):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite

2. Reinicie o Python3 no terminal e importe novamente a classe Conta do módulo conta para

7.13EXERCÍCIO:PRIMEIRACLASSEPYTHON

.

Page 107: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

testarmosnossocódigo:

>>>fromcontaimportConta

3. Tentecriarumacontasempassarqualquerargumentonoconstrutor:

>>>conta=Conta()Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:__init__()missing4requiredpositionalarguments:'numero','titular','saldo',and'limite

Notequeo interpretadoracusouumerro.Ométodo__init__() exige 4 argumentos 'numero','titular','saldo'e'limite'.

4. Agoravamosseguiroexigidopelaclasse,pelareceitadeumaconta:

>>>conta=Conta('123-4','João',120.0,1000.0)

5. Ointerpretadornãoacusounenhumerro.Vamosimprimironumeroetitulardaconta:

>>>conta.numero'123-4'>>>conta.titular'João'

6. Crieométododeposita()dentrodaclasseConta.Essemétododevereceberumareferênciadopróprioobjetoeovaloraseradicionadoaosaldodaconta.

defdeposita(self,valor):self.saldo+=valor

7. Crieométodosaca()querecebecomoargumentoumareferênciadopróprioobjetoeovalorasersacado.Essemétodosubtrairáovalordosaldodaconta.

defsaca(self,valor):self.saldo-=valor

8. Crieométodoextrato(), que recebe comoargumentouma referênciadopróprioobjeto.Essemétodoimprimiráosaldodaconta:

defextrato(self):print("numero:{}\nsaldo:{}".format(self.numero,self.saldo))

9. Modifiqueométodo`saca()fazendoretornarumvalorquerepresentaseaoperaçãofoiounãobemsucedida.Lembrequenãoépermitidosacarumvalormenordoqueosaldo.

defsaca(self,valor):if(self.saldo<valor):returnFalseelse:self.saldo-=valorreturnTrue

10. Crieométodotransfere_para()querecebecomoargumentoumareferênciadopróprioobjeto,umaContadestinoeovalorasertransferido.Essemétododevesacarovalordopróprioobjetoe

.

Page 108: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

depositarnacontadestino:

deftransfere_para(self,destino,valor):retirou=self.saca(valor)if(retirou==false):returnFalseelse:destino.deposita(valor)returnTrue

11. AbraoPythonnoterminal,importeomóduloconta,crieduascontasetesteosmétodoscriados.

12. (Opcional) Crie uma classe para representar um cliente do nosso banco que deve ter nome ,sobrenomeecpf.InstancieumaContaepasseumclientecomotitulardaconta.Modifiqueométodoextrato() da classeConta para imprimir, alémdonúmero e o saldo, osdadosdocliente.PodemoscriarumaContasemumCliente?EumClientesemumaConta?

13. (Opcional) Crie uma classe que represente uma data, com dia, mês e ano. Crie um atributodata_aberturanaclasseConta.CrieumanovacontaefaçatestesnoconsoledoPython.

14. (Desafio) Crie uma classe Historico que represente o histórico de uma Conta seguindo oexemplodaapostila.FaçatestesnoconsoledoPythoncriandoalgumascontas,fazendooperaçõeseporúltimomostrandoohistóricodetransaçõesdeumaConta.FazsentidocriarumobjetodotipoHistoricosemumaConta?

Agora, além de funcionar como esperado, nosso código não permite criar uma conta sem osatributosquedefinimosanteriormente.Discutacomseuscolegaseinstrutorasvantagensdaorientaçãoaobjetosatéaqui.

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

JáconheceoscursosonlineAlura?

.

Page 109: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO8

Umdosproblemasmaissimplesquetemosnonossosistemadecontaséqueométodosaca()permitesacarmesmoqueosaldosejainsuficiente.AseguirvocêpodelembrarcomoestáaclasseConta:

classConta:

def__init__(self,numero,titular,saldo,limite=1000.0):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite

#outrosmétodos

defsaca(self,valor):this.saldo-=valor

Abrimosoterminaletestamosnossocódigo:

minha_conta=Conta('123-4','joão',1000.0,2000.0)minha_conta.saca(500000)

Olimitedesaqueéultrapassado.Podemosincluirumifdentrodométodosaca()paraevitarasituação que resultaria em uma conta em estado inconsistente, com seu saldo menor do que zero.Fizemosissonocapítulodeorientaçãoaobjetosbásica.

Apesardemelhorarbastante,aindatemosumproblemamaisgrave:ninguémgarantequeousuárioda classe vai sempreutilizarométodopara alteraro saldoda conta.Ocódigoa seguir alterao saldodiretamente:

minha_conta=Conta('123-4','João',1000.0)minha_conta.saldo=-200

Comoevitarisso?Umaideiasimplesseriatestarsenãoestamossacandoumvalormaiorqueosaldotodavezqueformosalterá-lo.

minha_conta=Conta('123-4','joão',1000.0)novo_saldo=-200

if(novo_saldo<0):print("saldoinválido")else:minha_conta.saldo=novo_saldo

MODIFICADORESDEACESSOEMÉTODOSDECLASSE

.

Page 110: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Essecódigoiriaserepetirao longodetodanossaaplicaçãoe,pior,alguémpodeesquecerdefazeressacomparaçãoemalgummomento,deixandoacontaemumasituaçãoinconsistente.Amelhorformaderesolver issoseriaforçarquemusaaclasseContaa invocarométodosaca() e nãopermitir oacessodiretoaoatributo.

EmlinguagenscomoJavaeC#bastadeclararqueosatributosnãopodemseracessadosdeforadaclasse utilizando a palavra chave private. Em orientação a objetos, é prática quase que obrigatóriaprotegerseusatributoscomprivate.Cadaclasseéresponsávelporcontrolarseusatributos,portantoeladevejulgarseaquelenovovaloréválidoounão.Eestavalidaçãonãodevesercontroladaporquemestáusandoaclasseesimporelamesma,centralizandoessaresponsabilidadeefacilitandofuturasmudançasnosistema.

O Python não utiliza o termoprivate, que é ummodificador de acesso e também chamado demodificadordevisibilidade.NoPythoninserimosdoisunderscores('__')aoatributoparaadicionarestacaracterística:

classPessoa:

def__init__(self,idade):self.__idade=idade

DessamaneiranãoconseguimosacessaroatributoidadedeumobjetodotipoPessoa foradaclasse:

>>>pessoa=Pessoa(20)>>>pessoa.idadeTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>AttributeError:'Pessoa'objecthasnoattribute'idade'

OinterpretadoracusaqueoatributoidadenãoexistenaclassePessoa.Masissonãogarantequeninguémpossa acessá-lo.NoPythonnão existem atributos realmente privados, ele apenas alerta quevocênãodeveriatentaracessaresteatributo,oumodificá-lo.Paraacessá-lo,fazemos:

>>>p._Pessoa__idade

Aocolocaroprefixo__noatributodaclasse,oPythonapenasrenomeia'__nome_do_atributo'para'_nomeda_Classe\_nome_do_atributo',comofezem__idadepara_Pessoa__idade.Qualquerpessoaque saiba que os atributos privados não são realmente privados, mas "desconfigurados", pode ler eatribuir um valor ao atributo "privado" diretamente. Mas fazer pessoa._Pessoa__idade = 20 éconsideradomápráticaepodeacarretaremerros.

Podemosutilizarafunçãodirparaverqueoatributo_Pessoa__idadepertenceaoobjeto:

>>>dir(pessoa)['_Pessoa__idade','__class__','__delattr__','__dict__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__module__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__',

.

Page 111: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

'__weakref__']

Reparequenãoexistenenhumatributo__idadenoobjetopessoa.Agoravamostentaratribuirumvalorpara__idade:

>>>pessoa.__idade=25

Epa,seráqueoPythondeveriadeixarissoocorrer?Vamosacessaravariávelnovamenteeverseamodificaçãorealmenteaconteceu:

>>>pessoa._Pessoa__idade20

OqueaconteceuaquiéqueoPythoncriouumnovoatributo__idadeparaoobjetopessoajáqueéumalinguagemdinâmica.Vamosutilizarafunçãodirnovamenteparaverisso:

>>>dir(pessoa)['_Pessoa__idade','__class__','__delattr__','__dict__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__idade','__init__','__init_subclass__','__le__','__lt_''__module__','__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','__weakref__']

Notequeumnovoatributo__idade apareceu, jáque foi inicializadoemtempodeexecuçãoeédiferentedo__idadedaclasse.Issopodegerarmuitaconfusãoeerros!OPythontambémtemumamaneiradelidarcomesteproblemaatravésdavariável__slots__ondedefinimosumnúmerolimitadodeatributosqueveremosaseguir.

Nenhum atributo é realmente privado em Python já que podemos acessá-lo pelo seu nome'desfigurado'. Muitos programadores Python não gostam dessa sintaxe e preferem usar apenas umunderscore '_' para indicar quando um atributo deve ser protegido. Ou seja, deve ser explícita essadesconfiguraçãodonome- feitapeloprogramadorenãopelo interpretador- jáqueofereceomesmoresultado.Eargumentamque'__'sãoobscuros.

Oprefixo comapenasumunderscore não tem significadoparao interpretadorquandousado emnome de atributos, mas entre programadores Python é uma convenção que deve ser respeitada. Oprogramadoralertaqueesseatributonãodeveseracessadodiretamente:

def__init__(self,idade):self._idade=idade

Umatributocomapenasumunderscoreéchamadosdeprotegido,masquandousadosinalizaquedevesertratadocomoumatributo"privado"eacessá-lodiretamentepodeserperigoso.

As mesmas regras de acesso aos atributos valem para os métodos. É muito comum, e faz todosentido, que seus atributos sejam privados e quase todos seus métodos sejam públicos (não é umaregra!). Desta forma, toda conversa de um objeto com outro é feita por troca demensagens, isto é,acessandoseusmétodos.Algomuitomaiseducadoquemexerdiretamenteemumatributoquenãoé

.

Page 112: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

seu.

Melhorainda!OdiaqueprecisarmosmudarcomoérealizadoumsaquenanossaclasseConta,adivinheondeprecisaríamosmodificar?Apenasnométodosaca(),oquefazplenosentido.

Oquecomeçamosavernessecapítuloéaideiadeencapsular,istoé,'esconder'todososmembrosdeumaclasse (comovimosacima), alémde esconder como funcionamas rotinas (no casométodos)donossosistema.

Encapsularé fundamentalparaqueseusistemasejasuscetívelamudanças:nãoprecisamosmudaruma regra de negócio em vários lugares,mas sim em apenas um único lugar, já que essa regra estáencapsulada.Oconjuntodemétodospúblicosdeumaclasseétambémchamadodeinterfacedaclasse,poisestaéaúnicamaneiraaqualvocêsecomunicacomobjetosdessaclasse.

Ounderscore _ alerta queninguémdevemodificar, nemmesmo ler, o atributo emquestão.Comisso,temosumproblema:comofazerparamostrarosaldodeumaConta,jáquenãodevemosacessá-loparaleituradiretamente?

Precisamosentãoarranjarumamaneiradefazeresseacesso.Semprequeprecisamosarrumarumamaneira de fazer alguma coisa com um objeto, utilizamosmétodos! Vamos então criar ummétodo,digamospega_saldo(),pararealizaressasimplestarefa:

classConta:

#outrosmétodos

defpega_saldo(self):returnself._saldo

Paraacessarmososaldodeumaconta,podemosfazer:

>>>minha_conta=Conta('123-4','joão',1000.0)>>>minha_conta.deposita(100)>>>minha_conta.pega_saldo()1100

Para permitir o acesso aos atributos (já que eles são 'protegidos') de umamaneira controlada, aprática mais comum é criar dois métodos, um que retorna o valor e outro que muda o valor. Aconvençãoparaessesmétodosemmuitaslinguagensorientadasaobjetosécolocarapalavragetousetantes do nome do atributo. Por exemplo, uma conta com saldo e titular fica assim, no caso dedesejarmosdaracessoaleituraeescritaatodososatributos:

classConta:

def__init__(self,titular,saldo):self._titular=titularself._saldo=saldo

8.1ENCAPSULAMENTO

.

Page 113: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

defget_saldo(self):returnself._saldo

defset_saldo(self,saldo):self._saldo=saldo

defget_titular(self):returnself._titular

defset_titular(self,titular):self._titular=titular

Gettersesetterssãousados emmuitaslinguagensdeprogramaçãoorientadaaobjetosparagarantiroprincípio do encapsulamento de dados.O encapsulamento de dados é visto comoo agrupamento dedadoscomosmétodosqueoperamnessesdados.Essesmétodossão,obviamente,ogetterpararecuperarosdadoseosetterparaalterarosdados.Deacordocomesseprincípio,osatributosdeumaclassesãotornadosprivadosparaocultá-loseprotegê-losdeoutrocódigo.

Infelizmente, é crença generalizada que uma classe Python adequada deve encapsular atributosprivadosusandogettersesetters.Assimqueumdessesprogramadoresintroduzirumnovoatributo,elefará com que seja uma variável privada e criará "automaticamente" um getter e um setter para essesatributos.

Os programadores de Java irão torcer o nariz quando lerem o seguinte: Amaneira pythônica deintroduziratributosé torná-lospúblicos.Vamosexplicar issomais tarde.Primeiro,demonstramosnoexemploaseguir,comopodemosprojetarumaclasse,damesmamaneirausadanoJava,comgettersesettersparaencapsularumatributoprotegido:

classConta:

def__init__(self,saldo):self._saldo=saldo

defget_saldo(self):retornoself._saldo

defset_saldo(self,saldo):self._saldo=saldo

Epodemosvercomotrabalharcomessaclasseeosmétodos:

>>>conta1=Conta(200.0)>>>conta2=Conta(300.0)>>>conta3=Conta(-100.0)>>>conta1.get_saldo()200.0>>>conta2.get_saldo()300.0>>>conta3.set_saldo(conta1.get_saldo()+conta2.get_saldo())>>>conta3.get_saldo()500.0

Oque você acha da expressão "conta3.set_saldo(conta1.get_saldo() + conta2.get_saldo())"? É feio,

.

Page 114: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

nãoé?Émuitomaisfácilescreverumaexpressãocomoaseguinte:

conta3.saldo=conta1.saldo+conta2.saldo

Tal atribuição émais fácilde escrever e, acimade tudo,mais fácilde lerdoque a expressão comgettersesetters.VamosreescreveraclasseContadeummodoPythônico,semgetteresemsetter:

classConta:

def__init__(self,saldo):self.saldo=saldo

Masnestecasonãoháencapsulamentoenãoseriaumproblema.Masoqueacontecesequisermosmudar a implementação no futuro? O leitor atento deve ter reparado que no exemplo anteriordeclaramosumavariáveldotipoContacomsaldonegativoe issonãodeveriaacontecer.Temosqueevitaressasituaçãoeosetter,nestecaso,sejustificaparaacrescentarestavalidação:

classConta:

def__init__(self,saldo):self.saldo=saldo

defset_saldo(self,saldo):if(saldo<0):print("saldonãopodesernegativo")else:self.saldo=saldo

Podemosabrirointerpretadoretestar:

>>>conta1=Conta(200.0)>>>conta1.saldo200.0>>>conta2=Conta(300.0)>>>conta2.saldo300.0>>>conta3=Conta(100.0)>>>conta3.set_saldo(-100.0)"saldonãopodesernegativo">>>conta3.saldo100.0

Masháumproblema,casoprojetemosnossaclassecomatributopúblicoesemmétodosquebramosainterface:

conta1=Conta(100.0)conta.saldo=-100.0

ÉporissoqueemJavarecomenda-sequeaspessoasusemsomenteatributosprivadoscomgettersesetters,paraquepossamalteraraimplementaçãosemprecisaralterarainterface.OPythonofereceumasoluçãobastanteparecidapara este problema.A solução é chamadadeproperties.Mantemosnossosatributosprotegidosedecoramosnossosmétodoscomumdecoratorchamadoproperty.

Aclassecomumapropriedadeficaassim:

.

Page 115: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

classConta:

def__init__(self,saldo=0.0):self._saldo=saldo

@propertydefsaldo(self):returnself._saldo

@saldo.setterdefsaldo(self,saldo):if(self._saldo<0):print("saldonãopodesernegativo")else:self._saldo=saldo

Um método que é usado para obter um valor (o getter) é decorado com @property, isto é,colocamos essa linha diretamente acima da declaração do método que recebe o nome do próprioatributo.Ométodoquetemquefuncionarcomosetteré[email protected] funçãotivessesidochamadade"func",teríamosqueanotá[email protected].

PARASABERMAIS:DECORATOR

Umdecorador, oudecorator é umpadrãodeprojetode softwarequepermite adicionarumcomportamento a umobjeto já existente em tempode execução, ou seja, agrega dinamicamenteresponsabilidades adicionais a um objeto. Esta solução traz uma flexibilidade maior, em quepodemosadicionarouremoverresponsabilidadessemquesejanecessárioeditarocódigo-fonte.

Umdecoradoréumobjetoinvocável,umafunçãoqueaceitaoutrafunçãocomoparâmetro(afunção decorada). O decorador pode realizar algum processamento com a função decorada edevolvê-laousubstituí-laporoutrafunção.Opropertyéumdecoradorquepossuimétodosextrascomo um getter e um setter e ao ser aplicado a um objeto, retorna uma cópia dele com essasfuncionalidades:

@propertydeffoo(self):returnself._foo

éequivalentea:

deffoo(self)returnself._foo

foo=property(foo)

Portanto,afunçãofoo()ésubstituídapelapropriedadeproperty(foo).Então,sevocê[email protected](),oquevocêestáfazendoéchamarométodoproperty().setter

Desta maneira, podemos chamar esses métodos sem os parênteses, como se fossem atributos

.

Page 116: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

públicos.Éuma formamais elegantede encapsularnossos atributos.Vamos testar criaruma conta edepoisatribuirumvalornegativoaosaldo:

>>>conta=Conta(1000.0)>>>conta.saldo=-300.0"saldonãopodesernegativo"

Vejaquetemosumresultadomuitomelhordoqueusargettersandsettersdiretamente.Chamamosoatributopelasuaspropriedades,quepodemcontervalidações,enossosatributosestãosinalizadoscomo'protegidos'atravésdo'_'.

Masaindapodemosmodificarosaldoeistodeveriaserfeitoatravésdosmétodospúblicossaca()e deposita() . Então, a necessidade de um @saldo.setter é questionável. Devemos apenasmanipular o saldo através dos métodos saca() e deposita() , não precisamos da propertysaldo.setter. Issoéumadecisãodenegócioespecífico.Oprogramadordeveficaralertaquantoaspropriedadessettersdeseusatributos,nemsempreelassãonecessárias.

É uma má prática criar uma classe e, logo em seguida, criar as propriedades para todos seusatributos. Você só deve criar properties se tiver real necessidade. Repare que nesse exemplo, apropriedade setter do saldo não deveria ter sido criada já que queremos que todos usemosmétodosdeposita()esaca().

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

Nosso banco também quer controlar a quantidade de contas existentes no sistema. Comopoderíamosfazerisso?Bom,acadainstânciacriadadeveríamosincrementaressetotal:

total_contas=0conta=Conta(300.0)total_contas=total_contas+1conta2=Conta(100.0)total_contas=total_contas+1

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

8.2ATRIBUTOSDECLASSE

.

Page 117: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

AquiVoltaoproblemaderepetirummesmocódigoparatodaaplicação,alémdeterquelembrardeincrementaravariáveltotal_contas todavezapós instanciarumaConta.Comototal_contastemvínculocomaclasseConta,eledeveserumatributocontroladopelaclassequedeveincrementá-lotodavezqueinstanciamosumobjeto,ouseja,quandochamamosométodo__init__():

classConta:

def__init__(self,saldo):self._saldo=saldoself._total_contas=self._total_contas+1

Masondeinicializamosavariável_total_contas?Nãofazsentidorecebermosporparâmetrono__init__()jáqueéaclassequedevecontrolaressenúmeroenãooobjeto.Seriainteressantequeessavariável fosse própria da classe, fosse única e compartilhada por todos os objetos dessa classe.Dessamaneira, quandomudasse através de um objeto, o outro enxergaria omesmo valor. Para fazer isso,vamosinicializaravariávelnaclasse,portanto,foradométodo__init__():

classConta:

total_contas=0

def__init__(self,saldo):self._saldo=saldoself.total_contas+=1

Vejaquesaldoéumatributodeinstânciaetotal_contasumatributodeclasse.Vamosfazerumtesteparaversenossototal_contasfuncionacomoesperado:

>>>c1=Conta(100.0)>>>c1.total_contas1>>>c2=Conta(200.0)>>>c2.total_contas1

Criamosduasinstânciasemesmoassimototal_contasnãomudou.Issoaconteceporcontadoself.total_contas+=1.self.total_contas é diferente detotal_contas da classe. Comototal_contaséumavariáveldaclasse,devemoschamá-lapelaclasse:

classConta:

total_contas=0

def__init__(self,saldo):self._saldo=saldoConta.total_contas+=1

Etestamos:

>>>c1=Conta(100.0)>>>c1.total_contas1>>>c2=Conta(200.0)>>>c2.total_contas2

.

Page 118: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Agoraobtemosoresultadoesperado.Tambémépossívelacessaresteatributodiretodaclasse:

>>>Conta.total_contas2

Mas não queremos que ninguém venha a acessar nosso atributo total_contas e modificá-lo.Portantovamostorná-lo'protegido'acrescentandoum'_':

classConta:

_total_contas=0

Dessamaneiraavisamososusuáriosdenossaclassequeesseatributodeveserconsiderado'privado'enãomodificado.Mascomoacessá-loentão?Vejaqueagora,aoacessarpelaclasseobtemosumerro:

>>>Conta.total_contasTraceback(mostrecentcalllast):File<stdin>,line23,in<module>Conta.total_contasAttributeError:'Conta'objecthasnoattribute'total_contas'

Precisamoscriarummétodoparaacessaroatributo.Vamoscriaroget_total_contas:

classConta:

_total_contas=0

#__init__eoutrosmétodos

defget_total_contas(self):returnConta._total_contas

Funciona quando chamamos este método por um instância, mas quando fazemosConta.get_total_contas()ointerpretadorreclamapoisnãopassamosainstância:

>>>c1=Conta(100.0)>>>c1.get_total_contas()1>>>c2=Conta(200.0)>>>c2.get_total_contas()2>>>Conta.get_total_contas()Traceback(mostrecentcalllast):File<stdin>,line17,in<module>Conta.get_total_contas()TypeError:get_total_contas()missing1requiredpositionalargument:'self'

Vejaqueoerroavisaque faltapassaroargumentoself.Nãopodemos chamá-lopoisnão estávinculado a qualquer instância de Conta. E um método quer uma instância como seu primeiroargumento:

>>>c1=Conta(100.0)>>>c2=Conta(200.0)>>>Conta.get_total_contas(c1)2

Passamosainstânciac1deContaefuncionou.Masessanãoéamelhormaneiradesechamarum

.

Page 119: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

método.Achamadanãoéclaraelevaumtempoparalereentenderoqueaterceiralinhadessecódigorealmentefaz.Vamosentãodeixardepassaro'self'comoargumentodeget_total_contas:

defget_total_contas():returnConta._total_contas

Mas dessa maneira não conseguimos acessar o método já que todo método exige o argumentoself:

>>>c1=Conta(100.0)>>>c1.get_total_contas()Traceback(mostrecentcalllast):File<stdin>in<module>c1.get_total_contas()TypeError:get_total_contas()takes0positionalargumentsbut1wasgiven

E agora, o que fazer? Queremos um método que seja chamado via classe e via instância sem anecessidadedepassarareferênciadesteobjeto.OPythonresolveissousandométodosestáticos.

Métodos estáticosnãoprecisamdeuma referência,não recebemumprimeiroargumentoespecial(self).Écomoumafunçãosimplesque,poracaso,residenocorpodeumaclasseemvezdeserdefinidanoníveldomódulo.

Paraqueummétodosejaconsideradoestáticobastaadicionarmosumdecorador,comofizemoscomaspropriedadesnocapítuloanterior.Odecoradorsechama@staticmethod:

@staticmethoddefget_total_contas():returnConta._total_contas

Testando,vemosquefuncionatantochamadoporuminstânciaquantopelaclasse:

>>>c1=Conta(100.0)>>>c1.get_total_contas()1>>>c2=Conta(200.0)>>>c2.get_total_contas()2>>>Conta.get_total_contas()2

Métodosestáticosnãodevemserconfundidoscommétodosdeclasse.Comoosmétodosestáticos,métodosdeclassenãosãoligadosàsinstâncias,massimaclasse.Oprimeiroparâmetrodeummétododeclasseéumareferênciaparaaclasse, istoé,umobjetodotipoclassqueporconvençãonomeamoscomo 'cls'. Eles podem ser chamados via instância ou pela classe e utilizam um outro decorar, o@classmethod:

classConta:

_total_contas=0

8.3MÉTODOSDECLASSE

.

Page 120: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

def__init__(self):type(self)._total_contas+=1

@classmethoddefget_total_contas(cls):returncls._total_contas

Epodemostestar:

>>>c1=Conta(100.0)>>>c1.get_total_contas()1>>>c2=Conta(200.0)>>>c2.get_total_contas()2>>>Conta.get_total_contas()2

Noiníciopodeparecerconfusoqualusar:@staticmethodou@classmethod?Issonãoétrivial.Métodos de classe servem para definir um método que opera na classe, e não em instâncias. Já osmétodosestáticosutilizamosquandonãoprecisamosreceberareferênciadeumobjetoespecial(sejadaclasseoudeumainstância)efuncionacomoumafunçãocomum,semrelação.

Isso ficará mais claro quando avançarmos no aprendizado. No próximo capítulo discutiremosHerança,umconceito fundamentalemOrientaçãoaObjetos.Veremosqueclassespodemter filhaseaproveitarocódigodasclassesmães.Ummétododeclassepodemudaraimplementação,ouseja,podeser reescritopela classe filha. Jáosmétodosestáticosnãopodemser reescritospelas filhas, jáque sãoimutáveisenãodependemdeumreferênciaespecial.

@CLASSMETHODX@STATICMETHOD

Alguns programadores não veem muito sentido em usar métodos estáticos, já que se vocêescreverumafunçãoquenãovaiinteragircomaclasse,bastadefini-lanomódulo.Outrosjácontraargumentam em outra via, considerando herança de classes que veremos em outro capítulo.Indicamos a leitura do artigo 'The Definitive Guide on How to Use Static, Class and AbstractMethods in Python' de Julien Danjou que pode ser acessado pelo link:https://julien.danjou.info/guide-python-static-class-abstract-methods/.

Aprendemos sobre encapsulamento e vimos que é uma boa prática proteger nossos atributosincluindooprefixounderscore em seus nomes, seguindo a convençãoutilizada pelos programadores.Alémdisso,utilizamosproperties para acessar emodificarnossos atributos.Mas comoPython éumalinguagemdinâmica,nada impedequeusuáriosdenossaclasseConta criematributos em tempode

8.4PARASABERMAIS-SLOTS

.

Page 121: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

execução,fazendo,porexemplo:

>>>conta.nome="minhaconta"

Essecódigonãoacusaerroenossaconta ficaabertaamodificações ferindoasegurançadaclasse.Para evitar isso podemos utilizar uma variável embutida noPython chamada__slots__ que podeguardarumalistadeatributosdaclassedefinidospornós:

classConta:

__slots__=['_numero','_titular','_saldo','_limite']

def__init__(self,numero,titular,saldo,limite=1000.0):#inicializaçãodosatributos

#códigoomitido

Agora,quandotentamosadicionarumatributonaclasserecebemosumerro:

>>>conta.nome="minha_conta"Traceback(mostrecentcalllast):File<stdin>,line1,in<module>AttributeError:'Conta'objecthasnoattribute'__dict__'

classConta:

__slots__=['_numero','_titular','_saldo','_limite']

def__init__(self,numero,titular,saldo,limite=1000.0):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite

#restantedocódigo

conta.nome="minha_conta"

ReparequeoerroacusaqueaclasseContanãopossuioatributo__dict__.Aoatribuirumvalorpara__slots__,ointerpretadordoPythonvaientenderquequeremosexcluiro__dict__daclasseContanãosendopossívelcriaratributos,ouseja,impossibilitandoadicionaratributosaodicionáriodaclassequeéresponsávelporarmazenaratributosdeinstância.Portanto,tentarchamarvars(conta)tambémvaigerarumerro:

>>>vars(conta)Traceback(mostrecentcalllast):File<stdin>,line1,in<module>TypeError:vars()argumentmusthave__dict__attribute

Embora__slots__ sejamuitoutilizadoparanãopermitir queusuáriosdenossas classes criemoutrosatributos,essanãoésuaprincipalfunçãonemomotivodesuaexistência.Oqueaconteceéqueo__dict__ desperdiça muita memória. Imagine um sistema grande, com milhões de instâncias deConta-teríamos,consequentemente,milhõesdedicionáriosdeclassearmazenandoseusatributosdeinstância.OPythonnãopodesimplesmentealocarumaquantidadeestáticadememórianacriaçãodeobjetosparaarmazenartodososatributos.Porisso,consomemuitamemóriaRAMsevocêcriarmuitos

.

Page 122: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

objetos.

Para contornar este problema é que se usa o __slots__ e este é seu principal propósito. O__slots__avisaoPythonparanãousarumdicionárioeapenasalocarespaçoparaumconjuntofixodeatributos.

Programadoresviramumareduçãodequase40a50%nousodeRAMusandoessatécnica.

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

1. Adicioneomodificadordevisibilidadeprivado(doisunderscores:__)paracadaatributoemétododasuaclasseConta.TentecriarumaContaemodificaroulerumdeseusatributos"privados".Oqueacontece?

2. Sabendo que no Python não existem atributos privados, como podemos modificar e ler essesatributos?Éumaboapráticafazerisso?

3. Modifiqueoacessopara'protegido'seguindoaconvençãodoPythonemodifiqueoprefixo__porapenas umunderscore _. Crie métodos de acesso em sua classe Conta através do decorator@property.

4. Crienovamenteumacontaeacesseemodifiqueseusatributos.Oquemudou?

5. Modifique sua classe Conta de modo que não seja permitido criar outros atributos além dosdefinidosanteriormenteutilizando__slots__.

6. (Opcional)AdicioneumatributoidentificadornaclasseConta.EsseidentificadordeveterumvalorúnicoparacadainstânciadotipoConta.AprimeiraContainstanciadatemidentificador1,asegunda 2, e assim por diante. Você deve utilizar os recursos aprendidos aqui para resolver esseproblema.

Seuslivrosdetecnologiaparecemdoséculopassado?

8.5EXERCÍCIOS:

.

Page 123: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

.

Page 124: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO9

Quando começamos a programar, uma das principais dúvidas de iniciantes é: "qual ferramenta vouutilizar para escrever código?". A maioria dos códigos das principais linguagens de programaçãopermitemdesenvolveremumarquivoutilizandoumeditordetextocomum.

Algunseditoresde textopossuem ferramentasmais sofisticadasquedãomaiorauxílionahoradedesenvolver como: indentação de código, diferenciação de funções, autocompletamento de código,dentreoutras.

Outraferramenta,maisutilizadaparadesenvolvercódigo,éoquechamamosdeAmbienteIntegradodeDesenvolvimentoouIDE(siglaeminglêsparaIntegratedDevelopmentEnviroment).UmaIDEéumsoftware commuitas funcionalidades que auxiliam no desenvolvimento de código além de possuir acapacidadederodarocódigo.

NestecapítuloapresentaremosaIDEPycharmesuasprincipaisferramentas.

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

O Pycharm é multiplataforma com versões para Windows, MacOS e Linux. O PyCharm édesenvolvidopelaempresaJetBrainseforneceanálisedecódigo,depuradorgráfico,autocompletamento

PYCHARM

9.1IDE

Seuslivrosdetecnologiaparecemdoséculopassado?

9.2PYCHARM

.

Page 125: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

decódigoecapacidadesdenavegaçãoquefacilitamaescritadecódigo.

IDE'sforamdesenvolvidasparacriarcódigomaisrapidamenteecommaioreficiência.VeremosaquiosprincipaisrecursosdoPyCharm.Vocêperceberáqueeleevitaaomáximoatrapalhareapenasgeratrechosdecódigosóbvios,sempreaoseucomando.

Nositeoficialháguiasetutoriaisparainiciantes.Sevocêseinteressar,recomendamosusaroguiainicialnestelink:https://www.jetbrains.com/help/pycharm/meet-pycharm.html

Com o PyCharm você pode desenvolver em Python. A versão Profissional dá suporte paradesenvolvimentodeaplicaçõeswebcomDjango,FlaskePyramid.OPycharmtambémsuportaHTML,CSS, JavaScript e XML. Suporte para outras linguagens também podem ser adicionadas baixandoplugins.

OUTRASIDES

OutraIDEfamosanoPythonéoIDLEquepossuibemmenosrecursosdoqueoPyCharmmastambémébastanteutilizadopelacomunidade.

No site oficial da Python Brasil existem uma lista imensa de outras IDEs:https://wiki.python.org.br/IdesPython.

Se você ainda não possui o PyCharm, faça o download nesta página:https://www.jetbrains.com/pycharm/.

9.3DOWNLOADEINSTALAÇÃODOPYCHARM

.

Page 126: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Existem duas versões, a Professional e a Commmunity. A versão paga (a Professional) possuifuncionalidadesextrascomosuporteparadesenvolvimentodeaplicaçõeswebe integraçãocombancode dados. Para o curso, a versão Community será suficiente. Para o download, siga as instruçõesdependendodeseusistemaoperacional.

Se você precisar de ajuda para fazer a instalação, consulte as instruções de instação neste link:https://www.jetbrains.com/help/pycharm/install-and-set-up-pycharm.html

AoabriroPyCharmpelaprimeiravez,umajanelachamadaCreateProjectaparecerá.Énelaquedefinimostodasasconfiguraçõesnecessárias.

9.4CRIANDOUMPROJETO

.

Page 127: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Podemoscriarumnovoprojetoaqualquermomento.Parafazerisso,bastaclicaremFile->NewProjectnomenusuperiordajanelaprincipaldoPyCharm.

Primeiro,especificamosonomedoprojeto-nonossocasoseráapenasbanco.NotequeoPyCharmsugereumlocalpadrãoparasalvaroprojeto.Vocêpodeaceitareste localouconfigurarmanualmenteno campoLocation. Vamos optar pelo caminho padrão. Ao fazer isso, a IDE vai criar uma pastachamadaPyCharmProjectsnasuapastahome.

Após isso, escolhemos a versão do interpretador que usaremos no projeto. O PyCharm cria umambienteisoladodainstalaçãopadrãodosistemaoperacional(nocasodoLinuxeMacOS).Issoémuitoimportante e não causa concorrência comoutras bibliotecas instaladas em seu computador. Por fim,clicamosemCreateenossoprojetoécriado.

Nosso projeto tem uma estrutura padrão. A pasta venv é o ambiente isolado do sistemaoperacional.Nela contémaversãodo interpretadorPythonque selecionamosnacriaçãodoprojetoeseus módulos embutidos (builtins) - você pode checar isso na pasta lib . A qualquer momentopodemosincluirnovasbibliotecasaoprojeto.

Vamos iniciar nosso projeto criando a classeConta. Antes, precisamos criar uma pasta raiz doprojeto.VáemFile->New->Directory.

.

Page 128: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Definimosumnomeparanossodiretórioeclicamosem 'OK'.Vamoscriarumdiretóriochamadosrc:

Paradefini-locomopastaraiz,vamosclicarcomobotãodireitodomousenodiretório,navegaratéMarkDirectoryaseescolherSourcesRoot.Vocênotaráqueapastamudadacorcinzaparaazul.

.

Page 129: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Agoravamoscriaroarquivoconta.pyqueconteránossaclasseConta.Paraisso,cliquecomobotãodireitodomouseemsrceváemNew->PythonFile:

Digiteonomedoarquivoecliqueem'OK'.Vamosnomearoarquivocomoconta:

Agoraéamelhorhoradeaprenderalgonovo

9.5CRIANDOUMACLASSE

.

Page 130: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

OutramaneiradecriarumarquivopythonéclicarnapastasrcedigitaroatalhoALT+Inserteajanelaparavocêentrarcomonomedoarquivovaiaparecer.

Umanovaabavaiaparecercomonomedomóduloquecriamos,àdireitadomenudenavegaçãodoprojeto. Vamos começar a escrever o código de nossa classe Conta. Você vai notar que quandocomeçamosadigitarapalavraclassoPyCharmvaiteoferecersugestõesparavocêescolher.Comeceescrevendoapalavraclass(exemplo:'cl')eelevaiterminardedigitarpravocê:

Vamos agora escrever ométodo__init__().Aqui tambémoPycharmvai nos ajudar. Escrevaapenas"defi"eoPyCharmvaitedarnovamentesugestões:

.

Page 131: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Escolhaaprimeiraopção__init__(self)eaperteENTER.Vaigerarocódigo:

classConta:

def__init__(self):

FaçaométodoinicializadorrecebercomoparâmetroosvaloresdoatributosdeumaConta,ouseja,receberonumero,titular,saldoelimite:

classConta:

def__init__(self,numero,titular,saldo,limite=1000.0):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite

Agoravamostestarnossaclasse.OPycharmpossuiumconsoledoPythonembutido,paraabrí-lováemTools->PythonConsole.Vocêvainotarquea janeladoconsolevaiabrirabaixodoarquivoconta:

Vamosimportaromódulocontacomocomandofromsrc.contaimportConta,instanciarumaContaeacessarseusatributos:

9.6EXECUTANDOCÓDIGO

.

Page 132: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Reparequeoconsoletambémpossuiaferramentadeautocomplete.Parareiniciá-lobastaclicarnoprimeiroíconedomenuesquerdodoconsole.

AIDEtambémpermiteabriroterminaleusaromodointerativoparatestes.OatalhoparaabriroterminaléALT+F12.OPythonConsoledoPycharmémaisaconselhávelparaissoeoterminalémaisutilizadoparainstalarnovaslibsaoseuprojeto.

Masusaremosoconsoleapenasparatestes.Vamosexecutarocódigodiretamentedonossoarquivoconta. Para isso precisamos acrescentar a condicional if __name__ == '__main__': e fazer osmesmostestesquefizemosnoconsoledentrodestacondiçãoif.Bastavocêescrever"main"edigitarENTERqueoPycharmcriaacondicionalparavocê:

if__name__=='__main__':

AgoravamosinstanciareimprimirosatributosdeumaContacomofizemosutilizandooPythonConsole.Nãoesqueçadeutilizarafunçãoprintnahorademostrarosatributosjáquenãoestamosmaisnomodointerativo:

if__name__=='__main__':conta=Conta('123-4','João',1000.0)print(conta.numero)print(conta.titular)print(conta.saldo)print(conta.limite)

ParaexecutarváemRun->RunoucliquecomobotãodireitodomousenointeriordoarquivocontaeescolhaaopçãoRun'conta'.Ouainda,digiteoatalhoCTRL+Shift+F10quevaiteromesmoefeito.Depoisdeterrodadopelaprimeiravez,paravocêrodarnovamentebastaclicarnoíconedeumapequenasetaverdenomenusuperiordaIDE:

.

Page 133: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Vamos criar nosso primeiro método. Primeiro, dentro da condicional main, vamos digitar aseguintelinhadecódigo:

conta.deposita(100.0)

Se executarmos esse códigoonossoprogramaquebra já que a classeConta aindanãopossui ométododeposita().Paracriá-lo,coloqueocursordomousenapalavra"deposita"euseoatalhoALT+ENTER,váriassugestõesdoPycharmirãoaparecer.CliqueemAddmethoddeposita()toclassConta:

EoPycharmvaicriaradeclaraçãodométodoparavocê:

Viucomoéfácilerápido?Agorabastatrocarapalavraparamporvalor,apagarapalavrapass

9.7CRIANDOMÉTODOS

.

Page 134: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

eadicionaraimplementaçãodométodo:

defdeposita(self,valor):self._saldo+=valor

NopróximoexercíciovamoscriarnossoprimeiroprojetodobancoenossaclasseContautilizandooPycharmepraticaroqueaprendemosdeorientaçãoaobjetosesobreaIDEatéaqui.

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

OPycharmpossuimuitosatalhosúteisnahoradedesenvolver.Abaixoestãoosprincipaisdelesparavocêconhecerepraticar:

ALT+INSERT:crianovoarquivo

ALT+ENTER:sugereaçõeseconsertaerrosrápidos

CTRL+ESPAÇO:autocomplete

CTRL+N:buscaclasses

CTRL+SHIFT+N:buscaarquivos

CTRL+ALT+M:extraircódigoparaummétodo

CTRL+ALT+V:extrairparaumavariável

CTRL+ALT+SHIFT+T:refatoração(renomear)

CTRL+A:selecionatudo

CTRL+SHIFT+LEFT/RIGHT:selecionapartedotextoaesquerdaouadireita.

EditoraCasadoCódigocomlivrosdeumaformadiferente

9.8PRINCIPAISATALHOS

.

Page 135: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CTRL+SHIFT+PAGEDOWN/PAGEUP-movelinhaparacimaouparabaixo

ALT+J:procurapróximapalavraselecionada

A JetBrains fez uma tabela com todos os atalhos que você pode checar neste link:resources.jetbrains.com/storage/products/pycharm/docs/PyCharm_ReferenceCard.pdf

1. AbraoPycharmeváemFile->NewProject.Ajanelaabaixovaiaparecer.Troqueapalavrauntitledpelonomedonossoprojetoqueserábanco:

VerifiqueseaversãodoPythonestácorretaemBaseinterpreterecliqueemOK.

2. Nomenuesquerdovaiapareceraestruturadoprojeto.Vamosdefinirumapastaraizondeficarãonossosarquivosdecódigopython.CliquecomobotãodireitonapastabancoeescolhaaopçãoNewFolder.Umanovajanelavaiaparecerparavocêentrarcomonomedodiretório,digitesrceOK:

9.9EXERCÍCIO-CRIANDOPROJETOBANCONOPYCHARM

.

Page 136: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

3. Após isso, clicamos com o botão direito na pasta src e selecionamos Mark Directory as ->SourcesRoots para avisar oPyCharmque esta pasta será umdiretório fonte denossoprojeto,ondeficarãonossosarquivos.py.

Reparequeapastaficarádacorazuldepoisdeexecutardestaação:

4. Agora vamos criar nossa classe Conta que ficará no arquivo conta.py . Vamos fazer isso

.

Page 137: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

utilizandoumatalhodoPyCharm.ColoqueocursordomousenapastasrcedigiteALT+Insert.EscolhaaopçãoPythonFile.Umanovajanelavaiabrir,digite"conta"ecliqueemOK.

5. Oarquivoseráabertoaesquerda.Vamoscomeçaracriarnossaclasse.AocomeçarescreverafunçãoinitaprópriaIDEvaimostraropçõesemumajanela,bastaclicarqueeleauto-completaparavocêjácomaargumento'self'.AdicioneosatributosdeumaContacomofizemosnoexercíciodocapítuloanterior:

classConta:

def__init__(self,numero,titular,saldo,limite):self._numero=numeroself._titular=titularself._saldo=saldoself._limite=limite

Aproveiteacrieaspropertiesdecadaatributo.AbusedoCTRL+ESPAÇOparaaIDEautocompletarparavocêedoALT+ENTERparasugestões.

6. Em seguida criamos a condicional para que o PyCharm rode algumas linhas de código caso o__name__sejaiguala__main__,ouseja,oprogramaprincipal.OPycharmtambémfacilitaestacriação,bastadigitarapalavra'main'eapertarCTRL+ESPAÇOqueaestruturadoiféconstruídaparavocê:

if__name__=='__main__':

Vamoscriarumanovacontaeimprimirotitular:

if__name__=='__main__':conta=Conta('123-4','joão',1200.0,1000.0)print(conta.titular)

7. Pararodar,bastaclicarcomobotãodireitodomouseeescolheraopçãoRun'conta'ouutilizaro

.

Page 138: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

atalhoCtrl+Shift_F10.Ou ainda escolher a opção da barra de ferramentas como símbolo deplaydacorverde.Oresultadovaiaparecernoconsole,najanelainferiordaIDE.

8. Crieosmétodosdeposita(),saca(),extrato() etransfere_para() como fizemosnoúltimoexercício.AproveiteosrecursosdaIDEqueaprendemosparacriar todosessesmétodos.Apropriedadesetterdosaldoénecessária?

9. Crieduascontasetesteosmétodosquevocêcriounoexercícioanterior.

10. (Opcional)Crieumarquivopythonchamadocliente.pyecrieaclasseClientecomnome,sobrenomeecpf.TesteocódigopassandoumclientecomotitulardeumConta.Aproveiteeadicionealgunsmétodosaela.

VejaqueaIDEfacilitabastantenahoradodesenvolvimentoeganhamostempotambémrodandooscriptdiretamentenoPyCharm.

.

Page 139: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO10

Como toda empresa, nosso banco possui funcionários.Um funcionário temumnome, um cpf e umsalário.VamosmodelaraclasseFuncionario:

classFuncionario:

def__init__(self,nome,cpf,salario):self._nome=nomeself._cpf=cpfself._salario=salario

#outrosmétodosepropriedades

Alémdeumfuncionáriocomum,hátambémoutroscargos,comoosgerentes.Osgerentesguardama mesma informação que um funcionário comum, mas possuem outras informações, além de terfuncionalidadesumpoucodiferentes.Umgerentenonossobancopossuitambémumasenhanuméricaquepermiteoacessoaosistemainternodobanco,alémdonúmerodefuncionáriosqueelegerencia:

classGerente:

def__init__(self,nome,cpf,salario,senha,qtd_gerenciados):self._nome=nomeself._cpf=cpfself._salario=salarioself._senha=senhaself._qtd_gerenciados=qtd_gerenciados

defautentica(self,senha):ifself._senha==senhaprint("acessopermitido")returnTrueelse:print("acessonegado")returnFalse

#outrosmétodos(comunsaumFuncionario)

Se tivéssemos um outro tipo de funcionário que tem características diferentes do funcionáriocomum,precisaríamoscriarumaoutraclasseecopiarocódigonovamente.

Além disso, se um dia precisarmos adicionar uma nova informação para todos os funcionários,precisaremospassarportodasasclassesdefuncionárioeadicionaresseatributo.Oproblemaacontecenovamentepornãocentralizarmosasinformaçõesprincipaisdofuncionárioemumúnicolugar!

HERANÇAEPOLIMORFISMO

10.1REPETINDOCÓDIGO?

.

Page 140: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Existeumjeitoderelacionarmosumaclassedetalmaneiraqueumadelasherdatudoqueooutratem. Isto é uma relação de herança, uma relação entre classe 'mãe' e classe 'filha'. No nosso caso,gostaríamosdefazercomqueGerentetivessetudoqueumFuncionariotem,gostaríamosqueelafosseumaextensãodeFuncionario.Fazemosissoacrescentandoaclassemãeentreparentesesjuntoaclassefilha:

classGerente(Funcionario):

def__init__(self,senha,qtd_funcionarios):self._senha=senhaself._qtd_funcionarios=qtd_funcionarios

defautentica(self,senha):ifself._senha==senha:print("acessopermitido")returnTrueelse:print("acessonegado")returnFalse

TodomomentoquecriarmosumobjetodotipoGerentequeremosqueesteobjetotambémherdeosatributosdefinidosnaclasseFuncionario,poisumGerenteéumFuncionário.

ComoaclasseGerente jápossuiummétodo__init__() comoutros atributos, ométododaclasse Funcionario é sobrescrito pelo Gerente. Se queremos incluir os mesmos atributos deinstância de Funcionario em um Gerente devemos chamar o método __init__() deFuncionariodentrodométodo__init__()deGerente:

classGerente(Funcionario):

def__init__(self,senha,qtd_funcionarios):Funcionario.__init__(nome,cpf,salario)self._senha=senhaself._qtd_funcionarios=qtd_funcionarios

defautentica(self,senha):ifself._senha==senha:print("acessopermitido")returnTrueelse:print("acessonegado")returnFalse

.

Page 141: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

DizemosqueaclasseGerenteherdatodososatributosemétodosdaclassemãe,nonossocaso,aFuncionario.ComoPythontemtipagemdinâmica,precisamosgarantirissoatravésdoconstrutordaclasse.Alémdesenhaeqtd_funcionariospassamostambémosatributosnome,cpfesalarioquetodofuncionáriotem:

classGerente(Funcionario):

def__init__(self,nome,cpf,salario,senha,qtd_funcionarios):self._senha=senhaself._qtd_funcionarios=qtd_funcionarios

Como estes são atributos de um Funcionario e não queremos repetir o código do método__init__()deFuncionariodentrodaclasseGerente,podemoschamarestemétododaclassemãecomofizemosnoexemploacimaoupodemosutilizarummétododoPythonchamadosuper():

classGerente(Funcionario):

.

Page 142: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

def__init__(self,nome,cpf,salario,senha,qtd_funcionarios):super().__init__(nome,cpf,salario)self._senha=senhaself._qtd_funcionarios=qtd_funcionarios

Para sermais preciso, ela também herda os atributos emétodos 'privados' de Funcionario. Osuper() é usado para fazer referência a superclasse, a classe mãe - no nosso exemplo a classeFuncionario.

PARASABERMAIS:SUPERESUBCLASSE

AnomenclaturamaisencontradaéqueFuncionarioéasuperclassedeGerente,eGerenteéasubclassedeFuncionario.Dizemos tambémque todoGerenteéum Funcionario.Outra forma édizerqueFuncionarioéaclassemãedeGerenteeGerenteéaclassefilhadeFuncionario.

Da mesma maneira, podemos ter uma classe Diretor que estenda Gerente e a classePresidente pode estender diretamente de Funcionario. Fique claro que essa é uma relação denegócio. SeDiretor vai estender deGerente ou não, vai depender, para você, Diretor é umGerente?

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

JáconheceoscursosonlineAlura?

.

Page 143: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Todo fim de ano, os funcionários do nosso banco recebem uma bonificação. Os funcionárioscomunsrecebem10%dovalordosalárioeosgerentes,15%.

VamosvercomoficaaclasseFuncionario:

classFuncionario:

def__init__(self,nome,cpf,salario):self._nome=nomeself._cpf=cpfself._salario=salario

#outrosmétodoseproperties

defget_bonificacao(self):returnself._salario*0.10

SedeixarmosaclasseGerentecomoelaestá,elavaiherdarométodoget_bonificacao()

gerente=Gerente('José','222222222-22',5000.0,'1234',0)print(gerente.get_bonificacao())

Oresultadoaquiserá500.Nãoqueremosessaresposta,poisogerentedeveriater750debônusnessecaso.Paraconsertarisso,umadasopçõesseriacriarumnovométodonaclasseGerente,chamado,porexemplo,get_bonificacao_do_gerente().OproblemaéqueteríamosdoismétodosemGerente,confundindo bastante quem for usar essa classe, além de que cada um gerenciaria uma respostadiferente.

No Python, quando herdamos um método, podemos alterar seu comportamento. Podemosreescrever(sobrescrever,override)estemétodo,assimcomofizemoscomo__init__:

classGerente(Funcionario):

def__init__(self,nome,cpf,salario,senha,qtd_gerenciaveis):super().__init__(nome,cpf,salario)self._senha=senhaself._qtd_gerenciaveis=qtd_gerenciaveis

defget_bonificacao(self):returnself._salario*0.15

#metodoseproperties

AgoraométodoestácorretoparaoGerente.Refaçaotesteevejaqueovalorimpressoéocorreto(750):

gerente=Gerente('José','222222222-22',5000.0,'1234',0)print(gerente.get_bonificacao())

Utilizeométodovars()paraacessarosatributosdeGerenteeverqueaclasseherdatodososatributosdeFuncionario:

funcionario=Funcionario('João','111111111-11',2000.0)

10.2REESCRITADEMÉTODOS

.

Page 144: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

print(vars(funcionario))

gerente=Gerente('José','222222222-22',5000.0,'1234',0)print(vars(gerente))

Saída:

{'_salario':2000.0,'_nome':'João','_cpf':'111111111-11'}{'_cpf':'222222222-22','_salario':5000.0,'_nome':'José','_qtd_funcionarios':0,'_senha':'1234'}

Depoisde reescrito,nãopodemosmais chamarométodoantigoque foraherdadoda classemãe,realmente alteramos o seu comportamento. Mas podemos invocá-lo no caso de estarmos dentro daclasse.

Imagine que para calcular a bonificação de umGerente devemos fazer igual ao cálculo de umFuncionarioadicionando1000.0reais.Poderíamosfazerassim:

classGerente(Funcionario):

def__init__(self,senha,qtd_gerenciaveis):self._senha=senhaself._qtd_gerenciaveis=qtd_gerenciaveis

defget_bonificacao():returnself._salario*0.10+1000.0

#métodoseproperties

Aqui teríamos um problema: o dia que o get_bonificacao() do Funcionario mudar,precisaremosmudarométododoGerente para acompanhar anovabonificação.Para evitar isso,oget_bonificacao()doGerentepodechamarodoFuncionarioutilizandoométodosuper().

classGerente(Funcionario):

def__init__(self,senha,qtd_gerenciaveis):self._senha=senhaself._qtd_gerenciaveis=qtd_gerenciaveis

defget_bonificacao():returnsuper().get_bonificacao()+1000

#métodoseproperties

Essa invocaçãovaiprocurarométodocomonomeget_bonificacao() deuma superclassedeGerente.Nocaso,elelogovaiencontraressemétodoemFuncionario.

Essaéumapráticacomum,poisemmuitoscasosométodoreescritogeralmentefazalgoamaisqueométododaclassemãe.Chamarounãoométododecimaéumadecisãoedependedoseuproblema.Algumasvezesnãofazsentidoinvocarométodoquereescrevemos.

Para escrever uma classe utilizando o Python 2 é preciso acrescentar a palavra 'object' quando

10.3INVOCANDOOMÉTODOREESCRITO

.

Page 145: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

definimosumaclasse:

classMinhaClasse(object):pass

Isso aconteceporque toda classe é filhadeobject - que é chamada amãede todas as classes.NoPyhton,todaclasseherdadeobject.NoPython3nãoprecisamosacrescentaroobjectmasnãoquerdizerqueestaclasseeaherançanãoexistam,apenasqueessaherançaéimplícita.Quandocriamosumaclassevaziaeutilizamosométododir()parachecaralistadeseusatributos,reparamosqueelanãoévazia:

classMinhaClasse():pass

if__name__=='__main__':mc=MinhaClasse()print(dir(mc))

Geraasaída:

['__class__','__delattr__','__dict__','__dir__','__doc__','__eq__','__format__','__ge__','__getattribute__','__gt__','__hash__','__init__','__init_subclass__','__le__','__lt__','__module__''__ne__','__new__','__reduce__','__reduce_ex__','__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','__weakref__']

Todosestesatributossãoherdadosdaclasseobjectepodemosreescreverqualquerumdelesnanossasubclasse.Todoselessãoosconhecidosmétodos'mágicos'(começameiniciamcomdoisunderscores,eporestemotivo,tambémchamadosdedunders).

Vimosocomportamentodo__init__(),__new__()edo__dict__.Outrosmétodosmágicosfamosossão__str__()e__repr__()-métodosqueretornamarepresentaçãodoobjetocomoumastring.Quandochamamosprint(mc)temosasaída

<__main__.MinhaClasseobjectat0x7f11c1f59a58>

Esse éomodelopadrãode impressãodeumobjeto, implementadona classeobject.A funçãoprint() na verdade usa a string definida pelo método __str__() de uma classe. Vamosreescreverestemétodo:

classMinhaClasse:

def__str__(self):return'<Instânciade{};endereço:{}>'.format(self.__class__.__name__,id(self))

Agora,quandoexecutamosprint(mc),asaídaé:

<InstânciadeMinhaClasse;endereço:0x7f11c1f59a58>

OPythonsemprechamaométodo__str__()quandoutilizaafunçãoprint()emumobjeto.Novamente,estamosutilizandoreescritademétodos.

Ométodo__repr__()tambémretornaumastringepodemosutilizarafunçãorepr()parachecarseuretorno:

.

Page 146: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

classMinhaClasse():pass

if__name__=='__main__':mc=MinhaClasse()print(repr(mc))

Quevaigeraramesmasaídapadrãodo__str__():

<__main__.MinhaClasseobjectat0x7f11c1f59a58>

Masdiferentedo__str__(), não é comum sobrescrever estemétodo.Ele é sobrescritoquandoprecisamosutilizá-lojuntocomafunçãoeval()doPython.Afunçãoeval()recebeumastringetentaexecutaressastringcomoumcomandodoPython,vejaumexemplodeuso:

>>>x=1>>>eval("x+1")2

Vamosaumexemploutilizandoclasses:

classPonto:

def__init__(self,x,y):self.x=xself.y=y

def__str__(self):return"({},{})".format(self.x,self.y)

def__repr__(self):return"Ponto({},{})".format(self.x+1,self.y+1)

if__name__=='__main__':p1=Ponto(1,2)p2=eval(repr(p1))

print(p1)print(p2)

Seexecutarmosocódigoacima,temos:

(1,2)(2,3)

Reparequeutilizamosafunçãorepr()passandoumainstânciadePonto.OPythonvaichamarentãoométodo__repr__()daclassePonto,queretornaastring"Ponto(2,3)"jáquep1.x=1ep1.y=2.Aopassá-ladeargumentoparaafunçãoeval(),teremos:p2=eval('Ponto(2,3)).Comoafunçãoeval()vaitentarexecutaressastringcomoumcomandoPythonválido,elevaitersucessoeportantop2seráumanovainstânciadaclassePontocomp2.x=2ep2.y=3.

Paraconcluir,é importanteentenderque tanto__str__()quanto__repr__() retornamumastringquerepresentaoobjetomascompropósitosdiferentes.Ométodo__str__()éutilizadoparaapresentarmensagensparaosusuáriosdaclasse,demaneiramaisamigável.Jáométodo__repr__()éusadopararepresentaroobjetodemaneiratécnica,inclusivepodendoutilizá-locomocomandoválido

.

Page 147: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

doPythoncomovimosnoexemplodaclassePonto.

Os métodos mágicos são úteis pois permitem que os objetos de nossas classes possuam umainterface de acesso semelhante aos objetos embutidos do Python. O método __add__(), porexemplo, serve para executar a adição de dois objetos e é chamada sempre quando fazemos aoperaçãodeadição(obj+obj)utilizandoooperador'+'.Porexemplo,quandofazemos1+1noPython,oqueointerpretadorfazéchamarométodo__add__()daclasseint.Vimosqueumalisttambémimplementaométodo__add__()jáqueaoperaçãodeadiçãoédefinidaparaestaclasse:

>>>lista=[1,2,3]>>>lista+[4,5][1,2,3,4,5]

O mesmo ocorre para as operações de multiplicação, divisão, módulo e potência que sãodefinidas pelos métodos mágicos __mul__() , __div__() , __mod__() e __pow__() ,respectivamente.

Podemos definir cada uma dessas operações em nossas classes sobrescrevendo tais métodosmágicos. Além desses o Python possui muitos outros que você pode acessar aqui:https://docs.python.org/3/reference/datamodel.html#Basic_customization

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

OqueguardaumavariáveldotipoFuncionario?UmareferênciaparaumFuncionario,nuncao

10.4PARASABERMAIS-MÉTODOSMÁGICOS

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

10.5POLIMORFISMO

.

Page 148: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

objetoemsi.

Naherança,vimosquetodoGerenteéumFuncionario,poiséumaextensãodeste.Podemosnos referir a um Gerente como sendo um Funcionario . Se alguém precisa falar com umFuncionariodobanco,podefalarcomumGerente!Porque?PoisGerenteéumFuncionario.Essaéasemânticadaherança.

Polimorfismo é a capacidade de um objeto poder ser referenciado de várias formas. (cuidado,polimorfismonãoquerdizerqueoobjetoficasetransformando,muitopelocontrário,umobjetonascedeumtipoemorredaqueletipo,oquepodemudaréamaneiracomonosreferimosaele).

A situação que costuma aparecer é a que temos ummétodo que recebe um argumento do tipoFuncionario:

classControleDeBonificacoes:

def__init__(self,total_bonificacoes=0):self._total_bonificacoes=total_bonificacoes

defregistra(self,funcionario):self._total_bonificacoes+=funcionario.get_bonificacao()

@propertydeftotal_bonificacoes(self):returnself._total_bonificacoes

Epodemosfazer:

if__name__=='__main__':funcionario=Funcionario('João','111111111-11',2000.0)print("bonificacaofuncionario:{}".format(funcionario.get_bonificacao()))

gerente=Gerente("José","222222222-22",5000.0'1234',0)print("bonificacaogerente:{}".format(gerente.get_bonificacao()))

controle=ControleDeBonificacoes()controle.registra(funcionario)controle.registra(gerente)

print("total:{}".format(controle.total_bonificacoes))

quegeraasaída:

bonificacaofuncionario:200.0bonificacaogerente:1500.0total:1700.0

Repareque conseguimospassarumGerente para ummétodo que "recebe" umFuncionariocomo argumento. Pense como numa porta na agência bancária com o seguinte aviso: "Permitida aentrada apenas de Funcionários". Um gerente pode passar nessa porta? Sim, pois Gerente é umFuncionario.

Qual será o valor resultante? Não importa que dentro do método registra() do

.

Page 149: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

ControleDeBonificacoesrecebaFuncionario.QuandoelereceberumobjetoquerealmenteéumGerente,oseumétodoreescritoseráinvocado.Reafirmando:nãoimportacomonosreferenciamosaumobjeto,ométodoqueseráinvocadoésempreoqueédele.

No dia em que criarmos uma classe Secretaria, por exemplo, que é filha de Funcionario,precisaremosmudaraclasseControleDeBonificacoes?Não.BastaaclasseSecretariareescreverosmétodosquelhepareceremnecessários.Éexatamenteesseopoderdopolimorfismo,juntamentecomareescritademétodo:diminuiroacoplamentoentreasclasses,paraevitarquenovoscódigosresultememmodificaçõeseminúmeroslugares.

ReparequequemcriouControleDeBonificacoespodenunca ter imaginadoacriaçãodaclasseSecretaria ouEngenheiro. Contudo, não será necessário reimplementar esse controle em cadanovaclasse:reaproveitamosaquelecódigo.

Pensardestamaneiraem linguagenscomtipagemestáticaéomaiscorreto jáqueasvariáveis sãotipadas e garantem, através do compilador, que o método só funcionará se receber um tipoFuncionario.Masnãoéoqueaconteceem linguagensde tipagemdinâmicacomoPython.Vamossuporquetemosumaclassepararepresentarosclientesdobanco:

classCliente:

def__init__(self,nome,cpf,senha):self._nome=nomeself._cpf=cpfself._senha=senha

#métodoseproperties

Nada impede de registrarmos um Cliente em ControleDeBonificacoes. Vamos ver o queacontece:

cliente=('Maria','333333333-33','1234')controle=ControleBonificacoes()controle.registra(cliente)

Saída:

File"<stdin>",line99,in<module>controle.registra(cliente)File"<stdin">,line67,inregistaself._total_bonificacoes+=funcionario.get_bonificacao()AttributeError:'Cliente'objecthasnoattribute'get_bonificacao'

VejaquelançaumAttibuteErrorcomamensagemdizendoqueClientenãopossuioatributoget_bonificacao.Portanto, aquinão importa seoobjeto recebidonométodoregistra() é umFuncionario,masseelepossuiométodoget_bonificacao().

Ométodoregistra()utilizaummétododaclasseFuncionario e, portanto, funcionará comqualquer instância de uma subclasse de Funcionario ou qualquer instância de uma classe queimplementeométodoget_bonificacao().

.

Page 150: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Podemos evitar este erro verificando se o objeto passado possui ou não um atributoget_bonificacao()atravésdafunçãohasattr():

classControleDeBonificacoes:

def__init__(self,total_bonificacoes=0):self._total_bonificacoes=total_bonificacoes

defregistra(self,obj):if(hasattr(obj,'get_bonificacao'))self._total_bonificacoes+=obj.get_bonificacao()elseprint('instânciade{}nãoimplementaométodoget_bonificacao()'.format(self.__class__.__name__))

#demaismétodos

A funçãohasattr() recebe dois parâmetros, o objeto e o atributo (na formadestring) - everificaseoobjetopossuiaqueleatributo,ouseja,seoatributoestácontidono__dict__doobjeto.Então,fazemosapergunta:get_bonificacao()éatributodeFuncionario?Sesim,entranoblocoifepodemoschamarométodotranquilamente,evitandoerros.

Agora,setentarmoschamarométodoregistra()passandoumClienterecebemosasaída:

'Cliente'objecthasnoattribute'get_bonificacao

Portanto,otipopassadoparaométodoregistra()nãoimportaaquiesimseoobjetopassadoimplementa ou não o método get_bonificacao() . Ou seja, basta que o objeto atenda a umdeterminadoprotocolo.

ExisteumafunçãonoPythonquefuncionadeformasemelhantemasconsideraotipodainstância,éafunçãoisinstance().Aoinvésdepassarumainstância,passamosaclassenosegundoparâmetro.

classControleDeBonificacoes:

def__init__(self,total_bonificacoes=0):self.__total_bonificacoes=total_bonificacoes

defregistra(self,obj):if(isinstance(obj,Funcionario)):self.__total_bonificacoes+=obj.get_bonificacao()else:print('instânciade{}nãoimplementaométodoget_bonificacao()'.format(self.__class__.__name__))

MasessanãoéamaneiraPythônica.Vocêdeveescreverocódigoesperandosomenteumainterfacedoobjeto,nãootipodele.Ainterfaceéoconjuntodemétodospúblicosdeumaclasse.NocasodanossaclasseControleDeBonificacoes, ométodoregistra() espera um objeto que possua ométodoget_bonificacao()enãoumobjetodotipoFuncionario.

10.6DUCKTYPING

.

Page 151: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

UmacaracterísticadelinguagensdinâmicascomoPythonéachamadaDuckTyping,atipagemdepato.Éumacaracterísticadeumsistemadetiposemqueasemânticadeumaclasseédeterminadapelasua capacidade de responder a alguma mensagem, ou seja, responder a determinado atributo (oumétodo).Oexemplocanônico(earazãodonome)éotestedopato:seeleseparececomumpato,nadacomoumpatoegrasnacomoumpato,entãoprovavelmenteéumpato.

Vejaoexemploabaixo:

classPato:defgrasna(self):print('quack!')

classGanso:defgrasna(self):print('quack!')

if__name__=='__main__':pato=Pato()print(p.grasna())

ganso=Ganso()print(g.grasna())

Quegeraasaída:

quack!quack!

Vocêdeveescreverocódigoesperandosomenteumainterfacedoobjeto,nãoumtipodeobjeto.NocasodanossaclasseControleDeBonificacoes,ométodoregistra()esperaumobjetoquepossuaométodoget_bonificacao()enãoapenasumfuncionário.

ODuckTypingéumestilodeprogramaçãoquenãoprocuraotipodoobjetoparadeterminarseeletema interface correta.Ao invésdisso, ométodoou atributo é simplesmente chamadoouusado ('separececomoumpatoegrasnacomoumpato,entãodeveserumpato').DuckTypingevitatestesusandoasfunçõestype(),isinstance()eatémesmoahasattr()-aoinvésdisso,deixaoerroestourarnafrentedoprogramador.

AmaneiraPythônicaparagarantiraconsistênciadosistemanãoéverificarostiposeatributosdeumobjeto,maspressuporaexistênciadoatributonoobjetoetratarumaexceção,casoocorra,atravésdocomandotry/except:

try:self._total_bonificacoes+=obj.get_bonificacao()exceptAttributeErrorase:print(e)

Estamospedindoaointerpretadorparatentarexecutaralinhadecódigodentrodocomandotry(tentar).Casoocorraalgumerro,elevaitrataresteerrocomocomandoexcepteexecutaralgo,comoimprimiroerro(similaraoexemplo).Nãosepreocupedeentenderosdetalhessobreestecódigoeousodotry/exceptnestemomento,teremosumcapítulosóparafalardeles.

.

Page 152: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

O que é importante é que a maneira pythônica de se fazer é assumir a existência do atributo ecapturar(tratar)umexceçãoquandooatributonãopertenceraoobjetoeseguirofluxodoprograma.Porora,faremosestachecagemutilizandoafunçãohasattr().

HERANÇAVERSUSACOPLAMENTO

Notequeousodeherançaaumentaoacoplamentoentreasclasses,istoé,oquantoumaclassedependedeoutra.Arelaçãoentreclassemãeefilhaémuitoforteeissoacabafazendocomqueoprogramadordas classes filhas tenhaqueconhecera implementaçãodaclassemãeevice-versa -ficadifícilfazerumamudançapontualnosistema.

Por exemplo, imagine se tivermos quemudar algo na nossa classeFuncionario, mas nãoquiséssemosquetodososfuncionáriossofressemamesmamudança.Precisaríamospassarporcadauma das filhas de Funcionario verificando se ela se comporta como deveria ou se devemossobrescreverotalmétodomodificado.

Esseéumproblemadaherança,enãodopolimorfismo,queresolveremosmaistarde.

Vamos ter mais de um tipo de conta no nosso sistema. Portanto, além das informações que játínhamosnaconta,temosagoraotipo:sequeremosumacontacorrenteouumacontapoupança.Alémdisso,cadaumadevepossuirumataxa.

1. AdicionenaclasseContaumnovométodochamadoatualiza()*queatualizaacontadeacordocomataxapercentual:

classConta:

#outrosmétodos

defatualiza(self,taxa):self._saldo+=self._saldo*taxa

2. CrieduassubclassesdaclasseConta:ContaCorrenteeContaPoupanca.Ambasterãoométodo atualiza() reescrito: a ContaCorrente deve atualizar-se com o dobro da taxa e aContaPoupanca deve atualizar-se com o triplo da taxa. Além disso, a ContaCorrente devereescrever o método deposita() afim de retirar uma taxa bancária de dez centavos de cadadepósito.

CrieaclasseContaCorrentenoarquivoconta.py e façacomqueela seja subclasse (filha)daclasseConta.

classContaCorrente(Conta):

10.7EXERCÍCIO:HERANÇAEPOLIMORFISMO

.

Page 153: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

pass

CrieaclasseContaPoupancanoarquivoconta.pyefaçacomqueelasejasubclasse(filha)daclasseConta:

classContaPoupanca(Conta):pass

Reescrevaométodoatualiza()naclasseContaCorrente,seguindooenunciado:

classContaCorrente(Conta):

defatualiza(self,taxa):self._saldo+=self._saldo*taxa*2

Reescrevaométodoatualiza()naclasseContaPopanca,seguindooenunciado:

classContaPoupanca(Conta):

defatualiza(self,taxa):self._saldo+=self._saldo*taxa*3

NaclasseContaCorrente,reescrevaométododeposita()paradescontarataxabancáriadedezcentavos:

classContaCorrente(Conta):

defatualiza(self,taxa):self._saldo+=self._saldo*taxa*2

defdeposita(self,valor):self._saldo+=valor-0.10

3. Agora, testesuasclassesnoprópriomóduloconta.py.Acrescenteacondiçãoquandoomóduloforiguala__main__paraexecutarmosnoconsolenoPyCharm.Instancieessasclasses,atualize-asevejaoresultado:

if__name__=='__main__'c=Conta('123-4','Joao',1000.0)cc=ContaCorrente('123-5','Jose',1000.0)cp=ContaPoupanca('123-6','Maria',1000.0)

c.atualiza(0.01)cc.atualiza(0.01)cp.atualiza(0.01)

print(c.saldo)print(cc.saldo)print(cp.saldo)

4. Implementeométodo__str__()naclasseConta.FaçacomqueeleimprimaumarepresentaçãomaisamigáveldeumContacontendotodososseusatributos.

def__str__(self):#suaimplementaçãoaqui

Testechamandoométodoprint()passandoalgumasinstânciasdeContacomoargumento.

.

Page 154: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

5. Vamoscriarumaclassequesejaresponsávelporfazeraatualizaçãodetodasascontasbancáriasegerarumrelatóriocomosaldoanterioresaldonovodecadaumadascontas.NapastasrccrieaclasseAtualizadorDeContas:

classAtualizadorDeContas:

def__init__(self,selic,saldo_total=0):self._selic=selicself._saldo_total=saldo_total

#propriedades

defroda(self,conta):#imprimeosaldoanterior,atualizaacontaedepoisimprimeosaldofinal#somaosaldofinalaoatributosaldo_total

Nãoesqueçadefazerosimportsnecessárioparaocódigofuncionar.

6. No'main',vamoscriaralgumascontaserodá-lasapartirdoAtualizadorDeContas:

if__name__=='__main__':c=Conta('123-4','Joao',1000.0)cc=ContaCorrente('123-5','José',1000.0)cp=ContaPoupanca('123-6','Maria',1000.0)

adc=AtualizadorDeContas(0.01)

adc.roda(c)adc.roda(cc)adc.roda(cp)

print('Saldototal:{}'.format(adc.saldo_total))

7. (opcional) Sevocêprecisasse criarumaclasseContaInvestimento, e seumétodoatualiza()fossecomplicadíssimo,vocêprecisariaalteraraclasseAtualizadorDeContas?

8. (opcional,Trabalhoso)CrieumaclasseBancoquepossuiumalistadecontas.ReparequeemumalistadecontasvocêpodecolocartantoContaCorrentequantoContaPoupanca.Crieummétodoadiciona()queadicionaumacontanalistadecontas;ummétodopegaConta()quedevolveacontaemdeterminadaposiçãodalistaeoutropegaTotalDeContas()queretornaototaldecontasna lista.Depois teste criandodiversas contas, insira-as noBanco e depois, comum laçofor,percorra todasas contasdoBanco parapassá-las comoargumentoparaométodoroda() doAtualizadorDeContas.

9. (opcional) Que maneira poderíamos implementar o método atualiza() nas classesContaCorrenteeContaPoupançapoupandoreescritadecódigo?

10. (opcional)E se criarmosuma classe quenão é filhadeConta e tentar passar uma instância nométodorodadeAtualizadorDeContas?Comoqueaprendemosatéaqui,comopodemosevitarqueerrosaconteçamnestescasos?

.

Page 155: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

VamosrecordarnossaclasseFuncionario:

classFuncionario:

def__init__(self,nome,cpf,salario=0):#inicializaçãodosatributos

#propriedadeseoutrosmétodos

defget_bonificacao(self):returnself._salario*1.2

ConsidereagoranossoControleDeBonificacao:

classControleDeBonificacoes:

def__init__(self,total_bonificacoes=0):self.__total_bonificacoes=total_bonificacoes

defregistra(self,obj):if(hasattr(obj,'get_bonificacao')):self.__total_bonificacoes+=obj.get_bonificacao()else:print('instânciade{}nãoimplementaométodoget_bonificacao()'.format(self.__class__.__name__))

#propriedades

Nossométodoregistra()recebeumobjetodequalquertipomasestamosesperandoquesejaumFuncionario jáqueeste implementaométodoget_bonificacao(), isto é,podemserobjetosdotipoFuncionarioequalquerdeseussubtipos:Gerente,Diretore,eventualmente,algumanovasubclassequevenhaserescrita,semprévioconhecimentodoautordaControleDeBonificacao.

EstamosutilizandoaquiaclasseFuncionarioparaopolimorfismo.Senãofosseela,teríamosum

Seuslivrosdetecnologiaparecemdoséculopassado?

10.8CLASSESABSTRATAS

.

Page 156: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

grande prejuízo: precisaríamos criar um método registra() para receber cada um dos tipos deFuncionario,umparaGerente,umparaDiretor,etc.Reparequeperderessepoderémuitopiordoqueapequenavantagemqueaherançatrazemherdarcódigo.

Porém,emalgunssistemas,comoéonossocaso,usamosumaclassecomapenasessesintuitos:deeconomizar um pouco código e ganhar polimorfismo para criar métodos mais genéricos, que seencaixemadiversosobjetos.

Faz sentido ter um objeto do tipo Funcionario? Essa pergunta é bastante relevante já queinstanciar um Funcionario pode gerar um objeto que não faz sentido no nosso sistema. NossaempresatemapenasDiretores,Gerentes,Secretárias,etc...Funcionarioéapenasumaclassequeidealizaumtipo,defineapenasumrascunho.

Vejamosumoutrocasoemquenãofazsentidoterumobjetodedeterminadotipo,apesardaclasseexistir.ImagineaclassePessoaeduasfilhas:PessoaFisicaePessoaJuridica.Quandopuxamosumrelatóriodenossosclientes(umalistadeobjetosdetipoPessoa,porexemplo),queremosquecadaumdelessejaouumaPessoaFisicaouumaPessoaJuridica.AclassePessoa,nessecaso,estariasendo usada apenas para ganhar o polimorfismo e herdar algumas coisas - não faz sentido permitirinstanciá-la.

Paraonossosistema,éinadmissívelqueumobjetosejaapenasdotipoFuncionario(podeexistirumsistemaemquefaçasentidoterobjetosdotipoFuncionarioouapenasPessoa,mas,nonossocaso,não).Pararesolveressesproblemas,temosasclassesabstratas.

UtilizaremosumamódulodoPythonchamadoabcquepermitedefinirmosclassesabstratas.UmaclasseabstratadeveherdardeABC(AbstractBaseClasses).ABCéasuperclasseparaclassesabstratas.

Umaclasseabstratanãopodeserinstanciadaedeveconterpelomenosummétodoabstrato.Vamosverissonaprática.

VamostornarnossaclasseFuncionarioabstrata:

importabc

classFuncionario(abc.ABC):

#métodosepropriedades

Definimos nossa classe Funcionario como abstrata. Agora vamos tornar nosso métodoget_bonificacao()abstrato.Ummétodoabstratopodeterimplementação,masnãofazsentidoemnosso sistema, portanto vamos deixá-lo sem implementação. Para definir um método abstratoutilizamosodecorator@abstractmethod:

classFuncionario(abc.ABC):

@abc.abstractmethoddefget_bonificacao(self):

.

Page 157: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

pass

Agora,setentarmosinstanciarumobjetodotipoFuncionario:

if__name__=='__main__':f=Funcionario()

Acusaumerro:

TypeError:Can'tinstantiateabstractclassFuncionariowithabstractmethodsget_bonificacao

ApesardenãoconseguirinstanciaraclasseFuncionario,conseguimosinstanciarsuasfilhasquesãoobjetosquerealmenteexistememnossosistema(objetosconcretos):

classGerente(Funcionario):#outrosmétodosepropriedades

defget_bonificacao(self):returnself._salario*0.15

if__name__=='__main__':gerente=Gerente('jose','222222222-22',5000.0,'1234',0)print(gerente.get_bonificacao())

VamoscriaraclasseDiretorqueherdadeFucionariosemométodoget_bonificacao():

classDiretor(Funcionario):def__init__(self,nome,cpf,salario):super().__init__(nome,cpf,salario)

if__name__=='__main__':diretor=Diretor('joao','111111111-11',4000.0)

Quandorodamosocódigo:

TypeError:Can'tinstantiateabstractclassDiretorwithabstractmethodsget_bonificacao

NãoconseguimosinstanciarumasubclassedeFuncionariosemimplementarométodoabstratoget_bonificacao().Agoratornamosométodoget_bonificacao()obrigatórioparatodoobjetoque é subclasse de Funcionario . Caso venhamos a criar outras classes, como Secretaria e Presidente , que sejam filhas de Funcionario , seremos obrigados e criar o métodoget_bonificacao(),casocontrário,ocódigovaiacursarerroquandoexecutado.

1. TorneaclasseContaabstrata.

importabc

classConta(abc.ABC):

def__init__(self,numero,titular,saldo=0,limite=1000.0):self._numero=numeroself._titular=titularself._saldo=saldoself._limite=limite

10.9EXERCÍCIOS-CLASSESABSTRATAS

.

Page 158: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

#outrosmétodosepropriedades

2. Torneométodoatualiza()abstrato:

classConta(abc.ABC):

#códigoomitido

@abc.abstractmethoddefatualiza():pass

3. TenteinstânciaumaConta:

if__name__=='__main__':c=Conta()

Oqueacontece?

4. Instancie uma ContaCorrente e uma ContaPoupanca e teste o código chamando o métodoatualiza().

if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)cp=ContaPoupanca('123-5','José',1000.0)

cc.atualiza(0.01)cp.atualiza(0.01)

print(cc.saldo)print(cp.saldo)

5. CrieumaclassechamadaContaInvestimento:

classContaInvestimeto(Conta):pass

6. InstancieumaContaInvestimeto:

pythonci=ContaInvestimento('123-6','Maria',1000.0)```

7. Não conseguimos instanciar uma ContaInvestimento que herda Conta sem implementar ométodo abstrato atualiza() . Vamos criar uma implementação dentro da classeContaInvestimento:

defatualiza(self,taxa):self._saldo+=self._saldo*taxa*5

8. AgoratesteinstanciandoumaContaInvestimentoechameométodoatualiza():

ci=ContaInvestimento('123-6','Maria',1000)ci.deposita(1000.0)ci.atualiza(0.01)print(ci.saldo)

9. (opcional) Crie um atributo tipo nas classes ContaCorrente , ContaPoupanca e

.

Page 159: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

ContaInvestimento. Faça com que o tipo também seja impresso quando usamos a funçãoprint().

.

Page 160: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO11

ImaginequeumSistemadeControledoBancopodeseracessado,alémdosGerentes,pelosDiretoresdoBanco.TeríamosumaclasseDiretor.

classDiretor(Funcionario):

defautentica(self,senha):#verificaseasenahconfere

EaclasseGerente:

classGerente(Funcionario):

defautentica(self,senha):#verificaseasenhaconfereetambémseoseudepartamentotemacesso

ReparequeométododeautenticaçãodecadatipodeFuncionariopodevariarmuito.Masvamosaosproblemas.Considere oSistemaInterno e seu controle: precisamos receber umDiretor ouGerentecomoargumento,verificarseeleseautenticaecolocá-lodentrodosistema.

Vimos que podemos utilizar a funçãohasattr() para verificar se um objeto possui ométodoautentica():

classSistemaInterno:

deflogin(self,funcionario):if(hasattr(obj,'autentica')):#chamamétodoautenticaelse:#imprimemensagemdeaçãoinválida

Mas podemos esquecer, no futuro, quando modelar a classe Presidente (que também é umfuncionário e autenticável), de implementar ométodoautentica().Não faz sentido colocarmosométodoautentica()naclasseFuncionariojáquenemtodofuncionárioéautenticável.

Uma solução mais interessante seria criar uma classe no meio da árvore de herança, aFuncionarioAutenticavel:

classFuncionarioAutenticavel(Funcionario):

defautentica(self,senha):#verificaseasenhaconfere

EasclassesDiretor,GerenteequalqueroutrotipodeFuncionarioAutenticavelqueviera

HERANÇAMÚLTIPLAEINTERFACES

.

Page 161: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

existir em nosso sistema bancário passaria a estender de FuncionarioAutenticavel. Repare queFuncionarioAutenticaveléfortecandidataaclasseabstrata.Maisainda,ométodoautentica()poderiaserummétodoabstrato.

Ousodeherançasimplesresolveocaso,masvamosaumaoutrasituaçãoumpoucomaiscomplexa:todososclientestambémdevempossuiracessoaoSistemaInterno.Oquefazer?

Umaopçãoéfazerumaherançasemsentidopararesolveroproblema,porexemplo,fazerClienteestender de FuncionarioAutenticavel. Realmente resolve o problema,mas trará diversos outros.ClientedefinitivamentenãoéumFuncionarioAutenticavel.Sevocêfizerisso,oClienteterá,por exemplo, ummétodoget_bonificacao(), umatributosalario e outrosmembros que nãofazemomenorsentidoparaestaclasse.

Precisamos,pararesolveresteproblema,arranjarumaformadereferenciarDiretor,GerenteeClientedeumamesmamaneira,istoé,acharumfatorcomum.

Seexistisseuma formanaqual essas classesgarantissemaexistênciadeumdeterminadométodo,atravésdeumcontrato,resolveríamosoproblema.Podemoscriarum"contrato"quedefinetudooqueumaclassedevefazersequiserterumdeterminadostatus.Imagine:

contratoAutenticavel

-quemquiserserAutenticavelprecisasaberfazer:autenticardadaumasenha,devolvendoumbooleano

Quem quiser pode assinar este contrato, sendo assim obrigado a explicar como será feita essaautenticação.Avantageméque,seumGerenteassinaressecontrato,podemosnosreferenciaraumGerentecomoumAutenticavel.

ComoPythonadmiteherançamúltiplapodemoscriaraclasseAutenticavel:

classAutenticavel:

defautentica(self,senha):#verificaseasenhaconfere

EfazerGerente,DiretoreClienteherdaremessaclasse:

classGerente(Funcionario,Autenticavel):#códigoomitido

classDiretor(Funcionario,Autenticavel):#códigoomitido

classCliente(Autenticavel):#códigoomitido

Ouseja,GerenteeDiretoralémde funcionáriossãoautenticáveis!Assim,podemosutilizaroSistemaInternoparafuncionáriosautenticáveiseclientes:

classSistemaInterno:

.

Page 162: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

deflogin(self,obj):if(hasattr(obj,'autentica')):obj.autentica()returnTrueelse:print('{}nãoéautenticável'.format(self.__class__.__name__))returnFalse

if__name__=='__main__':diretor=Diretor('João','111111111-11',3000.0,'1234')gerente=Gerente('José','222222222-22',5000.0,'1235')cliente=Cliente('Maria','333333333-33','1236')

sistema=SistemaInterno()sistema.login(diretor)sistema.login(gerente)sistema.login(cliente)

Notequeumaclassepodeherdardemuitasoutrasclasses.Masvamosaosproblemasqueissopodegerar.Porexemplo,váriasclassespodempossuiromesmométodo.

O exemplo anterior pode parecer uma boa maneira de representar classes autenticáveis, mas secomeçássemos a estender esse sistema, logo encontraríamos algumas complicações. Emumbancodeverdade, as divisões entre gerentes, diretores e clientes nem sempre são claras. Um Cliente, porexemplo,podeserumFuncionario,umFuncionario pode teroutras subcategorias como fixos etemporários.

NoPython,épossívelqueumaclasseherdedeváriasoutrasclasses.Poderíamos,porexemplo,criaruma classeA, que será superclassedas classesB eC. A herançamúltipla não émuito difícil deentenderseumaclasseherdadeváriasclassesquepossuempropriedadescompletamentediferentes,masascoisasficamcomplicadasseduassuperclassesimplementamomesmométodoouatributo.

SeasclassesBeCherdaremaclasseAeclasseDherdarasclassesBeC,easclassesBeCtêmummétodom2(),qualmétodoaclasseDherda?

classA:defm1(self):print('métododeA')

classB(A):defm2(self):print('métododeB')

classC(A):defm2(self):print('métododeC')

classD(B,C):pass

11.1PROBLEMADODIAMANTE

.

Page 163: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Essaambiguidadeéconhecidacomooproblemadodiamante,ouproblemadolosango,ediferenteslinguagensresolvemesseproblemademaneirasdiferentes.OPythonsegueumaordemespecíficaparapercorrerahierarquiadeclasseseessaordeméchamadadeMRO:MethodResolutionOrder(OrdemdeResoluçãodeMétodos).

Todaclasse temumatributo__mro__ que retornauma tuplade referênciasdas superclassesnaordemMRO-daclasseatualatéaclasseobject.VejamosoMROdaclasseD:

print(D.mro())

Saída:

(<class'__main__.D'>,<class'__main__.B'>,<class'__main__.C'>,<class'__main__.A'>,<class'object'>)

Aordemésempredaesquerdaparadireita.ReparequeoPythonvaiprocurarachamadadométodom2()primeironaclasseD,nãoencontrandovaiprocuraremB (aprimeiraclasseherdada).CasonãoencontreemB,vaiprocuraremCesóentãoprocuraremA-eporúltimonaclasseobject.

Tambémpodemosacessaroatributo__mro__atravésdométodomro()chamadopelaclassequeretornaumalistaaoinvésdeumatupla:

print(D.mro())

saída:[<class'__main__.D'>,<class'__main__.B'>,<class'__main__.C'>,<class'__main__.A'>,<class'object'>]

Portanto,seguindooMRO,aclasseDchamaométodom2()daclasseB:

.

Page 164: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

d=D()d.m1()d.m2()

Saída:

métododeAmétododeB

Felizmente,afunçãosuper()sabecomolidardeformainteligentecomherançamúltipla.Seusá-ladentrodométodotodososmétodosdassuperclassesdevemserchamadosseguindooMRO.

classA:defm1(self):print('métododeA')

classB(A):

defm1(self):super().m1()

defm2(self):print('métododeB')

classC(A):defm1(self):super().m1()

defm2(self):print('métododeC')

classD(B,C):defm1(self):super().m1()

defm2(self):super().m2()

if__name__=='__main__':d=D()d.m1()d.m2()

Geraasaída:

métododeAmétododeB

.

Page 165: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

Se usarmos herança múltipla, geralmente é uma boa idéia projetarmos nossas classes de umamaneiraqueeviteotipodeambiguidadedescritaacima-apesardoPythonpossuiroMRO,emsistemasgrandesaherançamúltiplaaindapodecausarmuitosproblemas.

Umamaneiradefazerissoédividirafuncionalidadeopcionalemmix-ins.Ummix-inéumaclassequenãosedestinaaserindependente-existeparaadicionarfuncionalidadeextraaoutraclasseatravésdeherançamúltipla.Aideiaéqueclassesherdemestesmix-ins,essas"misturasdefuncionalidades".

Por exemplo, nossa classe Autenticavel pode ser um mix-in já que ela existe apenas paraacrescentarafuncionalidadedeserautenticável,ouseja,paraherdarseumétodoautentica.

NossaclasseAutenticaveljásecomportacomoumMix-In.NoPythonnãoexisteumamaneiraespecíficadecriarmix-ins.Osprogramadores,porconvençãoeparadeixarexplícitoaclassecomoummix-in,colocamotermo'MixIn'nonomedaclasseeutilizamatravésdeherançamúltipla:

classAutenticavelMixIn:defautentica(self,senha):#verificasenha

Cadamix-in é responsávelpor fornecerumapeçaespecíficade funcionalidadeopcional.Podemosteroutrosmix-insnonossosistema:

classAtendimentoMixIn:defcadastra_atendimento(self):#fazcadastroatendimento

defatende_cliente(self):#fazatendimento

classHoraExtraMixIn:

defcalcula_hora_extra(self,horas):#calculahorasextras

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

11.2MIX-INS

.

Page 166: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Epodemosmisturá-losnasclassesdenossosistema:

classGerente(Funcionario,AutenticavelMixIn,HoraExtraMixIn):pass

classDiretor(Funcionario,AutenticavelMixIn):pass

classCliente(AutentivavelMixIn):pass

classEscriturario(Funcionario,AtentimentoMixIn):pass

Reparequenossosmix-ins não temummétodo__init__() .Muitosmix-ins apenas fornecemmétodos adicionais mas não inicializam nada. Isso às vezes significa que eles dependem de outraspropriedadesquejáexistememsuasfilhas.Cadamix-inéresponsávelporfornecerumapeçaespecíficadefuncionalidadeopcional-éumjeitodecomporclasses.

Poderíamosestenderesteexemplocommaismisturasquerepresentamacapacidadedepagartaxas,acapacidadedeserpagoporserviços,eassimpordiante-poderíamosentãocriarumahierarquiadeclassesrelativamenteplanaparadiferentestiposdeclassesdefuncionárioqueherdamFuncionarioealgunsmix-ins.

Essaéumadasabordagensdeseusarherançamúltiplamaselaébastantedesencorajada.Casovocêutilize, opte porMix Ins sabendo de suas desvantagens. Usado em sistemas grandes podem ocorrercolisõescomnomesdemétodos,métodossubstituídosacidentalmente,hierarquiadeclassepoucoclarae dificuldade de ler e entender classes compostas pormuitosmix-ins, dentre outras desvantagens. Oproblemadaherançamúltiplapermanece.

Outra abordagem possível é definir funções fora de classes, digamos em um módulo e fazerchamadas dessas funções passando nossos objetos.Mas isso é um afastamento radical do paradigmaorientadoaobjetosqueébaseadaemmétodosdefinidosdentrodasclasses.

TkinteréumframeworkquefazpartedabibliotecapadrãodoPythonutilizadoparacriarinterfacegráfica.Éumcasoondemix-instrabalhambemjáquesetratadeumpequenoframework,mastambémé suficientemente grande para que seja possível ver o problema. Veja um exemplo de parte de suahierarquiadeclasse:

11.3PARASABEMAIS-TKINTER

.

Page 167: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Essa figuramostra parte do complicadomodelo de classes utilizando herançamúltipla do pacoteTkinter.AsetasrepresentamoMROquedeveiniciarnaclasseText.AclasseText implementaumcampodetextoeditáveletemmuitasfuncionalidadespróprias,alémdeherdarmuitosmétodosdeoutrasclasses.

UmaoutraclassedopacotequenãoaparecenestediagramaéaLabel,utilizadaparamostrarumtexto ou bitmap na tela. Você pode testar no Pycharm, aproveitando a ferramenta de autocomplete,chamandoTkinter.Label.eaIDEvaitemostrar181sugestõesdeatributosemumaúnicaclasse!Ouvocêpodeutilizarafunçãohelp()parachecaraorigemdecadaumdeles.

fromtkinterimport*

help(Label)

Essepacotetemmaisde20anoseéumexemplodecomoaherançamúltiplaerautilizadaquandoosprogramadores não consideravam suas desvantagens. Apesar damaioria das classes se comportaremcomomix-ins,opadrãodenomenclaturanãoerautilizado.Felizmente,oTkinter é um frameworkestável.

1. Nossobancoprecisatributardinheirodealgunsbensquenossosclientespossuem.ParaissovamoscriarumaclasseTributavel:

classTributavel:

defget_valor_imposto(self):pass

Lemosessaclassedaseguintemaneira:"Todosquequiseremsertributávelprecisamsaberretornarovalordo imposto".Algunsbenssão tributáveiseoutrosnão,ContaPoupanca não é tributável, jáparaContaCorrentevocêprecisapagar1%dacontaeoSeguroDeVidatemumafaixafixade50reaismais5%.dovalordoseguro.

11.4(OPCIONAL)EXERCÍCIOS-MIX-INS

.

Page 168: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

2. TorneaclasseTributavelummix-in:

classTributavelMixIn:

defget_valor_imposto(self)pass

3. FaçaaclasseContaCorrenteherdardaclasseTributavelMixIn.CrieaclasseSeguroDeVida:

classContaCorrente(Conta,TributavelMixIn):#códigoomitido

defget_valor_imposto(self):returnself._saldo*0.01

classSeguroDeVida(TributavelMixIn):def__init__(self,valor,titular,numero_apolice):self._valor=valorself._titular=titularself._numero_apolice=numero_apolice

defget_valor_imposto(self):return42+self._valor*0.05

4. VamoscriaraclasseManipuladorDeTributaveisemumarquivochamadomanipulador.py.Essaclassedeve terummétodochamadocalcula_imposto() que recebeumas lista de tributáveis eretornaototaldeimpostoscobrados:

classManipuladorDeTributaveis:

defcalcula_impostos(self,lista_tributaveis):total=0fortinlista_tributaveis:total+=t.get_valor_imposto()

returntotal

5. Aindanoarquivomanipulador.py,vamostestarocódigo.CriealgunsobjetosdeContaCorrenteedeSeguroDeVida.Emseguida,crieumalistadetributáveise insiraseusobjetosnela.InstancieumManipuladorDeTributaveis e chameométodocalcula_impostos() passando a lista detributáveiscriadaeimprimaovalortotaldosimpostos:

if__name__=='__main__':fromcontaimportContaCorrente,SeguroDeVida,TributavelMixIn

cc1=ContaCorrente('123-4','João',1000.0)cc2=ContaCorrente('123-4','José',1000.0)seguro1=SeguroDeVida(100.0,'José','345-77')seguro2=SeguroDeVida(200.0,'Maria','237-98')

lista_tributaveis=[]lista_tributaveis.append(cc1)lista_tributaveis.append(cc2)lista_tributaveis.append(seguro1)lista_tributaveis.append(seguro2)

manipulador=ManipuladorDeTributaveis()total=manipulador.calcula_impostos(lista_tributaveis)

.

Page 169: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

print(total)

Vimosqueherançamúltiplapodeserperigosaesenossosistemacrescerpodegerarmuitaconfusãoe conflitodenomesdemétodos.Umamaneiramais eficaznestes casos éusar classes abstratas comointerfacesqueveremosaseguir.

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

O Python não possui uma palavra reservada interface. Mesmo sem uma palavra reservada parainterface todaclasse temuma interface.Sãoosatributospúblicosdefinidos(queemPythonsão tantoatributos quanto métodos) em uma classe - isso inclui os métodos especiais como __str__() e__add__().

Uma interface vista como um conjunto de métodos para desempenhar um papel é o que osprogramadoresdaSmallTalkchamavamdeprotocoloeestetermofoidisseminadoemcomunidadesdeprogramadoresdelinguagensdinâmicas.Esseprotocolofuncionacomoumcontrato.

Osprotocolossãoindependentesdeherança.Umaclassepodeimplementarváriosprotocolos,comoos mix-ins. Protocolos são interfaces e são definidos apenas por documentação e convenções emlinguagens dinâmicas, por isso são considerados informais.Os protocolos não podem ser verificadosestaticamentepelointerpretador.

Ométodo__str__(),porexemplo,éesperadoqueretorneumarepresentaçãodoobjetoemformadestring.Nadaimpededefazermosoutrascoisasdentrodométodocomodeletaralgumconteúdo,fazeralgumcálculo,etc...aoinvésderetornarmosapenasastring.MasháumentendimentopréviocomumdoqueestemétododevefazereestápresentenadocumentaçãodoPython.Esteéumexemploondeo contrato semântico édescrito emummanual.Algumas linguagensde tipagemestática, comoJava, possuem interfaces em sua biblioteca padrão e podem garantir este contrato em tempo de

Seuslivrosdetecnologiaparecemdoséculopassado?

11.5INTEFACES

.

Page 170: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

compilação.

A partir do Python 2.6 a definição de interfaces utilizando o módulo ABC é uma solução maiselegantedoqueosmix-ins.NossaclasseAutenticavel pode serumaclasse abstrata comométodoabstratoautentica():

importabc

classAutenticavel(abc.ABC):

@abc.abstractmethoddefautentica(self,senha):pass

Como se trata de uma interface em uma linguagem de tipagem dinâmica como o Python, a boapráticaédocumentarestaclassegarantindoocontratosemântico:

importabc

classAutenticavel(abc.ABC):"""Classeabstrataquecontémoperaçõesdeumobjetoautenticável.

Assubclassesconcretasdevemsobrescreverométodoautentica"""

@abc.abstractmethoddefautentica(self,senha):"""MétodoabstratoquefazverificaçãodasenhareturnTrueseasenhaconfere,eFalsecasocontrário."""

EnossasclassesGerente,DiretoreClienteherdariamaclasseAutenticavel.Masqualadiferençadeherdarmuitosmix-insemuitasABCs?Realmente,aquinãohágrandediferençaevoltamosaoproblemaanteriordosmix-ins-muitoacoplamentoentreclassesquegeraaherançamúltipla.

MasanovidadedasABCséseumétodoregister().AsABCsintroduzemumasubclassevirtual,quesãoclassesquenãoherdamdeumaclassemassãoreconhecidaspelosmétodosisinstance() eissubclass() . Ou seja, nosso Gerente não precisa herdar a classe Autenticavel , bastaregistrarmoselecomoumaimplementaçãodaclasseAutenticavel.

Autenticavel.register(Gerente)

Etestamososmétodosisinstance()eissubclass()comumainstânciadeGerente:

gerente=Gerente('João','111111111-11',3000.0)print(isinstance(Autenticavel))print(issubclass(Autenticavel))

quevaigerarasaída:

TrueTrue

OPython não vai verificar se existe uma implementação dométodoautentica em Gerente

.

Page 171: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

quando registrarmos a classe. Ao registrarmos a classe Gerente como uma Autenticavel ,prometemosaoPythonqueaclasseimplementafielmenteanossainterfaceAutenticaveldefinida.OPythonvaiacreditarnissoeretornarTruequandoosmétodosisinstance()eissubclass()foremchamados.Sementirmos,ouseja,nãoimplementarmosométodoautentica()emGerente, umaexceçãoserálançadaquandotentarmoschamarestemétodo.

VejamosumexemplocomaclasseDiretor.Nãovamosimplementarométodoautentica()eregistrarumainstânciadeDiretorcomoumAutenticavel:

classDiretor(Funcionario):#códigoomitido

if__name__=='__main__':Autenticavel.register(Diretor)

d=Diretor('José','22222222-22',3000.0)

d.autentica('?')

Etemoscomosaída:

Traceback(mostrecentcalllast):File<stdin>,line47,in<module>d.autentica('?')AttributeError:'Diretor'objecthasnoattribute'autentica'

Novamente,podemostrataraexceçãoouutilizarosmétodosisinstance() ouissubclass()para verificação. Apesar de considerada má práticas por muitos pythonistas, o módulo de classesabstratasjustificaautilizaçãodestetipodeverificação.Averificaçãonãoédetipagem,masseumobjetoestádeacordocomainterface:

if__name__=='__main__':Autenticavel.register(Diretor)

d=Diretor('José','22222222-22',3000.0)

if(isinstance(d,Autenticavel)):d.autentica('?')else:print("DiretornãoimplementaainterfaceAutenticavel")

eportanto,nossaclasseSistemaInternoficariaassim:

fromautenticavelimportAutenticavel

classSistemaInterno:

deflogin(self,obj):if(isinstance(obj,Autenticavel)):obj.autentica(obj.senha)returnTrueelse:print("{}nãoéautenticável".format(self.__class__.__name__))returnFalse

Dessa maneira fugimos da herança múltipla e garantimos um contrato, um protocolo. Classes

.

Page 172: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

abstratas complementam oduck typing provendo umamaneira de definir interfaces quando técnicascomousarhasattr()sãoruinsousutilmenteerradas.VocêpodelermaisarespeitonodocumentodaPEP que introduz classes abstratas - é a PEP 3119 e você pode acessar seu conteúdo neste link:https://www.python.org/dev/peps/pep-3119/

AlgumasABCs tambémpodemprovermétodos concretos, ou seja, não abstratos.Por exemplo, aclasse Interator do módulo collections da biblioteca padrão do Python possui um método__iter__()retornandoelemesmo.EstaABCpodeserconsideradaumaclassemix-in.

OPythonjávemcomalgumasestruturasabstratas(vermóduloscollections,numberseio).

1. Nossobancoprecisatributardinheirodealgunsbensquenossosclientespossuem.ParaissovamoscriarumaclasseTributavelnomódulotributavel.py:

classTributavel:

defget_valor_imposto(self):pass

Lemosessaclassedaseguintemaneira:"Todosquequiseremsertributávelprecisamsaberretornarovalordo imposto".Algunsbenssão tributáveiseoutrosnão,ContaPoupanca não é tributável, jáparaContaCorrentevocêprecisapagar1%dacontaeoSeguroDeVidatemumafaixafixade50reaismais5%dovalordoseguro.

2. TorneaclasseTributavelumaclasseabstrata:

importabc

classTributavel(abc.ABC):

defget_valor_imposto(self)pass

3. Ométodoget_valor_imposto()tambémdeveserabstrato:

importabc

classTributavel(abc.ABC):

@abc.abstractmethoddefget_valor_imposto(self,valor):pass

4. Nadaimpedequeosusuáriosdenossaclassetributavelimplementeométodoget_valor_impostodemaneiranãoesperadapornós.Entãovamosacrescentaradocumentaçãoutilizandodocstringqueaprendemosnocapítulodemódulos:

importabc

11.6EXERCÍCIOS-INTERFACESECLASSESABSTRATAS

.

Page 173: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

classTributavel(abc.ABC):"""Classequecontémoperaçõesdeumobjetoautenticável

Assubclassesconcretasdevemsobrescreverométodoget_valor_imposto."""@abc.abstractmethoddefget_valor_imposto(self):"""aplicataxadeimpostosobreumdeterminadovalordoobjeto"""pass

5. Utilizaafunçãohelp()passandoaclasseTributavelparaacessaradocumentação.

6. FaçaaclasseContaCorrenteherdardaclasseTributavel.CrieaclasseSeguroDeVidacomosatributosvalor,titularenumero_apolicequetambémdeveserumtributável.Implementeométodoget_valor_imposto()deacordocomaregradenegóciodefinidapeloexercício:

classContaCorrente(Conta,Tributavel):#códigoomitido

defget_valor_imposto(self):returnself._saldo*0.01

classSeguroDeVida(Tributavel):def__init__(self,valor,titular,numero_apolice):self._valor=valorself._titular=titularself._numero_apolice=numero_apolice

defget_valor_imposto(self):return50+self._valor*0.05

7. Vamos criar a classe ManipuladorDetributaveis em um arquivo chamadomanipulador_tributaveis.py. Essa classe deve ter ummétodo chamado calcula_imposto() querecebeumaslistadetributáveiseretornaototaldeimpostoscobrados:

classManipuladorDeTributaveis:

defcalcula_impostos(self,lista_tributaveis):total=0fortinlista_tributaveis:total+=t.get_valor_imposto()returntotal

8. Nossas classes ContaCorrente e SeguraDeVida já implementam o métodoget_valor_imposto().Vamosinstanciarcadaumasdelasetestarachamadadométodo:

if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)seguro=SeguroDeVida(100.0,'José','345-77')

print(cc.get_valor_imposto())print(seguro.get_valor_imposto())

9. Crieuma lista comosobjetos criadosnoexercícioanterior, instancieumobjetodo tipolist epassealistachamandoométodocalcula_impostos().

if__name__=='__main__':

.

Page 174: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

#códigoomitido

lista_tributaveis=[]lista_tributaveis.append(cc)lista_tributaveis.append(seguro)

mt=ManipuladorDeTributaveis()total=mt.calcula_impostos(lista_tributaveis)print(total)

10. Nosso código funciona, mas ainda estamos utilizando herança múltipla! Vamos melhorar nossocódigo.FaçacomqueContaCorrenteeSeguroDeVidanãomaisherdemdaclasseTributavel.Vamos registrar nossas classes ContaCorrente e SeguroDeVida como subclasses virtuais deTributavel,demodoquefuncionecomoumainterface.

classContaCorrente(Conta):#códigoomitido

classSeguroDeVida:#códigoomitido

if__name__=='__main__':fromtributavelimportTributavel

cc=ContaCorrente('João','123-4')cc.deposita(1000.0)

seguro=SeguroDeVida(100.0,'José','345-77')

Tributavel.register(ContaCorrente)Tributavel.register(SeguroDeVida)

lista_tributaveis=[]lista_tributaveis.append(cc)lista_tributaveis.append(seguro)

mt=ManipuladorDeTributaveis()total=mt.calcula_impostos(lista_tributaveis)print(total)

11. Modifiqueométodocalcula_impostos()daclasseManipuladorDeTributaveisparachecarseoselementosda listas são tributáveisatravésdométodoisinstance().Casoumobjetoda listanão seja um tributável, vamos imprimir uma mensagem de erro e apenas os tributáveis serãosomadosaototal:

classManipuladorDeTributaveis:

defcalcula_impostos(self,lista_tributaveis):total=0fortinlista_tributaveis:if(isinstance(t,Tributavel)):total+=t.get_valor_imposto()else:print(t.__repr__(),"nãoéumtributável")returntotal

Testenovamentecomalistadetributáveisquefizemosnoexercícioanteriorevejasetudocontinua

.

Page 175: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

funcionando.

12. ContaPoupancanãoéumtributável.Experimente instanciarumaContaPoupanca, adicionar alistadetributáveisecalcularototaldeimpostosatravésdoManipuladorDetributaveis:

if__name__=='__main__':#códigoomitidodoexercícioanterioromitido

cp=ContaPoupanca('123-6','Maria')lista_tributaveis.append(cp)

total=mt.calcula_impostos(lista_tributaveis)print(total)

Oqueacontece?

13. (Opcional)AgoraalémdeContaCorrenteeSeguroDeVidanossaContaInvestimentotambémdeve ser um tributável, cobrando 3% do saldo. Instancie uma ContaInvestimento e registre aclasseContaInvestimento como tributável.AdicioneaContaInvestimento criadana lista detributáveis do exercício anterior e calcule o total de impostos através doManipuladorDeTributaveis.

Nestecapítuloaprendemossobreherançamúltiplaesuasdesvantagensmesmoutilizandomix-ins.Aprendemos utilizar classes abstratas como interfaces registrando as classes e evitando os problemascomaherançamúltipla.Agoranossa classe abstrataTributavel funciona comoumprotocolo.Nocapítulosobreomódulocollectionsveremosnapráticaalgunsconceitosvistosnestescapítulo.

.

Page 176: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO12

Voltandoascontasquecriamosnocapítulo6,oqueaconteceriaaotentarchamarométodosaca()comumvalorforadolimite?Osistemamostrariaumamensagemdeerro,masquemchamouométodosaca()nãosaberáqueissoaconteceu.

Comoavisaraquelequechamouométododequeelenãoconseguiufazeraquiloquedeveria?

Osmétodosdizemqualocontratoqueelesdevemseguir.Se,aotentarsacar(),elenãoconseguefazeroquedeveria,eleprecisa,aomenos,avisaraousuárioqueosaquenãofoifeito.

Vejanoexemploabaixo:estamosforçandoumaContaaterumvalornegativo,istoé,estaremumestadoinconsistentedeacordocomanossamodelagem.

conta=Conta('123-4','João')conta.deposita(100.0)conta.saca(3000.0)

#ométodosacafuncionou?

Em sistemas de verdade, é muito comum que quem saiba tratar o erro é aquele que chamou ométodoenãoaprópriaclasse!Portanto,nadamaisnaturalsinalizarqueumerroocorreu.

AsoluçãomaissimplesutilizadaantigamenteéademarcaroretornodeummétodocomobooleaneretornarTrue,setudoocorreudamaneiraplanejada,ouFalse,casocontrário:

if(valor>self.saldo+self.limite):print("naopossosacarforadolimite")returnFalseelse:self.saldo-=valorreturnTrue

Umnovoexemplodechamadadométodoacima:

conta=Conta('123-4','João')conta.deposita(100.0)conta.limite=100.0

if(notconta.saca(3000.0)):print("naosaquei")

Reparequetivemosdelembrardetestaroretornodométodo,masnãosomosobrigadosafazerisso.Esquecerdetestaroretornodessemétodoteriaconsequênciasdrásticas:amáquinadeautoatendimentopoderiaviraliberaraquantiadesejadadedinheiro,mesmoseosistemanãotivesseconseguidoefetuaro

EXCEÇÕESEERROS

.

Page 177: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

métodosaca()comsucesso,comonoexemploaseguir:

conta=Conta("123-4","João")conta.deposita(100.0)

#...

valor=5000.0conta.saca(valor)#vairetornarFalse,masninguémverifica

caixa_eletronico.emite(valor)

Mesmo invocando o método e tratando o retorno de maneira correta, o que faríamos se fossenecessáriosinalizarquandoousuáriopassouumvalornegativocomovalor.Umasoluçãoseriaalteraroretornodebooleanparainteretornarocódigodoerroqueocorreu.Issoéconsideradoumamáprática(conhecidatambémcomousode"magicnumbers").

Alémdevocêperderoretornodométodo,ovalordevolvidoé"mágico"esólegívelperanteextensadocumentação,alémdenãoobrigaroprogramadoratrataresseretornoe,nocasodeesquecerisso,seuprogramacontinuarárodandojánumestadoinconsistente.

Por esses e outro motivos, utilizamos um código diferente para tratar aquilo que chamamos deexceções:oscasosondeacontecealgoque,normalmente,nãoiriaacontecer.Oexemplodoargumentodosaqueinválidooudoidinválidodeumclienteéumaexceçãoàregra.

Umaexceçãorepresentaumasituaçãoquenormalmentenãoocorreerepresentaalgodeestranhoouinesperadonosistema.

Antes de resolvermos o nosso problema, vamos ver como o interpretador age ao se deparar comsituaçõesinesperadas,comodivisãoporzeroouacessoaumíndicedeumalistaquenãoexiste.

Para aprendermos os conceitos básicos das exceptions do Python, crie um arquivo teste_erro.py etesteoseguintecódigovocêmesmo:

fromcontaimportContaCorrente

defmetodo1():print('iníciodometodo1')metodo2()print('fimdometodo1')

defmetodo2():print('iníciodometodo2')cc=ContaCorrente('José','123')foriinrange(1,15):cc.deposita(i+1000)print(cc.saldo)if(i==5):cc=None

print('fimdometodo2')

if__name__=='__main__':print('iníciodomain')

.

Page 178: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

metodo1()print('fimdomain')

Reparequeduranteaexecuçãodoprogramachamamosometodo1()eesse,porsuavez,chamaometodo2().Cadaumdessesmétodospodetersuasprópriasvariáveislocais,istoé:ometodo1()nãoenxergaasvariáveisdeclaradasdentrodoexecutáveleporaíemdiante.

ComooPython(emuitasoutraslinguagens)fazisso?Todainvocaçãodemétodoéempilhadoemumaestruturadedadosqueisolaaáreaememóriadecadaum.Quandoummétodotermina(retorna),ele volta para ométodo que o invocou. Ele descobre isso através da pilha de execução (stack): bastaremoveromarcadorqueestánotopodapilha:

Porém, o nossometodo2() propositalmente possui um enorme problema: está acessando umareferênciaparaNonequandooíndiceforiguala6!

Rodeocódigo.Qualasaída?Oqueissorepresenta?Oqueelaindica?

Essasaídaéorastrodepilha,oTraceback.Éumasaídaimportantíssimaparaoprogramador-tantoque,emqualquerfórumoulistadediscussão,écomumosprogramadoresenviarem,juntamentecomadescriçãodoproblema,essaTraceback.Masporqueissoaconteceu?

O sistema de exceções do Python funciona da seguintemaneira: quando uma exceção é lançada

.

Page 179: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

(raise),ointerpretadorentraemestadodealertaevaiverseométodoatualtomaalgumaprecauçãoaotentarexecutaressetrechodecódigo.Comopodemosver,ometodo2()nãotomanenhumamedidadiferentedoquevimosatéagora.

Como o metodo2() não está tratando esse problema, o interpretador para a execução deleanormalmente, sem esperar ele terminar, e volta um stackframe para baixo, onde será feita novaverificação:"ométodo1()estáseprecavendodeumproblemachamadoAttributeError? "Não..."Voltaparaoexecutável,ondetambémnãoháproteção,entãoointerpretadormorre.

Obviamente,aquiestamosforçandoessecasoenãofariasentidotomarmoscuidadocomele.Éfácilarrumar um problema desses: basta verificar antes de chamar os métodos se a variável está comreferênciaparaNone.

Porém,apenasparaentenderocontroledefluxodeumaException,vamoscolocarocódigoquevaitentar (try) executar um bloco perigoso e, caso o problema seja do tipo AttributeError, ele seráexcluído(except).Repareque é interessanteque cada exceçãonoPython tenhaum tipo... elapode teratributosemétodos.

Adicioneumtry/except emvoltadofor, 'pegando' umAttributeError.Oqueo códigoimprime?

fromcontaimportContaCorrente

defmetodo1():print('iníciodometodo1')metodo2()print('fimdometodo1')

defmetodo2():print('iníciodometodo2')cc=ContaCorrente('José','123')try:foriinrange(1,15):cc.deposita(i+1000)print(cc.saldo)if(i==5):cc=Noneexcept:print('erro')

print('fimdometodo2')

if__name__=='__main__':print('iníciodomain')metodo1()print('fimdomain')

.

Page 180: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Emvezdefazerotryemtornodoforinteiro,tenteapenascomoblocodentrodofor:

defmetodo2():print('iníciodometodo2')cc=ContaCorrente('José','123')

foriinrange(1,15):try:cc.deposita(i+1000)print(cc.saldo)if(i==5):cc=Noneexcept:print('erro')

print('fimdometodo2')

Qualadiferença?

Retireotry/exceptecoloqueeleemvoltadachamadadometodo2():

defmetodo1():print('iníciodometodo1')try:metodo2()exceptAttributeError:print('erro')print('fimdometodo1')

.

Page 181: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Faça o mesmo, retirando o try/except novamente e colocando em volta da chamada dometodo1().Rodeoscódigos,oqueacontece?

if__name__=='__main__':print('iníciodomain')try:metodo1()exceptAttributeError:print('erro')print('fimdomain')

Repareque,apartirdomomentoqueumaexceptionfoicatched(pega,tratada,handled),aexceçãovoltaaonormalapartirdaqueleponto.

Runtime

Estetipodeerroocorrequandoalgodeerradoaconteceduranteaexecuçãodoprograma.Amaiorpartedasmensagensdestetipodeerroincluiinformaçõesdoqueoprogramaestavafazendoeolocalqueoerroaconteceu.

OinterpretadormostraafamosaTraceback-elemostraasequênciadechamadasdefunçãoquefezcom que você chegasse onde está, incluindo o número da linha de seu arquivo onde cada chamadaocorreu.

Oserrosmaiscomunsdetempodeexecuçãosão:

12.1EXCEÇÕESETIPOSDEERROS

.

Page 182: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

NameError

Quandotentamosacessarumavariávelquenãoexiste.

print(x)

Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>NameError:name'x'isnotdefined

Noexemploacimatentamosimprimirxsemdefini-loantes.Esteerrotambémémuitocomumdeocorrerquandotentamosacessarumvariávellocalemumcontextolocal.

TypeError

Quando tentamos usar um valor de forma inadequada, como por exemplo tentar indexar umsequênciacomalgodiferentedeumnúmerointeirooudeumfatiamento:

lista=[1,2,3]print(lista['a'])

Traceback(mostrecentcalllast):File"<stdin>",line2,in<module>TypeError:listindicesmustbeintegersorslices,notstr

KeyError

Quandotentamosacessarumelementodeumdicionáriousandoumachavequenãoexiste.

dicionario={'nome':'João','idade':25}print(dicionario['cidade'])

Traceback(mostrecentcalllast):File"<stdin>",line2,in<module>KeyError:'cidade'

AttributeError

Quandotentamosacessarumatributooumétodoquenãoexisteemumobjeto.

lista=[1,2,3]print(lista.nome)

Traceback(mostrecentcalllast):File"<stdin>",line2,in<module>AttributeError:'list'objecthasnoattribute'nome'

IndexError

Quando tentamos acessar um elemento de uma sequência com um índice maior que seucomprimentomenosum.

tupla=(1,2,3)print(tupla[3])

Traceback(mostrecentcalllast):

.

Page 183: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

File"<stdin>",line2,in<module>IndexError:tupleindexoutofrange

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Hámuitos outros erros de tempo de execução.Que tal dividir umnúmero por zero? Será que ointerpretadorconseguefazeraquiloquenósdefinimosquenãoexiste?

n=2n=n/0

Traceback(mostrecentcalllast):File"<stdin>",line2,in<module>ZeroDivisionError:divisionbyzero

ReparequeumZeroDivisionErrorpoderiaserfacilmenteevitadocomumifquechecariaseodenominador é diferente de zeromas a forma correta de se tratar um erro no Python é através docomandotry/except:

try:n=n/0exceptZeroDivisionError:print('divisãoporzero')

Quegeraasaída:

divisãoporzero

Oconjuntodeinstruçõesdentrodoblocotryéexecutado(o interpretador tentaráexecutar), senenhumaexceçãoocorrer,o comandoexcept é ignorado e a execução é finalizada.Mas se ocorreralgumaexceçãodurante a execuçãodoblocotry, as instruções remanescentes são ignoradas e se aexceçãolançadapreverumexcept,entãoasinstruçõesdentrodoblocoexceptsãoexecutadas.

Ocomandotrypodetermaisdeumcomandoexceptparaespecificarmúltiplostratadoresparadiferentesexceções.Nomáximoumúnicotratadorseráativado.Tratadoressósãosensíveisàsexceções

Agoraéamelhorhoradeaprenderalgonovo

12.2TRATANDOEXCEÇÕES

.

Page 184: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

levantadasno interiordacláusulatry, e não as que tenhamocorridono interiordeoutro tratadornuma mesma instrução try . Um tratador pode ser sensível a múltiplas exceções, desde que asespecifiqueemumatupla:

except(RuntimeError,TypeError,NameError):pass

Aúltimacláusulaexceptpodeomitironomedaexceção,funcionandocomoumcuringa.Nãoéaconselhávelabusardesterecursojáqueissopodeescondererrosdoprogramadoredousuário.

Oblocotry/exceptpossuiumcomandoopcionalelseque,quandousado,devesercolocadodepoisdetodososcomandosexcept.Éútilparacódigoqueprecisaserexecutadosenenhumaexceçãofoilançada,porexemplo:

try:arquivo=open('palavras.txt','r')exceptIOError:print('nãofoipossívelabriroarquivo')else:print('oarquivotem{}palavras'.format(len(arquivo.readlines())))arquivo.close()

O comando raise nos permite forçar a ocorrência de um determinado tipo de exceção. Porexemplo:

raiseNameError('oi')Traceback(mostrecentcalllast):File"<stdin>",line1,in?NameError:oi

Oargumentoderaiseindicaaexceçãoaserlançada.EsseargumentodeveserumainstânciadeExceptionouumaclassedealgumaexceção-umaclassequederivadeException.

Casovocêprecisedeterminarseumaexceção foi lançadaounão,masnãoquermanipularoerro,umaformaélançá-lanovamenteatravésdainstruçãoraise:

try:raiseNameError('oi')exceptNameError:print('lançouumaexceção')raise

Saída:

lançouumaexceçãoTraceback(mostrecentcalllast):File"<stdin>",line1,in?NameError:oi

12.3LEVANTANDOEXCEÇÕES

12.4DEFINIRUMAEXCEÇÃO

.

Page 185: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Programaspodemdefinirnovostiposdeexceções,atravésdacriaçãodeumanovaclasse.ExceçõesdevemserderivadasdaclasseException,diretaouindiretamente.Porexemplo:

classMeuErro(Exception):def__init__(self,valor):self.valor=valordef__str__(self):returnrepr(self.valor)

if__name__=='__main__':try:raiseMeuErro(2*2)exceptMeuErroase:print('Minhaexceçãoocorreu,valor:{}'.format(e.valor))

raiseMeuErro('oops!')

Quequandoexecutadogeraasaída:

Minhaexceçãoocorreu,valor:4Traceback(mostrecentcalllast):File"<stdin>",line13,in<module>raiseMeuErro('oops!')__main__.MeuErro:'oops!'

Nesteexemplo,ométodo__init__daclasseException foi reescrito.Onovocomportamentosimplesmentecriaoatributovalor.Classesdeexceçõespodemserdefinidaspara fazerqualquercoisaquequalqueroutraclassefaz,masemgeralsãobemsimples,frequentementeoferecendoapenasalgunsatributosqueforneceminformaçõessobreoerroqueocorreu.

Aocriarummóduloquepodegerardiversoserros,umapráticacomumécriarumaclassebaseparaas exceções definidas por aquele módulo, e as classes específicas para cada condição de erro comosubclassesdela:

classMeuError(Exception):"""Classebaseparaoutrasexceções"""pass

classValorMuitoPequenoError(Error):"""Élançadaquandoovalorpassadoémuitopequeno"""pass

classValorMuitoGrandeError(Error):"""Élançadaquandoovalorpassadoémuitogrande"""pass

EssaéamaneirapadrãodedefinirexceçõesnoPythonmasoprogramadornãoprecisaficarpresoaela. É comumquenovas exceções sejamdefinidas comnomes terminando em “Error”, semelhante amuitasexceçõesembutidas.

.

Page 186: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

O comando try pode ter outro comando opcional chamado finally. Sua finalidade é permitir aimplementação de ações de limpeza, que sempre devem ser executadas independentemente daocorrênciadeexceções.Comonoexemplo:

defdivisao(x,y):try:resultado=x/yexceptZeroDivisionError:print("Divisãoporzero")else:print("oresultadoé{}".format(resultado))finally:print("executandoofinally")

if__name__=='__main__':divide(2,1)divide(2,0)divide('2','1')

Executando:

resultadoé2executandoofinallydivisãoporzeroexecutandoofinallyexecutandoofinallyTraceback(mostrecentcalllast):File"<stdin>",line1,in?File"<stdin>",line3,individeTypeError:unsupportedoperandtype(s)for/:'str'and'str'

Reparequeobloco finally é executado em todosos casos.A exceçãoTypeError levantadapeladivisãodeduasstringsenãoétratadanoexcepteportantoérelançadadepoisqueofinallyéexecutado.

EditoraCasadoCódigocomlivrosdeumaformadiferente

12.5PARASABERMAIS:FINALLY

.

Page 187: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Emaplicações reais,o finally éútil para liberar recursos externos (comoarquivosou conexõesderede),independentementedousodorecursotersidobemsucedidoounão.

NoPython todas as exceções são instânciasdeuma classederivadadeBaseException. Elanãoserve para ser diretamente herdada por exceções criadas por programadores, para isso utilizamosExceptionquetambéméfilhadeBaseException.

AbaixoestáahierarquiadeclassesdeexceçõesdoPython.Paramais informaçõessobrecadaumadelasconsulteadocumentação:https://docs.python.org/3/library/exceptions.html

BaseException+--SystemExit+--KeyboardInterrupt+--GeneratorExit+--Exception+--StopIteration+--StopAsyncIteration+--ArithmeticError|+--FloatingPointError|+--OverflowError|+--ZeroDivisionError+--AssertionError+--AttributeError+--BufferError+--EOFError+--ImportError|+--ModuleNotFoundError+--LookupError|+--IndexError|+--KeyError+--MemoryError+--NameError|+--UnboundLocalError+--OSError|+--BlockingIOError|+--ChildProcessError|+--ConnectionError||+--BrokenPipeError||+--ConnectionAbortedError||+--ConnectionRefusedError||+--ConnectionResetError|+--FileExistsError|+--FileNotFoundError|+--InterruptedError|+--IsADirectoryError|+--NotADirectoryError|+--PermissionError|+--ProcessLookupError|+--TimeoutError+--ReferenceError+--RuntimeError|+--NotImplementedError|+--RecursionError+--SyntaxError|+--IndentationError

12.6ÁRVOREDEEXCEÇÕES

.

Page 188: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

|+--TabError+--SystemError+--TypeError+--ValueError|+--UnicodeError|+--UnicodeDecodeError|+--UnicodeEncodeError|+--UnicodeTranslateError+--Warning+--DeprecationWarning+--PendingDeprecationWarning+--RuntimeWarning+--SyntaxWarning+--UserWarning+--FutureWarning+--ImportWarning+--UnicodeWarning+--BytesWarning+--ResourceWarning

1. Na classe Conta, modifique o método deposita(). Ele deve lançar uma exceção chamadaValueError,que já fazpartedabibliotecapadrãodoPython, semprequeovalorpassadocomoargumentoforinválido(porexemplo,quandofornegativo):

defdeposita(self,valor):if(valor<0):raiseValueErrorelse:self._saldo+=valor

2. Da maneira com está, apenas saberemos que ocorreu um ValueError mas não saberemos omotivo.Vamosacrescentarumamensagemparadeixaroerromaisclaro:

defdeposita(self,valor):if(valor<0):raiseValueError('Vocêtentoudepositarumvalornegativo')else:self._saldo+=valor

3. Façaomesmoparaométodosaca()daclasseContaCorrente,afinaloclientetambémnãopodesacarumvalornegativo.

4. Vamosvalidartambémqueoclientenãopodesacarumvalormaiordoqueosaldodisponívelemconta.CriesuaprópriaexceçãochamadaSaldoInsuficienteError.Paraisso,vocêprecisacriarumaclassecomessenomequesejafilhadeRuntimeError.

classSaldoInsuficienteError(RuntimeError):pass

NométodosacadaclasseContaCorrentevamosutilizarestanovaexceção:

classContaCorrente(Conta):#códigoomitido

12.7EXERCÍCIOS:EXCEÇÕES

.

Page 189: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

defsaca(self,valor):if(valor<0):raiseValueError('Vocêtentousacarumvalornegativo')if(self._saldo<valor):raiseSaldoInsuficienteError()self._saldo-=(valor+0.10)

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

Errosde sintaxeUmdos errosmais comuns é oSyntaxError.Geralmente suasmensagensnãodizemmuito,amaiscomuméaSyntaxError:invalidsyntax.Poroutro lado,amensagemdiz o local onde o problema ocorreu. - onde o Python encontrou o problema. São descobertosquandoo interpretador está traduzindoo código fonteparaobytecode. Indicamqueháalgodeerradocomaestruturadoprograma.Porexemplo:esquecerdefecharaspas,simplesouduplas,nahorade imprimirummensagem;esquecerdecolocardoispontos (":")ao finaldeuma instruçãoif,whileoufor,etc...

Erro semântico Este erro é quando o programa não se comporta como esperado. Aqui não élançada uma exceção, o programa apenas não faz a coisa certa. São mais difíceis de encontrarporqueointerpretadornãofornecenenhumainformaçãojáquenãosabeoqueoprogramadeveriafazer.Sãoerrosnaregradenegócio.Utilizarafunçãoprint()emalgunslugaresdocódigoondevocêsuspeitaqueestágerandooerropodeajudar.

JáconheceoscursosonlineAlura?

12.8OUTROSERROS

.

Page 190: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

OdepuradordoPython,opdb,éummóduloembutidoquefuncionacomoumconsoleinterativoondeépossívelrealizardebugdecódigospython.Vocêpodelermaisarespeitonadocumentação:https://docs.python.org/3/library/pdb.html

12.9PARASABERMAIS-DEPURADORDOPYTHON

.

Page 191: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO13

Objetivos:

conheceromódulocollectionsconheceromódulocollections.abc

No capítulo 4 vimos uma introdução das principais estruturas de dados do Python como listas,tuplas,conjuntosedicionários.TambémaprendemosemorientaçãoaobjetosquetudoemPythonéumobjeto,inclusiveessasestruturas.

O Python possui uma biblioteca chamada collections que reúne outros tipos de dadosalternativosaojáapresentadosnocapítulo4.Essestipostrazemnovasfuncionalidades.

Omódulocollectionstambémprovêummódulodeclassesabstratas,omóduloabc.collections,quepodemserusadasparatestarsedeterminadaclasseprovêumainterfaceparticulareaprenderemosumpoucosobreelaseseuuso.

AsestruturasdedadospadrãodoPythonsãodegrandevaliaemuitoutilizadasnalinguagem,masexistemmomentosqueprecisamosdefuncionalidadesextrasquesãocomunsdeprojetoparaprojeto.Nessesentidosurgeomódulocollections,praacrescentaressasfuncionalidades.

Porexemplo,noRaspberryPiouArduino,umaplacaprogramadacompinosGPIOérepresentadapor um objeto board com um atributo pins. Esse atributo contém ummapeamento das localizaçõesfísicasdospinosparaobjetosque representamospinos.A localização físicapode serumnúmeroouumastringcomo"A0"ou"B1".Porconsistência,édesejávelquetodasaschavessejamstringsassimcomoéconvenientequefuncioneparapin[13]quandooprogramadordesejarfazerpiscaroLEDdopino13.

Precisamos usar índices que são strings, portanto um dicionário. Além disso, nosso dicionáriopoderiaapenasaceitarstringscomochavesparaesteobjetivoespecífico.Paranãotratarissoduranteaexecuçãodenossoprogramapodemoscriarumaclassequetenhaocomportamentodeumdicionáriocomessacaracterísticaespecífica.

Para isso, criamos uma classe que herda de uma classe chamada UserDict do pacotecollections:

COLLECTIONS

13.1USERLIST,USERDICTEUSERSTRING

.

Page 192: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

classMeuDicionario(UserDict):pass

AclasseUserDict não herda dedictmas simula um dicionário. AUserDict possui umainstânciadedictinternachamadadata,quearmazenaositenspropriamenteditos.

Criarsubclassesdetiposembutidoscomodictoulistdiretamenteépropensoaerrosporqueseusmétodos geralmente ignoram as versões sobrescritas.Além de que cada implementação pode secomportardemaneiradiferente.OfatodeherdarmosdeUserDictenãodiretamentededictéparaevitaressesproblemas.

Criandoaclassedestamaneira,temosumaclassenossaquefuncionacomoumdicionário.Masnãofazsentidocriá-lasemacrescentarfuncionalidades,jáqueoPythonjápossuiessaestruturaprontaqueéodict.

Vamoscriarnossodicionáriodemodoque sóaceite chaves comostrings e vai representar ospinosdaplacadoRasbperryPi,porexemplo:

classPins(UserDict):

def__contains__(self,key):returnstr(key)inself.keys()

def__setitem__(self,key,value):self.data[str(key)]=value

Notequeasobrescritade__setitem__garantequeachavesempreseráumastring.Podemostestaressaclasse:

if__name__=='__main__':pins=Pins(one=1)print(pins)pins[3]=1lista=[1,2,3]pins(lista)=2print(pins)

Percebaquequandoimprimimosodicionário,todassuaschavessãostrings.

.

Page 193: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

Outros tipos que existem no módulo collections são: defaultdict , counter , deque enamedtuple.

Aocontráriododict,nodefaultdictnãoénecessárioverificarseumachaveestápresenteounão.

cores=[('1','azul'),('2','amarelo'),('3','vermelho'),('1','branco'),('3','verde')]

cores_favoritas=defaultdict(list)

forchave,valorincores:cores_favoritas[chave].append(valor)

print(cores_favoritas)

Ocódigovaigerarasaída:

[('1',['azul','branco']),('2',['amarelo']),('3',['vermelho','verde'])]

SemacusarKeyError.

Counter

OCounter é um contador e permite contar as ocorrências de um determinado item em umaestruturadedados:

fromcollectionsimportCounter

cores=['amarelo','azul','azul','vermelho','azul','verde','vermelho']

contador=Counter(cores)

print(contador)

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

13.2PARASABERMAIS

.

Page 194: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Vaiimprimir:

Counter({'azul':3,'vermelho':2,'amarelo':1,'verde':1})

UmCounteréumdictepodereceberumobjetoiterávelouummapacomoargumentopararealizaracontagemdeseuselementos.

deque

Odequeéumaestruturadedadosque forneceumafila comduas extremidades e é possíveladicionareremoverelementosdeambososlados:

fromcollectionsimportdeque

fila=deque()

fila.append('1')fila.append('2')fila.append('3')

print(len(fila))#saída:3

fila.pop()#excluielementodadireita

fila.append('3')#adicionaelementonadireita

fila.popleft()#excluielementodaesquerda

fila.appendleft('1')#adicionaelementonaesquerda

namedtuple

Anamedtuple,comoonomesugere,sãotuplasnomeadas.Nãoénecessáriousaríndicesinteirosparaacessarseuselementosepodemosutilizarstrings- similaraosdicionários.Masaocontráriosdosdicionários,namedtupleéimutável:

fromcollectionsimportnamedtuple

Conta=namedtuple('Conta','numerotitularsaldolimite')conta=Conta('123-4','João',1000.0,1000.0)

print(conta)#saída:Conta(numero='123-4',titular='João',saldo=1000.0,limite=1000.0)

print(conta.titular)#saída:João

Notequepara acessaro elementonomeadoutilizamosooperador '.' (ponto).Umanamedtupleposuidoisargumentosobrigatóriosquesão:onomedatuplaeseuscampos(separadosporvírgulaouespaço).No exemplo, a tupla se chamaConta e possui 4 campos:numero,titular,saldo elimite.Comosãoimutáveis,nãopodemosmodificarosvaloresdeseuscampos:

conta.titular="José"

Issovaigeraroseguinteerro:

Traceback(mostrecentcalllast):

.

Page 195: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

File<stdin>,line5,in<module>conta.titular="José"AttributeError:can'tsetattribute

Anamedtupletambémécompatívelcomumatuplanormal.Issoquerdizerquevocêtambémpodeusaríndicesinteirosparaacessarseuselementos.

print(conta[0])#saída:'123-4'

Maisdetalhesde cadaumadessas estruturas estãonadocumentação epode ser acessadapor estelink:https://docs.python.org/3/library/collections.html.Outraalternativaéusarafunção`help(){}noobjetoparaacessaradocumentação.

Omódulocollections.abc fornece classes abstratas quepodem serusadaspara testar seumaclasseforneceumainterfaceespecífica.Porexemplo,seelaéiterávelounão.

Imaginequeobanconosentregouumarquivocomváriosfuncionáriosepediuquecalculássemosabonificação de cada um deles. Precisamos acrescentar este arquivo em nossa aplicação para iniciar aleitura.

Conteúdodoarquivofuncionarios.txt:

João,111111111-11,2500.0Jose,222222222-22,3500.0Maria,333333333-33,4000.0Pedro,444444444-44,2500.0Mauro,555555555-55,1700.0Denise,666666666-66,3000.0Tomas,777777777-77,4200.0

CadalinhadoarquivorepresentaumFuncionariocomseusatributosseparadosporvírgula.EstearquivoestánopadrãoComma-separated-values,tambémconhecidocomocsvesãocomumenteusados.OPythondásuportedeleituraparaestetipodearquivo.Entãovamosacrescentaromódulocsvquevaiajudarnatarefadeleroarquivo:

importcsv

arquivo=open('funcionario.txt','r')leitor=csv.reader(arquivo)

forlinhainleitor:print(linha)

arquivo.open()

Oprogramaacimaabreumarquivoeum leitordomódulocsv,oreader - recebeo arquivocomoparâmetroedevolveumleitorquevai ler linhaa linhaeguardarseuconteúdo.Podemos iterarsobreesteleitorepedirparaimprimiroconteúdodecadalinha-queéexatamenteoqueéfeitonolaçofor.Porúltimofechamosoarquivo.

13.3COLLECTIONSABC

.

Page 196: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Asaídaserá:

['João','111111111-11','2500.0']['Jose','222222222-22','3500.0']['Maria','333333333-33','4000.0']['Pedro','444444444-44','2500.0']['Mauro','555555555-55','1700.0']['Denise','666666666-66','3000.0']['Tomas','777777777-77','4200.0']

Reparequeoreaderguardacadalinhadeumarquivoemumalistaecadavalordelimitadoporvírgulasetornaumelementodestalistaoquefacilitaoacessoaosdados.

Agora,comestesdadosemmãos,podemosconstruirnossosobjetosdetipoFuncionario:

forlinhainreader:funcionario=Funcionario(linha[0],linha[1],linha[2])

Masaindaprecisamosdeumaestruturaparaguardá-los.Vamosutilizarumalista:

funcionarios=[]

forlinhainreader:funcionario=Funcionario(linha[0],linha[1],linha[2])funcionarios.append(funcionario)

Eporfimimprimimosossaldosdalista:

forfinfuncionarios:print(f.saldo)

Acontecequenadaimpede,posteriormente,deinserirmosnestalistaqualqueroutroobjetoquenãoumfuncionário:

funcionarios.append('Python')funcionarios.append(1234)funcionarios.append(True)

Alist da bibliotecapadrão aceita qualquer tipodeobjeto como elemento.Nãoqueremos estecomportamentojáqueiremoscalcularabonificaçãodecadaumdelesedependendodotipodeobjetosinseridonalista,geraráerros.

OidealéquetivéssemosumaestruturadedadosqueaceitasseapenasobjetosdetipoFuncionario.Omódulocollections.abcfornececlassesabstratasquenosajudamaconstruirestruturasespecíficas,comcaracterísticasdaregradenegóciodaaplicação.

Omódulocollections.abcpossuiumaclasseabsratachamadaContainer>Umcontaineréqualquer objeto que contém um número arbitrário de outros objetos. Listas, tuplas, conjuntos edicionários são tipos de containers. A classe Container suporta o operador in com o método__contains__.

13.4CONSTRUINDOUMCONTAINER

.

Page 197: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

PrecisamosconstruirumcontainerdeobjetosdetipoFuncionario.PodemosconstruirumaclassequerepresentaráessaestruturaquedevesersubclassedeContainer:

fromcollections.abcimportContainer

classFuncionarios(Container):pass

if__name__=='__main__':funcionarios=Funcionarios()

OcódigoacimaacusaumTypeError:

TypeError:Can'tinstantiateabstractclassFuncionarioswithabstractmethods__contains__

Precisamos implementar ométodo __contains__ já queFuncionarios deve implementar aclasseabstrataContainer.Aideiaéquenossocontainersecomportecomoumalista,entãoteremosumatributodotipolistaemnossaclasseparaguardarosobjetoseimplementarométodocontains:

fromcollections.abcimportContainer

classFuncionarios(Container):

_dados=[]

def__contains__(self,posicao):returnself._dados.__contains__(self,posicao)

if__name__=='__main__':funcionarios=Funcionarios()

Conheça a Casa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Com a curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.

CasadoCódigo,LivrosdeTecnologia.

Otamanhodonossocontainertambéméumainformaçãoimportante.NossaclasseFuncionariosdevesaberretornaressevalor.UtilizamosaclasseabstrataSizedparagarantiressafuncionalidade.AclasseSizedprovêométodolen()atravésdométodoespecial__len__():

Seuslivrosdetecnologiaparecemdoséculopassado?

13.5SIZED

.

Page 198: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

fromcollections.abcimportContainer

classFuncionarios(Container,Sized):

_dados=[]

def__contains__(self,posicao):returnself._dados.__contains__(self,posicao)

def__len__(self):returnlen(self._dados)

if__name__=='__main__':funcionarios=Funcionarios()

Além de conter objetos e saber retornar a quantidade de seus elementos, queremos que nossocontainersejaiterável,ouseja,queconsigamositerarsobreseuselementosemumlaçofor,porexemplo.Omódulocollection.abc tambémprovêumaclasse abstratapara este comportamento, é a classeIterable.Iterablesuportaiteraçãocomométodo__iter__:

fromcollections.abcimportContainer

classFuncionarios(Container,Sized,Iterable):

_dados=[]

def__contains__(self,posicao):returnself._dados.__contains__(self,posicao)

def__len__(self):returnlen(self._dados)

def__iter__(self):returnself._dados.__iter__(self)

if__name__=='__main__':funcionarios=Funcionarios()

TodacoleçãodeveherdardessasclassesABCs:Container,IterableeSized.Ouimplementarseusprotocolos:__contains__,__iter__e__len__.

Alémdessas classes existem outras que facilitam esse trabalho e implementamoutros protocolos.Vejaahierarquiadeclassedomódulocollections.abc:

Figura13.1:legendadaimagem

Alémdoquejáfoiimplementado,aideiaéquenossaclasseFuncionariofuncionecomoumalistacontando apenas objetos do tipoFuncionario. Como aprendemos no capítulo 4, uma lista é umasequência.Alémdeumasequência,éumasequênciamutável-podemosadicionarelementosemuma

13.6ITERABLE

.

Page 199: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

lista.NossaclasseFuncionariotambémdevepossuiressafuncionalidade.

Segundoodiagramadeclassesdomódulocollections.abc,aclassequerepresentaessaestruturaé a MutableSequence . Note que MutableSequece herda de Sequence que representa umasequência;queporsuavezherdadeContainer,IterableeSized.

Figura13.2:legendadaimagem

Portanto, devemos implementar 5 métodos abstratos (em itálico na imagem) segundo adocumentaçãodeMutableSequence:__len__,__getitem__,__setitem__,__delitem__ einsert.Ométodo__getitem__garantequeaclasseéumContainereIterable.SegundoaPEP234 (https://www.python.org/dev/peps/pep-0234/) um objeto pode ser iterável com um laço for seimplementa__iter__ou__getitem__.

Então,bastanossaclasseFuncionarioherdardeMutableSequenceeimplementarseusmétodosabstratos:

classFuncionarios(MutableSequence):

_dados=[]

def__len__(self):returnlen(self._dados)

def__getitem__(self,posicao):returnself._dados[posicao]

def__setitem__(self,posicao,valor):self._dados[posicao]=valor

def__delitem__(self,posicao):delself._dados[posicao]

definsert(self,posicao,valor):returnself._dados.insert(posicao,valor)

E podemos voltar ao nosso código para acrescentar os dados de um arquivo em nosso containerFuncionarios:

.

Page 200: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

importcsv

arquivo=open('funcionario.txt','r')leitor=csv.reader(arquivo)

funcionarios=Funcionarios()

forlinhainleitor:funcionario=Funcionario(linha[0],linha[1],linha[2])funcionarios.append(funcionario)

arquivo.open()

Ométodoinsert() garante o funcionamentodométodoappend(). Epodemos imprimir osvaloresdossaláriosdecadafuncionário:

forfinfuncionarios:print(f.salario)

Masatéaquinãohánadadediferentedeumalistacomum.Aindanãohánadaqueimpeçadeinserirqualqueroutroobjetoemnossalista.NossaclasseFuncionariossecomportacomoumalistacomum.A ideia de implementarmos as interfaces de collections.abc era exatamente modificar algunscomportamentos.

QueremosquenossalistadefuncionáriosapenasaceiteobjetosFuncionario.Vamossobrescreverosmétodos__setitem__()queatribuiuumvaloremdeterminadaposiçãonalista.EstemétodopodeapenasatribuiraumadeterminadaposiçãoumobjetoFuncionario.

Paraisso,vamosusarométodoisinstance()quevaiverificarseoobjetoaseratribuídoéumainstância de Funcionario . Caso contrário, vamos lançar uma exceção TypeError com umamensagemdeerro:

def__setitem__(self,posicao,valor):if(isinstance(valor,Funcionario)):self._dados[posicao]=valorelse:raiseValueError('ValoratribuídonãoéumFuncionario')

Agora, ao tentar atribuir uma valor a determinada posição de nossa lista, recebemos umTypeError:

funcionarios[0]='Python'

Saída:

Traceback(mostrecentcalllast):File<stdin>,line18,in__setitem__raiseValueError('ValoratribuídonãoéumFuncionario')ValueError:valoratribuídonãoéumFuncionario

Faremosomesmocomométodoinsert():

definsert(self,posicao,valor):if(isinstance(valor,Funcionario)):returnself._dados.insert(posicao,valor)

.

Page 201: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

else:raiseValueError('ValorinseridonãoéumFuncionario')

EpodemostestarnossaclasseimprimindonãoapenasosaláriomasovalordabonificaçãodecadaFuncionarioatravésdométodoget_bonificacao()quedefinimosnoscapítulospassados:

if__name__=='__main__':importcsv

arquivo=open('funcionario.txt','r')leitor=csv.reader(arquivo)

funcionarios=Funcionarios()

forlinhainleitor:funcionario=Funcionario(linha[0],linha[1],linha[2])funcionarios.append(funcionario)

print('salário-bonificação')forcincontas:print('{}-{}'.formar(f.salario,f.get_bonificacao()))

arquivo.open()

AsclassesABCsforamcriadasparaencapsularconceitosgenéricoseabstraçõescomoaprendemosno capítulo de classes abstratas. São comumente utilizadas em grandes aplicações e frameworks paragarantiraconsistênciadosistemaatravésdosmétodosisinstance()eissubclass().NodiaadiaéraramenteusadoebastaousocorretodasestruturasjáfornecidaspelabibliotecapadrãodoPythonparaamaiorpartedastarefas.

Conheceromódulocollections.abcé

1. Vánapastanocursoecopieoarquivocontas.txtnapastasrcdoprojetobancoquecontémváriosdadosdecontascorrentesdeclientesdobanco.

2. Crieumarquivochamadocontas.pynapastasrcdoprojetobanco.Crieuma classe chamadaContasqueherdedaclasseabstrataMutableSequence:

fromcollections.abcimportSequence

classContas(MutableSequence):pass

3. Vamoscriarumatributodaclassedotipolistparaarmazenarnossascontas:

fromcollections.abcimportMutableSequence

classContas(MutableSequence):

_dados=[]

4. TenteinstanciarumobjetodetipoContas:

13.7EXERCÍCIO:CRIANDONOSSASEQUÊNCIA

.

Page 202: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

if__name__=='__main__':contas=Contas()

Note que não podemos instanciar este objeto. A interface MutableSequence nos obriga aimplementaralgunsmétodos:

Traceback(mostrecentcalllast):File<stdin>,line44,in<module>contas=Contas()TypeError:Can'tinstantiateabstractclassContaswithabstractmethods__delitem__,__getitem__,__len__,__setitem__,insert

5. ImplementeosmétodosexigidospelainterfaceMutableSequencenaclasseContas:

fromcollections.abcimportMutableSequence

classContas(MutableSequence):

_dados=[]

def__len__(self):returnlen(self._dados)

def__getitem__(self,posicao):returnself._dados[posicao]

def__setitem__(self,posicao,valor):self._dados[posicao]=valor

def__delitem__(self,posicao):delself._dados[posicao]

definsert(self,posicao,valor):returnself._dados.insert(posicao,valor)

Agoraconseguimosinstanciarnossaclassesemnenhumerro:

if__name__=='__main__':contas=Contas()

6. NossasequênciasódevepermitiradicionarelementosquesejamdotipoConta.Vamosacrescentaressavalidaçãonosmétodos__setitem__einsert.CasoovalornãosejaumaConta, vamoslançarumValueErrorcomasdevidasmensagensdeerro:

def__setitem__(self,posicao,valor):if(isinstance(valor,Conta)):self._dados[posicao]=valorelse:raiseValueError("valoratribuídonãoéumaconta")

definsert(self,posicao,valor):if(isinstance(valor,Conta)):returnself._dados.insert(posicao,valor)else:raiseValueError('valorinseridonãoéumaconta')

7. Vamosiniciaraleituradosdadosdoarquivoparaarmazenaremnossoobjetocontas:

if__name__=='__main__':

.

Page 203: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

importcsv

contas=Contas()

arquivo=open('contas.txt','r')leitor=csv.reader(arquivo)

arquivo.close()

8. Vamos criar uma laço for para ler cada linha do arquivo e construir um objeto do tipoContaCorrente.

if__name__=='__main__':importcsvfromcontaimportContaConrrete

contas=Contas()

arquivo=open('contas.txt','r')leitor=csv.reader(arquivo)

forlinhainleitor:conta=ContaCorrente(linha[0],linha[1],linha[2],linha[3])

arquivo.close()

9. Queremosinserircadacontacriadaemnossasequênciamutávelcontas.Vamospedirparaqueoprogramaacrescentecadacontacriadaemcontas:

forlinhainleitor:conta=ContaCorrente(linha[0],linha[1],float(linha[2]))contas.append(conta)

arquivo.close()

10. Nossa classe Contas implementa MutableSequence. Isso quer dizer que ela é iterável já queMutableSequenceimplementaoprotocolo__iter__atravésdométodo__getitem__.Vamositerar através de uma laço for nosso objetocontas e pedir para imprimir o saldo e o valor doimpostodecadaumadelas:

if__name__=='__main__':#códigoomitido

arquivo.close()

print('saldo-imposto')

forcincontas:print('{}-{}'.format(c.saldo,c.get_valor_imposto()))

Quevaigerarasaída:

saldo-imposto1200.0-12.02200.0-22.01500.0-15.05300.0-53.07800.0-78.0

.

Page 204: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

1700.0-17.02300.0-23.08000.0-80.04600.0-46.09400.0-94.0

11. (Opcional) Modifique o código do exercício anterior de modo que imprima o valor do saldoatualizadodascontas.

12. (Opcional) Faça omesmo com as contas poupanças.Crie um arquivo com extensão.csv comalgumas contas poupanças, faça a leitura, construa os objetos e acrescente em uma estrutura dedadosdotipoMutableSequence.

13. (Opcional)RefaçaoexercícioutilizandoMutableMappingaoinvésdeMutableSequence.

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

Agoraéamelhorhoradeaprenderalgonovo

.

Page 205: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO14

Caso você esteja iniciando seus estudos na linguagem Python ou começando um projeto novo,aconselhamosfortementequevocêutilizeoPython3.

OPython2vemsendochamadodePythonlegadoouPythonantigoporboapartedacomunidadeque está em constante atividade para fazer amigração da base de código existente (bem grande, porsinal)paraPython3.

Aconselhamos a leitura deste artigo para maiores detalhes:https://wiki.python.org/moin/Python2orPython3.

Aperguntacorretaaquié:QuandodevousaroPythonantigo?Earespostamaiscomumquevocêvaiencontraré:usePythonantigoquandovocênãotiverescolha.

Porexemplo,quandovocêtrabalharemumprojetoantigoemigrarparaanovaversãonãoforumaalternativa nomomento.Ou quando você precisa utilizar uma biblioteca que ainda não funciona noPython3ounão está emprocessodemudança.Outro caso é quando seu servidordehospedagem sópermiteusarPython2-aquioaconselháveléprocurarporoutroserviçoqueatendasuademanda.

Nomais,vocêencontrarámuitomaterialsobreoPython2nainterneteaospoucosvaiconhecendomelhorasdiferençasentreumaversãoeoutra.

Nesteartigovocêvaiencontrararespostahttps://docs.python.org/3/whatsnew/3.0.html.Masnestecapítulomostramosasdiferençasmaisbásicaseimportantesparavocêiniciarseusestudos.

APÊNDICE-PYTHON2OUPYTHON3?

14.1QUAISASDIFERENÇAS?

.

Page 206: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design, Infra,Front-Ende

Business!Ex-alunodaCaelumtem15%dedesconto,sigaolink!

ConheçaaAluraCursosOnline.

No Python2 o comando print funciona de maneira diferente já que não é uma função. Paraimprimiralgofazemos:

#nopython2>>>print"HelloWorld!"HelloWorld!

NoPython3printéumafunçãoeutilizamososparêntesescomodelimitadores:

#nopython3>>>print("HelloWorld!")HelloWorld!

Afunçãoraw_inputdoPython2foirenomeadaparainput()noPython3:

#nopython2>>>nome=raw_input("Digiteseunome:")

NoPython3:

#nopython3>>>nome=input("Digiteseunome:")

NoPython2adivisãoentrenúmerosdecimaisédiferenteentreumnúmerodecimaleuminteiro:

#nopython2>>>5/22>>>5/2.02.5

Agoraéamelhorhoradeaprenderalgonovo

14.2AFUNÇÃOPRINT()

14.3AFUNÇÃOINPUT()

14.4DIVISÃODECIMAL

.

Page 207: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

No Python3 a divisão tem omesmo comportamento damatemática. E se quisermos o resultadointeirodadivisãoutilizamos//:

#nopython3>>>5/22.5>>>5//22

Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelum eobsessãoporlivrosdequalidadeapreçosjustos.

CasadoCódigo,ebookcompreçodeebook.

NoPython2suasclassesdevemherdardeobject:

#nopython2>>>classMinhaClasse(object):defmetodo(self,attr1,attr2):returnattr1+attr2

NoPython3essaherançaéimplícita,nãoprecisandoherdarexplicitamentedeobject:

#nopython3>>>classMinhaClasse():defmetodo(self,attr1,attr2):returnattr1+attr2

EditoraCasadoCódigocomlivrosdeumaformadiferente

14.5HERANÇA

.

Page 208: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

CAPÍTULO15

OPythonjáveminstaladonossistemasLinuxeMacOSmasseránecessáriofazerodownloaddaúltimaversão(Python3.6)paraacompanharaapostila.OPythonnãoveminstaladoporpadrãonoWindowseodownloaddeveráserfeitonositehttps://www.python.org/alémdealgumasconfiguraçõesextras.

OprimeiropassoéacessarositedoPython:https://www.python.org/.NasessãodeDownloadsjáserá disponibilizado o instalador específico do Windows automaticamente, portanto é só baixar oPython3,nasuaversãomaisatual.

Figura15.1:TeladedownloaddoPythonparaoWindows

Apósodownload ser finalizado, abra-o enaprimeira telamarque aopçãoAddPython3.XtoPATH.EssaopçãoéimportanteparaconseguirmosexecutaroPythondentrodoPromptdeComandodoWindows.Casovocênãotenhamarcadoestaopção,teráqueconfiguraravariáveldeambientenoWindowsdeformamanual.

APÊNDICE-INSTALAÇÃO

15.1INSTALANDOOPYTHONNOWINDOWS

.

Page 209: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Figura15.2:Checkboxselecionado

Selecioneainstalaçãocustomizadasomenteparaverainstalaçãocommaisdetalhes.

Figura15.3:Instalaçãocustomizada

Na tela seguinte são as featuresopcionais, se certifiquequeo gerenciadordepacotespip estejaselecionado, ele que permite instalar pacotes e bibliotecas no Python. Clique em Next para dar

.

Page 210: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

seguimentonainstalação.

Figura15.4:OptionalFeatures

Jána terceira tela,deixe tudocomoestá,mas seatenteaodiretóriode instalaçãodoPython,paracasoqueiraprocuraroexecutáveloualgoqueenvolvaoseudiretório.

Figura15.5:AdvancedOptions

.

Page 211: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

Porfim,bastaclicaremInstalleaguardarotérminodainstalação.

Figura15.6:InstalaçãoConcluídacomSucesso

Terminadaainstalação,testeseoPythonfoiinstaladocorretamente.AbraoPromptdeComandoeexecute:

python-V

OBS:ParaquefuncionecorretamenteénecessárioquesejanoPromptdeComandoenãoemalgumprogramaGitBashinstaladoemsuamáquina.Eocomandopython-VéimportantequeestejacomoVcomletramaiúscula.

EssecomandoimprimeaversãodoPythoninstaladanoWindows.Seaversãoforimpressa,significaqueoPythonfoiinstaladocorretamente.Agora,rodeocomandopython:

python

AssimvocêteráacessoaoconsoledopróprioPython,conseguindoassimutilizá-lo.

.

Page 212: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

AAlura oferece centenasdecursosonline em suaplataforma exclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,

Design & UX, Infra e Business, com um plano que dá acesso a todos os cursos. Ex-aluno daCaelumtem15%dedescontonestelink!

ConheçaoscursosonlineAlura.

OssistemasoperacionaisbaseadosnoDebianjápossuemoPython3pré-instalado.VerifiqueseoseusistemajápossuioPython3instaladoexecutandooseguintecomandonoterminal:

python3-V

OBS:Ocomandopython3-VéimportantequeestejacomoVcomletramaiúscula.

EstecomandoretornaaversãodoPython3instalada.Sevocêaindanãotivereleinstalado,digiteosseguintescomandosnoterminal:

sudoapt-getupdatesudoapt3-getinstallpython

ParaquevocêconsigainstalarospacotesdoPythonénecessárioterogerenciadordepacotespipinstaladonosistema.Parainstalaressegerenciador,digitenoterminal:

sudoapt-getinstallpython-pip

AmaneiramaisfácildeinstalaroPython3noMacOSéutilizandooHomebrew.ComoHomebrewinstalado,abraoterminaledigiteosseguintescomandos:

brewupdatebrewinstallpython3

ParaquevocêconsigainstalarospacotesdoPythonénecessárioterogerenciadordepacotespipinstaladonosistema.Parainstalaressegerenciador,digitenoterminal:

sudoapt-getinstallpython-pip

JáconheceoscursosonlineAlura?

15.2INSTALANDOOPYTHONNOLINUX

15.3INSTALANDOOPYTHONNOMACOS

.

Page 213: Python e Orientação a Objetos - Caelum | Cursos de …...10.7 Exercício: Herança e Polimorfismo 145 10.8 Classes Abstratas 148 10.9 Exercícios - classes abstratas 150 11 Herança

PodemosrodaroPythondiretamentedoseupróprioPrompt.

Podemos procurar pelo Python na caixa de pesquisa doWindows e abri-lo, assim o seu consolepróprioseráaberto.UmaoutraformaéabriraIDLEdoPython,queseparecemuitocomoconsolemasvemcomummenuquepossuialgumasopçõesextras.

Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelumofereceocursoPY-14 presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.

ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos

15.4OUTRASFORMASDEUTILIZAROPYTHON

VocêpodetambémfazerocursoPY-14dessaapostilanaCaelum

.