Download - Python e Orientação a Objetos
![Page 1: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/1.jpg)
![Page 2: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/2.jpg)
![Page 3: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/3.jpg)
1
3
14
Sumário
1ComoaprenderPython1.1Oqueérealmenteimportante? 1
1.2Sobreosexercícios 1
1.3Tirandodúvidaseindoalém 2
2OqueéPython2.1Python 3
2.2BreveHistória 3
2.3Interpretador 4
2.4Qualversãoutilizar? 5
2.5Download 6
2.6Cpython,Jython,IronPython? 6
2.7PEP-Oquesãoepraqueservem 7
2.8Ondeusareobjetivos 7
2.9Primeiroprograma 8
2.10ModoInterativo 8
2.11ModoScript 9
2.12Exercício:Modificandooprograma 11
2.13Oquepodedarerrado? 11
3Variáveisetiposembutidos3.1Tiposembutidos(built-ins) 14
3.2Variáveis 15
3.3Parasabermais:Nomesdevariáveis 16
3.4Instruções 17
3.5OperadoresAritméticos 18
3.6Strings 19
3.7Entradadousuário 20
3.8Constantes 22
3.9Comandoif 25
SumárioCaelum
![Page 4: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/4.jpg)
37
44
63
73
3.10Convertendoumastringparainteiro 26
3.11Ocomandoelif 27
3.12Exercícios-Jogodaadivinhação 28
3.13Comandowhile 30
3.14Exercícios-Jogocomwhile 32
3.15Comandofor 34
3.16Exercícios-Utilizandoofornojogo 35
4IntroduçãoaoPycharm4.1IDE 37
4.2Pycharm 38
4.3DownloadeInstalaçãodoPyCharm 39
4.4CriandoumProjeto 40
4.5Executandocódigo 42
4.6PrincipaisAtalhos 43
5Estruturadedados5.1Exercícios:JogodaForca 48
5.2Sequências 51
5.3Conjuntos 56
5.4Dicionários 57
5.5Exercícios:Estruturadedados 59
6Funções6.1Oqueéumafunção? 63
6.2ParâmetrosdeFunção 64
6.3Funçãocomretorno 65
6.4Retornandomúltiplosvalores 66
6.5Exercícios:Funções 67
6.6Númeroarbitráriodeparâmetros(*args) 68
6.7Númeroarbitráriodechaves(**kwargs) 69
6.8Exercício-*argse**kwargs 70
6.9Exercício-Funçãojogar() 71
6.10Móduloseocomandoimport 72
7Arquivos7.1Escritadeumarquivo 73
7.2Fechandoumarquivo 74
7.3Escrevendopalavrasemnovaslinhas 74
7.4Exercícios 75
CaelumSumário
![Page 5: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/5.jpg)
89
110
126
137
7.5Lendoumarquivo 76
7.6Lendolinhaporlinhadoarquivo 77
7.7Gerandoumnúmeroaleatório 78
7.8Exercícios-Leituradearquivos 79
7.9Parasabermais-comandowith 81
7.10Melhorandonossocódigo 81
7.11Exercício-RefatorandoojogodaForca 82
8OrientaçãoaObjetos8.1Funcionalidades 90
8.2Exercício:Criandoumaconta 91
8.3ClasseseObjetos 92
8.4Construtor 94
8.5Métodos 96
8.6Métodoscomretorno 97
8.7Objetossãoacessadosporreferência 98
8.8Métodotransfere 100
8.9Continuandocomatributos 101
8.10Tudoéobjeto 103
8.11Composição 104
8.12Parasabermais:outrosmétodosdeumaclasse 106
8.13Exercício:PrimeiraclassePython 107
9Modificadoresdeacessoemétodosdeclasse9.1Encapsulamento 113
9.2Atributosdeclasse 117
9.3Métodosdeclasse 120
9.4Parasabermais-Slots 121
9.5Exercícios: 123
10PycharmeOrientaçãoaobjetos10.1CriandoumProjeto 126
10.2Criandoumaclasse 128
10.3Executandocódigo 130
10.4Criandométodos 132
10.5Exercício-CriandoprojetobanconoPyCharm 133
11HerançaePolimorfismo11.1Repetindocódigo? 137
11.2Reescritademétodos 140
SumárioCaelum
![Page 6: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/6.jpg)
158
175
191
206
11.3Invocandoométodoreescrito 142
11.4Parasabermais-MétodosMágicos 145
11.5Polimorfismo 145
11.6DuckTyping 149
11.7Exercício:HerançaePolimorfismo 150
11.8ClassesAbstratas 153
11.9Exercícios-classesabstratas 156
12HerançaMúltiplaeInterfaces12.1Problemadodiamante 160
12.2Mix-ins 163
12.3Parasabemais-Tkinter 164
12.4Exercícios-Mix-Ins 165
12.5Interfaces 167
12.6(Opcional)Exercícios-InterfaceseclassesAbstratas 170
13ExceçõeseErros13.1Exceçõesetiposdeerros 180
13.2TratandoExceções 182
13.3Levantandoexceções 183
13.4DefinirumaExceção 184
13.5Parasabermais:finally 185
13.6ÁrvoredeExceções 186
13.7Exercícios:Exceções 187
13.8OutrosErros 190
13.9Parasabermais-depuradordoPython 190
14Collections14.1UserList,UserDicteUserString 191
14.2Parasabermais 193
14.3Collectionsabc 195
14.4ConstruindoumContainer 197
14.5Sized 198
14.6Iterable 198
14.7Exercício:CriandonossaSequência 202
15Apêndice-Python2ouPython3?15.1Quaisasdiferenças? 206
15.2Afunçãoprint() 207
15.3Afunçãoinput() 207
CaelumSumário
![Page 7: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/7.jpg)
209
15.4Divisãodecimal 207
15.5Herança 208
16Apêndice-Instalação16.1InstalandooPythonnoWindows 209
16.2InstalandooPythonnoLinux 213
16.3InstalandooPythonnoMacOS 213
16.4OutrasformasdeutilizaroPython 213
Versão:24.8.11
SumárioCaelum
![Page 8: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/8.jpg)
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,quedeveser tratadaseriamente: todososexercíciossãomuito importanteseosdesafiospodemser feitosapóso términodocurso.Dequalquermaneira,recomendamosaosalunosestudarememcasaepraticarembastantecódigoevariações.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
COMOAPRENDERPYTHON
1.1OQUEÉREALMENTEIMPORTANTE?
Agoraéamelhorhoradeaprenderalgonovo
1.2SOBREOSEXERCÍCIOS
1COMOAPRENDERPYTHON 1
![Page 9: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/9.jpg)
Os exercícios do curso variam, de práticos até pesquisas na internet, ou mesmo consultas sobreassuntosavançadosemdeterminadostópicos,paraincitaracuriosidadedoaprendiznatecnologia.
Existe também, emdeterminados 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.3TIRANDODÚVIDASEINDOALÉM
2 1.3TIRANDODÚVIDASEINDOALÉM
![Page 10: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/10.jpg)
CAPÍTULO2
Python é uma linguagem de programação interpretada, orientada a objetos, de alto nível e comsemânticadinâmica.A simplicidadedoPython reduz amanutençãodeumprograma.Python suportamódulosepacotes,queencorajaaprogramaçãomodularizadaereusodecódigos.
É uma das linguagens que mais tem crescido devido sua compatibilidade (roda na maioria dossistemasoperacionais)ecapacidadedeauxiliaroutraslinguagens.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.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
Pythonfoicriadaem1990porGuidoVanRossumnoCentrodeMatemáticaStichting(CWI,vejahttp://www.cwi.nl) na Holanda como uma sucessora da linguagemABC. Guido é lembrado como oprincipalautordePython,masoutrosprogramadoresajudaramcommuitascontribuições.
AlinguagemABCfoidesenhadaparausodenãoprogramadores,maslogodeiníciomostroucertas
OQUEÉPYTHON
2.1PYTHON
VocêpodetambémfazerocursodatadessaapostilanaCaelum
2.2BREVEHISTÓRIA
2OQUEÉPYTHON 3
![Page 11: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/11.jpg)
limitaçõeserestrições.Amaiorreclamaçãodosprimeirosalunosnãoprogramadoresdessalinguagemera 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 linguageminterpretadaquantoumalinguagemcompilada.UmcompiladortraduzlinguagemPythonemlinguagemdemáquina-códigoPythonétraduzidoemumcódigointermediárioquedeveserexecutadoporumamáquinavirtualconhecidacomoPVM(PythonVirtualMachine).ÉmuitosimilaraoJava-háaindaumjeito de traduzir programas Python em bytecode Java para JVM (Java Virtual Machine) usando aimplementaçãoJython.
O interpretador faz esta 'tradução' em tempo real para código demáquina, ou seja, em tempo deexecuçã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 interpretada mas, assim como Java, passa por umprocessodecompilação.UmcódigofonteJavaéprimeiramentecompiladoparaumbytecodeedepois
2.3INTERPRETADOR
4 2.3INTERPRETADOR
![Page 12: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/12.jpg)
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éum pacote que vem com um compilador e um interpretador Python (no caso, umaMáquina VirtualPython) 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,dependedoquesedesejafazer.OPython3aindapossuialgumasdesvantagensemrelaçãoaversão2,comoosuportedebibliotecas(queémaisreduzido)epelofatodamaioriadasdistribuiçõesLinuxeoMacOSaindautilizaremaversão2comopadrãoemseus sistemas.Porém,oPython3émaismaduroemaisrecomendávelparaouso.
ExistemcasosqueexigemoPython2aoinvésdoPython3comoimplementaralgoemumambienteque o programador não controla ou quando precisa utilizar algum pacote/módulo específico que nã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?
2.4QUALVERSÃOUTILIZAR? 5
![Page 13: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/13.jpg)
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, algumas
funcionalidades 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.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Comodito acima, o Python já vem instalado nos sistemasLinux eMacOS,mas será necessáriofazer o download da última versão (Python 3.6) para acompanhar a apostila. O Python não veminstaladoporpadrãonoWindowseodownloaddeveráserfeitonositehttps://www.python.org/,alémdealgumasconfiguraçõesextras(vejaapêndicedestaapostilasobreinstalação).
ExistemoutrasimplementaçõesdalinguagemcomooJythoneoIronPython.Adiferençaéqueestasimplementações são apenas os compiladores.Obytecode gerado pelo Jython é interpretado por uma
Seuslivrosdetecnologiaparecemdoséculopassado?
2.5DOWNLOAD
2.6CPYTHON,JYTHON,IRONPYTHON?
6 2.5DOWNLOAD
![Page 14: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/14.jpg)
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.Sequisermosverobytecodepeloterminal,bastausaromó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.APEP0éaquelaquecontémoíndicedetodasaspropostasdeaprimoramentodoPythonepodeseracessadaaqui:https://www.python.org/dev/peps.
Ao longo do curso, de acordo com a aprendizagem e uso de certas funcionalidades, citaremosalgumasPEPsmaisimportantes.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Python é uma linguagem de propósito geral.Muitas vezes precisamos lidar com tarefas laterais:buscardadosemumbancodedados,lerumapáginanainternet,exibirgraficamenteosresultados,criar
2.7PEP-OQUESÃOEPRAQUESERVEM
Agoraéamelhorhoradeaprenderalgonovo
2.8ONDEUSAREOBJETIVOS
2.7PEP-OQUESÃOEPRAQUESERVEM 7
![Page 15: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/15.jpg)
planilhasetc.EPythonpossuiváriosmódulosprontospararealizaressastarefas.
PoresseeoutrosmotivosquePythonganhougrandepopularidadenacomunidadecientífica.Alémdisso,Pythonéextremamente legíveleuma linguagemexpressiva,ouseja,de fácilcompreensão.Asciências,poroutrolado,possuemraciocínioessencialmentecomplicadoeseriaumproblemaadicionalparacientistasconhecerem,alémdeseuassuntodepesquisa,assuntoscomplexosdeumprogramadecomputador como alocação de memória, gerenciamento de recursos etc. O Python faz issoautomaticamentedemaneiraeficiente,possibilitandoocientistaseconcentrarnoproblemaestudado.
Vamosparanossoprimeirocódigo!Umprogramaqueimprimeumamensagemsimples.
Paramostrarumamensagemespecífica,fazemos:
print('MinhaprimeiraaplicaçãoPython!')
Certo,masondedigitaressecomando?ComorodarumainstruçãoPython?
Iremos,primeiro,aprenderomodointerativoutilizandooterminal(LinuxeMacOS)ouopromptdecomando(Windows)pararodaroprogramaacima.Abraoterminaledigite:
dev@caelum:~$python3
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!
Oprint()éumafunçãodoPythonutilizadaparaimprimiralgumamensagemnatela.Maisdetalhes
2.9PRIMEIROPROGRAMA
2.10MODOINTERATIVO
8 2.9PRIMEIROPROGRAMA
![Page 16: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/16.jpg)
sobre 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 dedesenvolvimentonoPythonmaisutilizado,queevitadigitarumprograma longonoconsole todavezqueprecisarexecutá-lo.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
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
EditoraCasadoCódigocomlivrosdeumaformadiferente
2.11MODOSCRIPT
2.11MODOSCRIPT 9
![Page 17: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/17.jpg)
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
Entretanto,estespassosnãosãonecessários.Oprocessodecompilaçãoé feitoautomaticamenteenã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ãocompiladacomaextensão .pyc -estearquivodevesermaisnovodoqueodeextensão .py (seoarquivoexistir).OPythonvaicarregarobytecode,oquevaiaceleraroscript.Casonãoexistaaversãobytecode,oPythoncriaráoarquivobytecodeantesdeiniciaraexecuçãodoprograma.AexecuçãodeumprogramaPythonsignificaaexecuçãodeumcódigobytecodenaPythonVirtualMachine.
10 2.11MODOSCRIPT
![Page 18: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/18.jpg)
TodavezqueumscriptPythonéexecutado,umcódigobytecode écriado.SeumscriptPythonéimportadocomoummódulo,obytecodevaiarmazenarseuarquivo.pyccorrespondente.
Portanto,opassoseguintenãocriaráoarquivobytecode,já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 texto
usandoumaú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:
>>>print'MinhaprimeiraaplicaçãoPython!'Traceback(mostrecentcalllast):File"<stdin>",line1print'MinhaprimeiraaplicaçãoPython!'^SyntaxError:Missingparenthesesincallto'print'.Didyoumeanprint('MinhaprimeiraaplicaçãoPython!')?
Nãoseassustecomamensagem.Vamosentenderoqueelaquerdizer.NaprimeiralinhaapareceapalavraTracebackquesignificaalgocomo:"Oqueoprogramaestavafazendoquandoparouporque
algodeerradoaconteceu?".Éporestemotivoqueamensagemmostrecentcalllast(chamada
maisrecente)émostrada.
ATracebackfazreferênciaaumarquivo-queéonomedoarquivoPythonchamadoacimapelo
nomedestdinquepossuimétodosparaleitura,ondeoprogramalêaentradadoteclado.Oprograma
acusaqueesteerroestá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ão
2.12EXERCÍCIO:MODIFICANDOOPROGRAMA
2.13OQUEPODEDARERRADO?
Esquecerosparênteses
2.12EXERCÍCIO:MODIFICANDOOPROGRAMA 11
![Page 19: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/19.jpg)
faz a menor ideia do que esta mensagem significa é um bom começo e uma boa prática durante aaprendizagempesquisararespeitodelanainternet,assimcomodemaiserrosquepossamsurgir.
Nestecaso,éumSyntaxError,ouseja,ErrodeSintaxe -oPythonnãoentendeuoquefoi
digitado.Amensagemdizquefaltamosparênteses!Então,éfácilacharumerroquandoeleacontece.
AlgumasvezesvocêveráapalavraExceptionemumamensagemdeerro.UmaExceptionéum
problema que ocorre enquanto o código está sendo executado. Já o SyntaxError é um problema
detectadoquandooPythonverificaocódigoantesdeexecutá-lo,ouseja,emtempodecompilação.
O interpretador vai aguardar (continuar imprimindo reticências cada vez que a tecla ENTER for
apertada)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ão maiscomunsdeacontecerdoqueseimagina.Outroserrosserãoabordadosemumcapítuloespecíficodestaapostila. Neste momento, iremos aprender outros recursos que a linguagem Python oferece, e nosfamiliarizarcomsuasintaxe.
Esquecerdefecharosparênteses
Esquecerdecolocaramensagementreaspas(simplesouduplas)
12 2.13OQUEPODEDARERRADO?
![Page 20: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/20.jpg)
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
JáconheceoscursosonlineAlura?
2.13OQUEPODEDARERRADO? 13
![Page 21: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/21.jpg)
CAPÍTULO3
NestecapítulovamosconhecerostiposdabibliotecapadrãodoPython.Osprincipaistiposinternossãonúmeros,sequências,mapas,classes,objetoseexceções,masiremosfocarprimeiramentenosnúmerosesequênciasdetexto(strings).Sãoobjetosnativosdalinguagem,recursosquejávêmprontosparausoechamadosdebuilt-ins.
Nesteiníciodaaprendizagem,trabalharemoscomomodointerativo,eaofinalproduziremosumapequenaaplicaçãoemumscript.
Umvalor,comoumnúmerooutexto,éalgocomumemumprograma.Porexemplo,'Hello,World!',1,2,todossãovalores.Estesvaloressãodediferentestipos:1e2sãonúmerosinteirose'HelloWorld!'éumtexto,tambémchamadodeString.Podemosidentificarstringsporquesãodelimitadasporaspas(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çãoparainteger).
Ignore a palavra class por enquanto, teremos um capítulo especial para tratar dela. Veremos que
funçõescomotype()eprint()tambémsãotiposembutidosnoPython.
OutrotipoqueexistenoPythonsãoosnúmerosdecimaisquesãodotipofloat(pontoflutuante):
>>>type(3.2)<class'float'>
VARIÁVEISETIPOSEMBUTIDOS
3.1TIPOSEMBUTIDOS(BUILT-INS)
14 3VARIÁVEISETIPOSEMBUTIDOS
![Page 22: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/22.jpg)
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(),podemos
noscertificarqueseutipoécomplex.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Podemospedir para oPython lembrar de umvalor que queiramos utilizar emoutromomento doprograma.OPythonvaiguardarestevaloremumavariável.Variáveléumnomequefazreferênciaaumvalor. É como uma etiqueta que colocamos naquele valor e quando precisarmos usar, chamamospelonomequefoidadonaetiqueta.
Umcomandodeatribuição(osinaldeigualdade=)criaumanovavariáveleatribuiumvaloraela:
Agoraéamelhorhoradeaprenderalgonovo
3.2VARIÁVEIS
3.2VARIÁVEIS 15
![Page 23: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/23.jpg)
>>>mensagem='oi,python''oi,python'
>>>numero=55
>>>pi=3.143.14
Trêsatribuiçõesforamfeitasnestecódigo.Atribuímosavariávelmensagemumastring;avariável
numero um inteiro e a variável pi um valor aproximado do número pi. No modo interativo, o
interpretadormostraoresultadoapó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échamadodesnakecase.Variáveis tambémpodemcomeçar comunderscore (_)mas
deveserevitadoeutilizadoemcasosmaisespecíficos.
Senomearmosnossasvariáveiscomumnomeilegal,ointerpretadorvaiacusarumerrodesintaxe:
>>>1nome='python'File"<stdin>",line11nome='python'^SyntaxError:invalidsyntax
>>>numero@=10File"<stdin>",line1
3.3PARASABERMAIS:NOMESDEVARIÁVEIS
16 3.3PARASABERMAIS:NOMESDEVARIÁVEIS
![Page 24: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/24.jpg)
numero@=10^SyntaxError:invalidsyntax
>>>class='oi'File"<stdin>",line1class=oi^SyntaxError:invalidsyntax
1nomeé ilegalporquecomeçacomumnúmero,numero@ é ilegalporquecontémumcaractere
especial (o@) considerado ilegal para variáveis. Eclass é ilegal porqueclass é umapalavrachave em Python.O interpretador utiliza palavras chaves comopalavras reservadas da linguagem,comoumvocabuláriopróprio.
Pythonpossui33palavrasreservadas:
anddelfromNoneTrueaselifglobalnonlocaltryassertelseifnotwhilebreakexceptimportorwithclassFalseinpassyieldcontinuefinalyisraisedefforlambdareturn
Portanto,nãopodemosutilizaressaspalavrasparanomearnossasvariáveis.
Umainstrução(oucomando)éumaunidadedecódigoqueoPythonpodeexecutar.Porexemplo,afunçãoprint()paraimprimirumamensagemnatelaéumcomando:
>>>print("Hello,World!")Hello,World!
Quandoexecutamosumcomandonomodointerativo,ointerpretadorPythonapresentaoresultado,caso exista, deste comando. Um script contém uma sequência de instruções. Se existir mais de umcomando,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
3.4INSTRUÇÕES 17
![Page 25: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/25.jpg)
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
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Operadores são símbolos especiais que representamcálculos comoadições emultiplicações.Parafazercálculoscomnúmerosutilizamososoperadores+,-,*,/e**querepresentam,respectivamente,adição,subtração,multiplicação,divisãoepotenciação.
Umaexpressãoéumacombinaçãodevalores,variáveiseoperadores,comox+17,1+1etc.
Quando digitamos uma expressão no modo interativo, o interpretador vai calcular e imprimir oresultado:
>>>1+1
EditoraCasadoCódigocomlivrosdeumaformadiferente
3.5OPERADORESARITMÉTICOS
18 3.5OPERADORESARITMÉTICOS
![Page 26: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/26.jpg)
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é2egerarestoiguala1.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
3.6STRINGS 19
![Page 27: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/27.jpg)
concatenandostrings,ouseja,juntandoduasstrings:
>>>texto1='oi'>>>texto2='Python'texto1+texto2oiPython
Ooperador* tambémfuncionacomstrings,multiplicando seu conteúdopor um inteiro.Vamos
checaresseresultado:
>>>texto1='python'>>>texto1*3pythonpythonpython
Aomultiplicarmospor3,oPythonreplicaastring trêsvezes.Noteapresençadeumespaçoapósterminardeescreverapalavranastring.Casoomesmonãoestivessepresente,todasaspalavrasgeradasficariam"grudadas",ouseja,nãohaveriaumaseparaçãoautomáticaentreasmesmas.
Stringspossuemmuitas funcionalidadesprontaschamadasdemétodos.Ométodoupper(), por
exemplo,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çãoquecapturaaentradadevalores:a funçãoinput().Quando essa
funçãoéchamada,oprogramaparaeesperaousuáriodigitaralgumacoisa.QuandoousuárioapertaateclaENTER,oprogramaprocessaeimprimeovalordigitadoemformadestring:
>>>entrada=input()'oipyhton'
>>>print(entrada)'oipython'
Masoidealépediralgoespecíficoaousuárioedizerqualdadoqueremosreceber.Podemospassarumastringparaafunçãoinput():
>>>nome=input("digiteseunome:\n")digiteseunome:
3.7ENTRADADOUSUÁRIO
20 3.7ENTRADADOUSUÁRIO
![Page 28: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/28.jpg)
caelum
>>>print(nome)caelum
O\nnofinalrepresentaumanovalinhaeointerpretadorvaiquebrarumalinhaapósimprimira
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áriodigitar
o 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{}pelavariávelnumero.Aprincípio, podeparecer uma
alternativapior, jáqueescrevemosmaiscódigoparaconseguiromesmoresultado.Todavia,a funçãoformat() fornece mais facilidades. Suponha que o programa receba dois valores digitados pelo
usuárioeosimprimaemumaúnicamensagem:
nome=input('Digiteseunome')idade=input('Digitesuaidade')print('Seunomeé{}esuaidadeé{}'.format(nome,idade))
Vejaqueessaformafacilitaaimpressãoeformataçãodosdadosumavezquenãoquebraastringemváriaspartescomoaconcatenaçãofaz.Alémdeque,comooperador+,sempretemosquelembrardos
espaçosembrancoentreaspalavras:
print('Seunomeé'+nome+'esuaidadeé'+idade)
Nestecasoafunçãoformat()émaisrecomendadaefacilitanaimpressãodemensagensnatela.
Agoraoscriptestámelhorepodemosexecutá-lopeloterminal:
dev@caelum:~$python3programa2.py
Asaída:
digiteseunome:caelum
3.7ENTRADADOUSUÁRIO 21
![Page 29: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/29.jpg)
digitesuaidade:20Seunomeécaelumesuaidadeé20
PARASABERMAIS:AFUNÇÃOFORMAT()
Afunçãoformat() fazpartedeumconjuntodefunçõesdeformataçãodestringschamada
Formatter. Para mais detalhes, acesse a documentação:https://docs.python.org/3/library/string.html#string.Formatter.
Háoutrasfunçõesdeformataçãoeaformat()éaprincipaldelaseamaisutilizada.Comela,
podemospassarqualquertipodeparâmetro,alémdeserextremamenteútilparaformatarnúmerospassando seu format code. Por exemplo, podemos arredondar o número flutuante 245.2346paraduascasasdecimaisatravésdocódigodeformatação:.2f:
>>>x=245.2346>>>print('{:.2f}'.format(x))245.23
O:.2fdizquequeremosapenasduascasasdecimaisparaavariávelx.Nadocumentação
oficial do Python você acessa os códigos de formatação ou através da PEP 3101:https://www.python.org/dev/peps/pep-3101/.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
OPythonpossuipoucas constantes embutidas.Asmaisutilizadas sãoTrue,False eNone.Essastambémsãopalavras chavesdoPython,portantopalavras reservadasquenãopodemosutilizar comonomesdevariáveis.
JáconheceoscursosonlineAlura?
3.8CONSTANTES
22 3.8CONSTANTES
![Page 30: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/30.jpg)
TrueeFalse sãovaloresbooleanosquerepresentam,respectivamente,verdadeiroefalso.OPythontambémpossuiafunçãobool(),queretornaTruequandooargumentopassadoéverdadeiro
eretornaFalse,casocontrário.
PodemosrepresentarTrueeFalseatravésdeexpressões.Porexemplo"Onúmero1é iguala
string'1'?".VamosperguntaraoPython:
>>>1=='1'False
print(1=='1')
Ooperador==éusadoparaverificarsealgoéigualaoutro.Nãoconfundircomo=,queatribui
umvaloraumavariá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,elepodereceberqualquercoisaevairesponder
setalvaloré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
3.8CONSTANTES 23
![Page 31: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/31.jpg)
Repare que a função resulta False em strings vazias, quando um número é zero ou quando é
None.AindanãofalamosoqueoNonerepresenta.ONoneéumvalordotipoNoneType,eéusado
pararepresentaraabstençãodeumvalor-comoquandoumargumentopadrãonãoépassadoparaumafunção(queveremosemoutrocapítulo).
type(None)<class'NoneType'>
Emoutraslinguagensdeprogramação,écomumutilizarapalavraNullpararepresentaraabstençãodevalor.ParaprogramadoresmaisexperientesecomalgumconhecimentoemlinguagenscomoJavaeC#,éimportanteobservarquediferentedoNull,oNoneocupaespaçonamemória,éumobjetocomreferência.
Noexemplo acima foramutilizados trêsoperadoresdiferentesdaqueles jávistos anteriormente: o== (igual),o> (maiordoque)eo< (menor doque).Estes operadores não são aritméticos, são
conhecidosporoperadoresdecomparaçã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 funcionamdemaneira diferente.Vamosusar o
exemplodeduaslistasechecarseelassãoiguais:
>>>x=[1,2,3]>>>y=[1,2,3]>>>x==yTrue
>>>xisyFalse
24 3.8CONSTANTES
![Page 32: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/32.jpg)
Ooperador==checaseoconteúdodasvariáveissãoiguaiseseucomportamentopodevariarde
interpretador para interpretador - o exemplo acima é o comportamento padrão do CPython. Já ooperadorischecaseaebsãoomesmoobjeto.Falaremosdeobjetosemumoutrocapítulo,maséimportante ter em mente que tudo em Python é um objeto e cada objeto possui uma referência namemória.Ooperadorisvaichecarexatamentesexeysãoomesmoobjeto,ouseja,sepossuema
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.Agora,devemosmostraramensagem"Vocêacertou"casoonumero
sejaigualaochute,e"Vocêerrou"casoonumerosejadiferentedochute.Emportuguês, seria
assim:
Sechuteigualanúmero:"Vocêacertou"Sechutediferentedenúmero:"Vocêerrou"
Oumelhor:
Sechuteigualanúmero:"Vocêacertou"Senão:"Vocêerrou"
PodemostraduzirissoparacódigoPython.OPythonpossuiooperadorcondicionalpararepresentarapalavrasequeéoifeapalavrasenãoqueéoelse.Asintaxeficaria:
ifchute==numero:print('Vocêacertou')else:print('Vocêerrou')
EstecódigoaindanãofuncionaporqueoPythonentendeasinstruçõesifeelsecomoblocose
osblocosdevemseguirumaindentação.Comoprint('Vocêacertou')éainstruçãoquedeveserexecutadacasoaverificaçãodoif sejaverdadeira,devemos terumrecuoparaadireitaemquatros
espaços:
ifchute==numero:print('Vocêacertou')else:print('Vocêerrou')
Casocontrário,ointerpretadorvaiacusarerrodesintaxe.Dessamaneira,ocódigoficamaislegível
3.9COMANDOIF
3.9COMANDOIF 25
![Page 33: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/33.jpg)
eoqueemoutraslinguagenséumaescolhadoprogramador,oPythonteobrigaafazerforçando,destamaneira, a organizar o código.Tudoque estiver no bloco da primeira condição (doif) deve estar
indentado,ouseja,recuadoparadireita.Assimcomoasinstruçõesqueestiveremnoblocodoelse.
Nofim,nossoprograma,quesalvaremosemumarquivochamadoadivinhacao.pyfica:
numero=42chute=input('Digiteumnúmero:')
ifchute==numero:print('Vocêacertou')else:print('Vocêerrou')
Eexecutamosnoterminal:
dev@caelum:~$python3adivinhacao.pyDigiteumnúmero:25Vocêerrou
Notequeacondiçãodeumifdeveserumbooleano,ouseja,TrueouFalse.Passamosaexpressãochute==numero que vai checar se ela é verdadeira ou não.Caso seja verdadeira, vai executar o
código dentro do bloco do if, senão, vai executar o código dentro do else. Agora, vamos chutar onú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ésdafunçãotype()que retornao tipodavariável.Vamos testar issono
terminal:
>>>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) é diferente de42
3.10CONVERTENDOUMASTRINGPARAINTEIRO
26 3.10CONVERTENDOUMASTRINGPARAINTEIRO
![Page 34: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/34.jpg)
(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'>>>>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.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
Podemosmelhoraraindamaisojogo:casoochutenãosejaigualaonúmerosecreto,podemosdarumapistaparaousuárioseelefoimaioroumenordoqueochuteinicial.Ouseja,devemosacrescentaressetratamentocasoousuárioerreochute:
Sechute=número:"Vocêacertou!"Senão:Sechutemaiordoquenúmero_secreto:"Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto"
VocêpodetambémfazerocursodatadessaapostilanaCaelum
3.11OCOMANDOELIF
3.11OCOMANDOELIF 27
![Page 35: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/35.jpg)
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')else:print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')
Masnestecasopodemosfazerumelsecomumacondiçãodeentrada,oelif.Vamosutilizá-lo
paradeixarocó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ção para
umavariável:
acertou=chute==numero_secreto
if(acertou):print('Vocêacertou!')
#restantedocódigo
Avariávelacertouguardaumaexpressãoe,portantoédo tipobooleano epodemosusarcomocondiçãonocomandoif.Agoraacondiçãoifficaumpoucomaisclara.Vamosfazeramesmacoisa
paraasoutrasduascondiçõ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
3.12EXERCÍCIOS-JOGODAADIVINHAÇÃO
28 3.12EXERCÍCIOS-JOGODAADIVINHAÇÃO
![Page 36: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/36.jpg)
|_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. 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.Seosvaloresforemiguais,mostre
umamensagemdeacerto,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 chute 42não funciona comoesperado.Esquecemosde converter o chute digitadopelousuárioparaumnúmero inteiro.Modifiqueocódigoeutilizea funçãoint()para receberaentradado
usuário:
chute=int(input('Digiteoseunúmero:'))
8. Rodeocódigonovamentecomaentradaiguala42evejaqueagorafuncionacomoesperado.
3.12EXERCÍCIOS-JOGODAADIVINHAÇÃO 29
![Page 37: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/37.jpg)
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')
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éumjogo de adivinhação.A primeira ideia é repetir o código, desde a função input() até o bloco do
elif. Ou seja, para cada nova tentativa que quisermos dar ao usuário, copiaríamos esse código
novamente.
Sóque copiar código sempre éumamáprática, queremos escrevero código apenasumavez.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!')
3.13COMANDOWHILE
30 3.13COMANDOWHILE
![Page 38: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/38.jpg)
Comoditoanteriormente,oPythonnãoentendeportuguêseassimcomooifeletemumcomando
quesubstituiráapalavraenquantodonossoexemplo.Owhile é essecomandoque, assimcomooif,recebeumacondição.Adiferençaéqueoif,casoacondiçãosejaverdadeira,executaapenas
umavezocódigodeseubloco,jáowhileexecutaenquantoacondiçãoforverdadeira,porexemplo:
x=5enquantoxformaiordoque1,faça:imprime(x)x=x-1
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.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
3.13COMANDOWHILE 31
![Page 39: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/39.jpg)
1. Daremosaousuáriodo jogoumnúmeromáximode tentativas.Abraoarquivoadivinhacao.py napasta jogos e atribua a variável total_de_tentativas com valor 3, e acrescente o bloco docomandowhile:
numero_secreto=42total_de_tentativas=3
while(aindahátotal_de_tentativas):#executaocódigo
2. Restaagoraaexpressãoaindahá.Aideiaéqueousuáriotenha3tentativas,representadanocódigopelavariáveltotal_de_tentativas.A cada rodada subtraímos1dovalor dessavariável, até o
valor chegar a 0, que é quando devemos sair do while. Logo, vamos executá-lo enquanto a
variá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çacomo
valor1:
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)
3.14EXERCÍCIOS-JOGOCOMWHILE
32 3.14EXERCÍCIOS-JOGOCOMWHILE
![Page 40: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/40.jpg)
#restantedocódigoaqui
5. Eparaavariáveltotal_de_tentativascontinuarcomovalor3,nãovamosmaissubtrair1do
seuvalor,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)
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á como
valor3,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ção da
mensagemdeacerto:
if(acertou):print('Vocêacertou!')breakelif(maior):
3.14EXERCÍCIOS-JOGOCOMWHILE 33
![Page 41: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/41.jpg)
#restantedocódigo
8. Testeoprogramaevejasetudoestáfuncionandocomooesperado.
Ainda no código do jogo da adivinhação, implementamos o loop while, no qual temos uma
variávelrodadaquecomeçacomovalor1,eéincrementadadentrodoloop,queporsuaveztemuma
condiçãodeentrada,queéarodadasermenorouigualaototaldetentativas,queé3.
Ouseja,arodadatemumvalorinicial,queé1,evaiaté3.Fazemosumlaçocomeçandocomum
valorinicial,atéumvalorfinal,sempreincrementandoessevaloracadaiteração.Masseesquecermosdeincrementararodada,entramosemumloopinfinito.
Emcasos comoesse, existe umoutro loop que simplifica essa ideia de começar comumvalor eincrementá-loatéchegaremumvalorfinal:oloopfor.
Paraentenderoloop,oulaçofor,podemosiratéoconsoledoPythonparaveroseufuncionamento.Aideiaédefinirmosovalorinicialeovalorfinal,queoloopoincrementaautomaticamente.Paraistoutilizamosafunçãoembutidarange(),passando-osporparâmetro,definindoassimasériedevalores.
Asintaxeéaseguinte:
Paravariávelemumasériedevalores:Façaalgo
Isso,emPython,podeficarassim:
forrodadainrange(1,10):
Orange(1,10)vaigerarointervalodenúmerosinteirosde1a9.Naprimeiraiteração,ovalor
davariávelrodadaserá1,depois2eatéchegaraovalorfinaldafunçãorange()menos1,istoé,o
segundoparâmetrodafunçãonãoéinclusivo.Noexemploacima,asériedevaloreséde1a9.PodemosconfirmarissoimprimindoovalordavariávelrodadanoconsoledoPython:
>>>forrodadainrange(1,10):...print(rodada)...123456789
Comafunçãorange(),podemosdefinirumstep(umpasso),queéointervaloentreoselementos.
Porpadrão,osteptemvaloriguala1,maspodemosalterarestevalorpassandoumterceiroparâmetro
3.15COMANDOFOR
34 3.15COMANDOFOR
![Page 42: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/42.jpg)
paraafunção:
>>>forrodadainrange(1,10,2):...print(rodada)...13579
Vejaqueointervaloentrecadaelementodasérieagoraé2,acadaiteraçãoolaçopuladoispassos(incrementa2).Masnãonecessariamenteprecisamosusarafunçãorange()nofor,podemospassar
osvaloresdasequênciamanualmenteconseguindoomesmoresultado:
>>>forrodadain[1,2,3,4,5]:...print(rodada)...12345
Tantoowhilequantooforpodemserusadosnojogo.Conseguiremosomesmoresultado,mas
o código ficamais verboso comowhile, alémde corrermoso riscode esquecer de incrementar a
rodada(rodada=rodada+1)enossocódigoentraremumloopinfinito.Nestecasos,épreferível
utilizarocomandofor.
1. Substituaocomandowhilepeloforcomeçandono1eindoatéototal_de_tentativas.Não
esqueç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!')breakelif(maior):print('Vocêerrou!Oseuchutefoimaiorqueonúmerosecreto')elif(menor):print('Vocêerrou!Oseuchutefoimenorqueonúmerosecreto')
3.16EXERCÍCIOS-UTILIZANDOOFORNOJOGO
3.16EXERCÍCIOS-UTILIZANDOOFORNOJOGO 35
![Page 43: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/43.jpg)
print('Fimdojogo!')
2. Éimportantesaberqueofornãoéobrigadoaterparênteses.Podemostestareverqueoprograma
dá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çapara
ousuárioescolheremqualníveleledeseja jogar.Onívelémensuráveldeacordocomo totaldetentativas:nível1(tentativas=20),nível2(tentativas=10)enível3(tentativas=5).
5. (opcional) Acrescente um total de pontos ao jogador que deve iniciar com 1000 e a cada chuteerradodevesersubtraídodototaldepontosumvalorquecorrespondeadiferençaentreochuteeonúmerosecreto.Paraesteexercíciovocêvaiprecisardafunçãoabs().Vejanadocumentaçãodo
Pythoncomoelafunciona.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Agoraéamelhorhoradeaprenderalgonovo
36 3.16EXERCÍCIOS-UTILIZANDOOFORNOJOGO
![Page 44: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/44.jpg)
CAPÍTULO4
Aoadentrarmosemcódigosquerequeremmaiorcomplexidade,vemosquenemsempreomodoscriptde execução de códigos em Python não conseguirá atender todas as nossas necessidades durante acriaçãodenossasaplicações.Dessaforma,seránecessárionosaprofundarmosaescrevernossocódigoemarquivosexternos,demaneiraaexecutartodoocódigodeumavezdemaneiramaisestruturadaeorganizada.
Aoiniciaroprimeirocontatocomprogramação,umadasprincipaisdúvidasde iniciantesé:"qualferramenta vou utilizar para escrever código?". A maioria dos códigos das principais linguagens deprogramaçãopermitemdesenvolveremumarquivoutilizandoumeditordetextocomum.
Algunseditoresde textopossuemferramentasmais 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ítulo,apresentaremosaIDEPycharmesuasprincipaisferramentas.
INTRODUÇÃOAOPYCHARM
4.1IDE
4INTRODUÇÃOAOPYCHARM 37
![Page 45: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/45.jpg)
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
O Pycharm é multiplataforma com versões para Windows, MacOS e Linux. O PyCharm édesenvolvidopelaempresaJetBrainseforneceanálisedecódigo,depuradorgráfico,autocompletamentodecódigoecapacidadesdenavegaçãoquefacilitamaescritadecódigo.
IDE's foram desenvolvidas para criar códigomais rapidamente e commaior eficiê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.
EditoraCasadoCódigocomlivrosdeumaformadiferente
4.2PYCHARM
38 4.2PYCHARM
![Page 46: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/46.jpg)
OUTRASIDES
UmanovatendênciadeIDE'sparadesenvolvimentoemPython,especialmenteparaaáreadeDataScience,envolvemautilizaçãodeambientescomputacionaisdiretamenteutilizadosnaweb,possibilitandoumainteraçãomaisdinâmicaecolaborativaentreosseusparceirosdeequipe.Sendomuitas vezes definidos como Notebooks, os mesmos possibilitam a execução de scripts em
Pythonemblocosseparadosdecódigo,facilitandoavisualizaçãoedocumentaçãodoseucódigo,eobservandoosresultadosemtemporealcommaioreficácia.UmdosexemplosmaisfamososéoJupyterNotebook,quepossuisuporteadiversasbibliotecaseédefácilinstalaçãodoambientenasuamáquina,sendoutilizadopordiversasempresasnoramodedadosatéhoje.
OutraIDEqueestácadavezmaisdisseminadanaatualidadeparaageraçãodecódigosPythonéoGoogleColaboratory,quepossibilitaacriaçãodeNotebooksinterativosdiretamenteatravés
desuacontaGoogle.UmadasmaioresvantagensdoColaboratoryaoutrasIDE'séquetudoéfeitoatravés da nuvem, desde o armazenamento dos dados dentro da sua conta Google até oprocessamentodedadosfeitopelaGPUfornecidapelamesma.
Porfim,umoutroambientebastanteconsolidadonacomunidadePythonnosúltimosanoséoIDLE, que possui bem menos recursos do que o PyCharm mas ainda é bastante utilizado pordiversosusuários.
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/.
4.3DOWNLOADEINSTALAÇÃODOPYCHARM
4.3DOWNLOADEINSTALAÇÃODOPYCHARM 39
![Page 47: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/47.jpg)
Existem duas versões, aProfessional e aCommmunity. A versão paga (aProfessional) possuifuncionalidadesextrascomosuporteparadesenvolvimentodeaplicaçõeswebeintegraçãocombancode dados. Para o curso, a versãoCommunity 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,uma janelachamadaCreateProject aparecerá.Énela
quedefinimostodasasconfiguraçõesnecessárias.
4.4CRIANDOUMPROJETO
40 4.4CRIANDOUMPROJETO
![Page 48: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/48.jpg)
Podemoscriarumnovoprojetoaqualquermomento.Parafazerisso,bastaclicaremFile->New
ProjectnomenusuperiordajanelaprincipaldoPyCharm.
Primeiro,especificamosonomedoprojeto-nonossocasoseráapenasjogos.NotequeoPyCharmsugereumlocalpadrãoparasalvaroprojeto.VocêpodeaceitarestelocalouconfigurarmanualmentenocampoLocation.Vamosoptarpelocaminhopadrão.Aofazerisso,aIDEvaicriarumapastachamada
PyCharmProjectsnasuapastahome.
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 com outras bibliotecas instaladas em seu computador. Por fim,clicamosemCreateenossoprojetoécriado.
Nosso projeto tem uma estrutura padrão. A pasta venv é o ambiente isolado do sistema
operacional.Nela contémaversãodo interpretadorPythonque selecionamosna criaçãodoprojeto eseus módulos embutidos (builtins) - você pode checar isso na pasta lib . A qualquer momento
podemosincluirnovasbibliotecasaoprojeto.
Porfim,vamosimportaronossoúltimocódigogeradonocapítuloanterior,oadivinhacao.py.Vá
naabaFile->Openeselecioneoarquivoparaoseuprojeto.
4.4CRIANDOUMPROJETO 41
![Page 49: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/49.jpg)
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Agoravamostestarnossaclasse.OPycharmpossuiumconsoledoPythonembutido,paraabrí-lováemTools->PythonConsole.Vocêvainotarquea janeladoconsolevaiabrirabaixodoarquivo
adivinhacao.py:
Reparequeoconsoletambémpossuiaferramentadeautocomplete.Parareiniciá-lobastaclicarnoprimeiroíconedomenuesquerdodoconsole.
AIDEtambémpermiteabriroterminaleusaromodointerativoparatestes.OatalhoparaabriroterminaléALT+F12.OPythonConsoledoPycharmémaisaconselhávelpara issoeo terminalé
maisutilizadoparainstalarnovaslibsaoseuprojeto.
ParaexecutarváemRun->Runoucliquecomobotãodireitodomousenointeriordoarquivo
adivinhacaoeescolhaaopçãoRun'adivinhacao'.Ouainda,digiteoatalhoCTRL+Shift+F10que
vaiteromesmoefeito.Depoisdeterrodadopelaprimeiravez,paravocêrodarnovamentebastaclicarnoíconedeumapequenasetaverdenomenusuperiordaIDE:
JáconheceoscursosonlineAlura?
4.5EXECUTANDOCÓDIGO
42 4.5EXECUTANDOCÓDIGO
![Page 50: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/50.jpg)
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.
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
4.6PRINCIPAISATALHOS
4.6PRINCIPAISATALHOS 43
![Page 51: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/51.jpg)
CAPÍTULO5
Nocapítulopassadocriamosojogodaadivinhação,agoravamoscriarojogodaForca.Vamoscomeçarcomos conhecimentos que temos até aqui para estruturarmos o nosso jogo.Vamos criar um arquivochamadoforca.pynapastajogos:
|_home|_jogos|_adivinhacao.py|_forca.py
Comonojogodaadivinhação,devemosadivinharumapalavrasecreta,entãonadamais justoquedefini-laemumavariável.Porenquanto,apalavraseráfixa,comovalorbanana:
print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')
palavra_secreta='banana'
print('Fimdojogo')
Maisàfrentedeixaremosessapalavrasecretamaisdinâmica.
Como estamos tratando de um jogo da forca, o usuário deve acertar uma palavra 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áveisbooleanasenforcoueacertouparaguardaresta informaçãoeo jogo
continuaráatéumadelasforTrue;paratalacrescentamosumlaçowhile:
acertou=Falseenforcou=False
while(notacertouandnotenforcou):print('Jogando...')
Ousuáriodojogotambémvaichutarletras.Alémdisso,seochuteforigualaumaletracontidanapalavra_secreta,querdizerqueousuárioencontrouumaletra.Podemosutilizarumlaçoforpara
tratarisso,assimcomofizemosnojogodaadivinhaçãoparaapresentarastentativaserodadas:
while(notacertouandnoterrou):chute=input('Qualletra?')
posicao=0forletrainpalavra_secreta:if(chute==letra):print('Encontreialetra{}naposição{}'.format(letra,posicao))
ESTRUTURADEDADOS
44 5ESTRUTURADEDADOS
![Page 52: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/52.jpg)
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)éumtipoembutido
noPythonquepossuialgumasfunçõ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,posicao))
Dessamaneira, o jogador pode chutar tanto 'a' como 'A' queo tratamentodoif vai considerar
todascomomaiúsculas.
Agorapodemostestarnovamentecomchuteiguala'A'(ou'a')evemosoprogramafuncionarcomooesperado:
************************************BemvindoaojogodaForca!************************************Qualletra?AEncontreialetraanaposição1Encontreialetraanaposição3Encontreialetraanaposição5Jogando...Qualletra?
Atualmente, jádizemosao jogadoremqueposiçãoa letraqueelechutouestánapalavra secreta,casoaletraexistanapalavra.Masemumjogorealdeforca,ojogadorvêquantasletrashánapalavra
5ESTRUTURADEDADOS 45
![Page 53: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/53.jpg)
secreta.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'>
Assimcomoastring,list tambéméuma sequênciadedados.Podemosver suadocumentação
atravé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 fazercomuma lista.Podemos,porexemplo,verificaro seuvalormínimocommineoseumáximocommax.Nossalistaaindaestávazia,masjápodemosiniciá-lacomalguns
valoreseutilizarmosessasfunçõesparaverificarmosseusvaloresmá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
46 5ESTRUTURADEDADOS
![Page 54: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/54.jpg)
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 um
elementodedeterminadaposiçã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.Em
casoafirmativo,adicionaaletranaposiçãocorretaeincrementaaposicaoapósoblocodoif.
Aoexecutarojogoechutaralgumasletras,temos:
5ESTRUTURADEDADOS 47
![Page 55: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/55.jpg)
$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 jogador amensagemde abertura, similar aoque foi feitonojogodaadivinhação:
print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')
3. Crieavariávelpalavra_secreta,queseráiniciadacomovalor'banana',eumalistapararepresentarasletrasacertadas.
palavra_secreta='banana'letras_acertadas=['_','_','_','_','_','_']
4. Crieasvariáveisbooleanasacertoueerrou,quevamosutilizarnolaçowhile.Alémdisso,
crieavariávelerros,quearmazenaráonumerodeerrosdousuário:
acertou=Falseenforcou=Falseerros=0
while(notacertouandnotenforcou):#código
5.1EXERCÍCIOS:JOGODAFORCA
48 5.1EXERCÍCIOS:JOGODAFORCA
![Page 56: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/56.jpg)
5. Crieavariávelchute,quevaiguardarentradadousuário.
while(notacertouandnotenforcou):chute=input('Qualletra?')
6. Dentrodowhile,crieumloopforparachecarsealetraexistenapalavrasecreta.Seochutefor
igualaletradigitadapelojogador,adicionealetranalistaletras_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ção
upperdestrings.Atualizetambémavariávelchute.
if(chute.upper()==letra.upper()):
8. Agoraprecisamosincrementaravariávelerroscasoojogadornãoacertealetra.Seochuteéumaletradentrodepalavra_secreta,querdizerqueojogadoracertou,ecasocontrário,incrementamosavariávelerros.Paraisso,teremosmaisumblocoif/else:
if(chuteinpalavra_secreta):posicao=0forletrainpalavra_secreta:if(chute.upper()==letra.upper()):letras_acertadas[posicao]=letraposicao+=1else:erros+=1
9. Atualizeavariávelacertou.Setodasasletrasaindanãoforamacertadas,querdizerqueousuário
aindanãofinalizouojogo,ouseja, letrasacertasaindacontémespaçosvazios('').Dentrodo loopwhile,apósocomandofor,vamosatualizaravariávelacertoueutilizarooperadornotin:
acertou='_'notinletras_acertadas.
Podemoslerocódigoacimacomo"'_'nãoestácontidoemletras_acertadas".
10. Vamostambématualizaravariávelenforcou.Vamosconsiderarqueseojogadorerrar7vezesele
perdeojogo.Comoavariável iniciacom0(zero),querdizerquequandoelafor iguala6,eleseenforca.Atualizeavariáveldentrodoloopwhileapósavariávelacertou:
acertou="_"notinletras_acertadasenforcou=erros==6
11. Para que o jogador acompanhe o resultado a cada chute que ele der, ao final do laço while,
imprimatambémalistaletras_acertadasparaqueelevejacomoeleestáindonojogo:
5.1EXERCÍCIOS:JOGODAFORCA 49
![Page 57: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/57.jpg)
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"casotenhacometido6erros.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=posicao+1else:erros+=1
enforcou=erros==6acertou='_'notinletras_acertadasprint(letras_acertadas)
50 5.1EXERCÍCIOS:JOGODAFORCA
![Page 58: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/58.jpg)
if(acertou):print('Vocêganhou!!')else:print('Vocêperdeu!!')print('Fimdojogo')
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
Desenvolvemosumnovojogoeconhecemosumanovaestrutura,aslistas.Umalistaédenominadapor uma sequência de valores, e o Python possui outros tipos de dados que também são sequências.Nestemomento,conheceremosumpoucodecadaumadelas.
Sequênciassãocontainers,umtipodedadoquecontémoutrosdados.Existemtrêstiposbásicosdesequência:list (lista) , tuple (tupla) e range (objeto de intervalo). Outro tipo de sequência
famosoquejávimossãoasstringsquesãosequênciasdetexto.
Sequências podem ser mutáveis ou imutáveis. Sequências imutáveis não podem ter seus valoresmodificados. Tuplas, strings e ranges são sequências imutáveis, enquanto listas são sequê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
VocêpodetambémfazerocursodatadessaapostilanaCaelum
5.2SEQUÊNCIAS
5.2SEQUÊNCIAS 51
![Page 59: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/59.jpg)
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#']
O primeiro exemplo é uma lista com 4 inteiros, o segundo é uma lista contendo três strings.Contudo,listasnãoprecisamconterelementosdemesmotipo.Podemosterlistasheterogêneas:
>>>lista=[1,2,'python',3.5,'java']>>>lista[1,2,'python',3.5,'java']
Nossalistapossuielementosdotipoint,floatestr.Sequeremosselecionarumelemento
específico,utilizamosooperador[]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],apareceoerroIndexError,dizendoque
alistaexcedeuseulimitejáquenãoháumquintoelemento(índice4).
OPythonpermitepassarvaloresnegativoscomoíndicequevaidevolverovalornaquelaposiçãode
52 5.2SEQUÊNCIAS
![Page 60: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/60.jpg)
formareversa:
>>>lista=[1,2,3,4]>>>lista[-1]4>>>lista[-2]3
Também é possível usar a função list() para criar uma lista passando um tipo que pode ser
iterávelcomoumastring:
>>>lista=list('python')>>>lista['p','y','t','h','o','n']
Listassãomuitoúteis,porexemplo:
meses=['Janeiro','Fevereiro','Março','Abril','Maio','Junho','Julho','Agosto','Setembro','Outubro','Novembro','Dezembro']n=1
while(n<4):mes=int(input("Escolhaummês(1-12):"))if1<=mes<13:print('Omêsé{}'.format(meses[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 imprimimosna telaomêsescolhido(mes[mes-1]) indexadoalistaapartirdozero.Usamosumlaçowhilequefaznossoprogramaentraremloopeserrodado3
vezes.
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:
5.2SEQUÊNCIAS 53
![Page 61: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/61.jpg)
>>>lista[2:][5,7,11]
Ouutilizamosíndicesnegativos:
>>>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. As listas podem ser utilizadas em conjunto com uma função chamada append(), que
adicionaumdadonalista:
>>>lista=[]>>>lista.append('zero')>>>lista.append('um')>>>lista['zero','um']
Afunçãoappend()sóconsegueinserirumelementoporvez.Sequisermosinserirmaiselementos,
podemossomaroumultiplicarlistas,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 pois listas são sequênciasmutáveis, ou seja, conseguimos adicionar, remover emodificarseuselementos.Paraimprimiroconteúdodeumalista,podemosutilizarocomandofor:
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)
54 5.2SEQUÊNCIAS
![Page 62: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/62.jpg)
<class'tuple'>
Podemosomitirosparênteseseinseriroselementosseparadosporvírgula:
>>>dias='domingo','segunda','terça','quarta','quinta','sexta','sabado'>>>type(dias)>>><class'tuple'>
Noteque,naverdade,éavírgulaquefazumatupla,nãoosparênteses.Osparêntesessãoopcionais,excetonocasodatuplavazia,ouquandosãonecessáriosparaevitarambiguidadesintá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êneadeelementos.Jáaslistassão mutáveis, e seus elementos geralmente são homogêneos, sendo acessados pela iteração da lista,emboranãosejaumaregra.
5.2SEQUÊNCIAS 55
![Page 63: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/63.jpg)
Quandoénecessárioarmazenarumacoleçãodedadosquenãopossaseralterada,prefirausartuplasalistas.Outravantageméquetuplaspodemserusadascomochavesdedicionários,quediscutiremosnasseçõesadiante.
TuplassãofrequentementeusadasemprogramasPython.Umusobastantecomumsãoemfunçõesquerecebemmúltiplosvalores.Astuplasimplementamtodasasoperaçõesdesequênciacomuns.
Range
Orangeéumtipodesequênciaimutáveldenúmeros,sendocomumenteusadoparaloopingdeumnú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 imprimeoselementosdasequência,eleapenasarmazenaseu inícioeseufinal.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).
OPythontambémincluiumtipodedadosparaconjuntos.Umconjunto,diferentedeumasequência,
5.3CONJUNTOS
56 5.3CONJUNTOS
![Page 64: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/64.jpg)
éumacoleçãonãoordenadaequenãoadmiteelementosduplicados.
Chavesouafunçãoset()podemserusadosparacriarconjuntos.
>>>frutas={'laranja','banana','uva','pera','laranja','uva','abacate'}>>>frutas>>>{'uva','abacate','pera','banana','laranja'}>>>type(frutas)<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 cria um
dicionáriovazio,umaestruturadedadosquediscutiremosnapróximaseção.
>>>a=set()>>>aset()>>>b={}>>>b{}>>>type(a)<class'set'>>>>type(b)<class'dict'>
Vimosquelist,tuple,rangeestrsãosequênciasordenadasdeobjetos,esetssãocoleções
deelementosnãoordenados.DicionárioéoutraestruturadedadosemPythoneseuselementos,sendoestruturadas de forma não ordenada assim como os conjuntos. Ainda assim, essa não é a principaldiferença com as listas. Os dicionários são estruturas poderosas e muito utilizadas, já que podemosacessar seus elementos através de chaves e não por sua posição. Em outras linguagens, este tipo éconhecidocomo"matrizesassociativas".
Qualquer chave de um dicionário é associada (ou mapeada) a um valor. Os valores podem ser
5.4DICIONÁRIOS
5.4DICIONÁRIOS 57
![Page 65: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/65.jpg)
qualquertipodedadodoPython.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'
Osdicionáriossãodelimitadosporchaves({})esuaschaves('nome','idade'e'cidade')poraspas.Jáosvalorespodemserdequalquertipo.Noexemploacima,temosduasstringseumint.
Oqueseráqueacontecesetentarmosacessarseuprimeiroelemento?
>>>pessoa[0]Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>KeyError:0
Nãoépossívelacessarumelementodeumdicionárioporumíndicecomonalista.Devemosacessá-losporsuachave:
>>>pessoa['nome']'João'>>>pessoa['idade']25
Seprecisarmosadicionaralgumelemento,comoporexemplo,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'])
Notequeas chavesdeumdicionárionãopodemser iguaisparanãocausar 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:
58 5.4DICIONÁRIOS
![Page 66: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/66.jpg)
>>>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}
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Vamostentarresolveralgunsdesafios.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
1. Primeiramente,vamosgerarumnovoarquivoparaestecódigo,chamadolista.py.Crieoarquivo
noPycharmdentrodomesmoprojeto'jogos'criadonocapítuloanterior.
2. Vamoscomeçargerandoumloopparapercorreralista.Utilizamosumforjuntocomumrange
parapercorrercadaíndicedanossalista:
lista=[12,-2,4,8,29,45,78,36,-17,2,12,12,3,3,-52]
forindexinrange(0,len(lista)):
Seuslivrosdetecnologiaparecemdoséculopassado?
5.5EXERCÍCIOS:ESTRUTURADEDADOS
5.5EXERCÍCIOS:ESTRUTURADEDADOS 59
![Page 67: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/67.jpg)
3. Agora,vamos resolvero itema.Definaumavariável forado seu for chamadamaiorValor e a
igualeaoprimeiroelementonalista.Dentrodoseufor,percorraoselementosdentrodeumif
parasubstituirovalorencontradocasosejamaiordoqueomesmo:
lista=[12,-2,4,8,29,45,78,36,-17,2,12,12,3,3,-52]
maiorValor=lista[0]
forindexinrange(0,len(lista)):#Maiorvalorif(maiorValor<lista[index]):maiorValor=lista[index]
print(maiorValor)
4. Pararesolveroitemb,bastaseguiramesmaideiadoexemploanterior.Crieumoutroifabaixo
doquevocêcriounopassoanterior,apenasmudandoooperadordacondição:
menorValor=lista[0]
forindexinrange(0,len(lista)):#...seucódigoaqui#Menorvalorif(menorValor>lista[index]):menorValor=lista[index]
print(menorValor)
5. Pararesolveroitemc,bastadefinirumalista,ecasoovaloratualdalistacommódulo2retorne0,
eleéadicionadonamesma:
listaPares=[]
forindexinrange(0,len(lista)):#...seucódigoaqui#Numerosparesif(lista[index]%2==0):listaPares.append(lista[index])print(listaPares)
6. Pararesolveroitemd,éprecisoverificarseoitematualdalistaaserpercorridacoincidecomo
elementoemseuprimeiroíndice:
ocorrenciasItem1=0
forindexinrange(0,len(lista)):#...seucódigoaqui#Numerodeocorrenciasif(lista[index]==lista[0]):ocorrenciasItem1=ocorrenciasItem1+1
print(ocorrenciasItem1)
7. Aresoluçãodoitemerequeraimplementaçãodentroeforadofor.Dentrodofor,somecada
um dos elementos em uma variável única. Após o loop, divida o valor obtido pelo total de
elementosnasualista:
60 5.5EXERCÍCIOS:ESTRUTURADEDADOS
![Page 68: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/68.jpg)
mediaElementos=0
forindexinrange(0,len(lista)):#...seucódigoaqui#MediadeelementosmediaElementos=+mediaElementos+lista[index]mediaElementos=mediaElementos/len(lista)
print(mediaElementos)
8. Por fim, para resolver o itemf, faça a somade todosos númerosnegativos somando todosos
valoresquesãomenoresque0:
somaNegativos=0
forindexinrange(0,len(lista)):#...seucódigoaqui#Somadosnúmerosnegativosif(lista[index]<0):somaNegativos=somaNegativos+lista[index]
print(somaNegativos)
9. Tenteimprimirtodasestascondiçõesnoseuloopevejaoresultado.Oseuresultadodeveráestar
similara:
```python
lista=[12,-2,4,8,29,45,78,36,-17,2,12,12,3,3,-52]
#declarandonossasvariáveismaiorValor=lista[0]menorValor=lista[0]listaPares=[]ocorrenciasItem1=0mediaElementos=0somaNegativos=0
#iniciandoonossoloop:forindexinrange(0,len(lista)):
#Maiorvalorif(maiorValor<lista[index]):maiorValor=lista[index]
#Menorvalorif(menorValor>lista[index]):menorValor=lista[index]
#Numerosparesif(lista[index]%2==0):listaPares.append(lista[index])
#Numerodeocorrênciasif(lista[index]==lista[0]):ocorrenciasItem1=ocorrenciasItem1+1
#Somadosnúmerosnegativosif(lista[index]<0):somaNegativos=somaNegativos+lista[index]
5.5EXERCÍCIOS:ESTRUTURADEDADOS 61
![Page 69: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/69.jpg)
#MediadosomatóriodoselementosmediaElementos=+mediaElementos+lista[index]
mediaElementos=mediaElementos/len(lista)
print("Maiorvalor:"+str(maiorValor))print("Menorvalor:"+str(menorValor))print("Listadeelementospares:"+str(listaPares))print("Númerodeocorrênciasdoprimeiroitem:"+str(ocorrenciasItem1))print("Médiadoselementos:"+str(mediaElementos))print("Somatóriodosvaloresnegativos:"+str(somaNegativos))```
62 5.5EXERCÍCIOS:ESTRUTURADEDADOS
![Page 70: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/70.jpg)
CAPÍTULO6
Objetivos:
entenderoconceitodefunçãosabereusaralgumasfunçõesembutidasdalinguagemcriarumafunção
Oconceitodefunçãoéumdosmaisimportantesnamatemática.Emcomputação,umafunçãoéumasequênciadeinstruçõesquecomputaumoumaisresultadosquechamamosdeparâmetros.Nocapítuloanterior,utilizamosalgumasfunçõesjáprontasdoPython,comooprint(),input(),format()etype().
Tambémpodemoscriarnossasprópriasfunções.Porexemplo,quandoqueremoscalculararazãodoespaçopelotempo,podemosdefinirumafunçã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
OPythonpermitedefinirmosfunçõescomoessadavelocidademédia.Asintaxeémuitoparecidacomadamatemática.ParadefinirmosumafunçãonoPython,utilizamosocomandodef:
defvelocidade(espaco,tempo):pass
Logoapósodefvemonomedafunção,eentreparêntesesvêmosseusparâmetros.Umafunção
tambémtemumescopoeumblocodeinstruçõesondecolocamososcálculos,ondeestesdevemseguiraidentaçãopadrãodoPython(4espaçosadireita).
Comonossafunçãoaindanãofaznada,utilizamosapalavrachavepassparadizeraointerpretadorquedefiniremososcálculosdepois.Apalavrapassnãoéusadaapenasemfunções,podemosusarem
FUNÇÕES
6.1OQUEÉUMAFUNÇÃO?
6FUNÇÕES 63
![Page 71: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/71.jpg)
qualquerblocodecomandoscomonasinstruçõ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 para
imprimi-lonatela.Vamostestarnossafunção:
velocidade(100,20)
#velocidade:5m/s
Demaneirageral,umafunçãoéumestruturaparaagruparumconjuntodeinstruçõesquepodemserreutilizadas.Agoraqualquerpartedonossoprogramapodechamarafunçãovelocidadequandoprecisarcalcularavelocidademé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
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Umconjuntodeparâmetrosconsisteemumalistacomnenhumoumaiselementosquepodemserobrigatórios ou opcionais. Para um parâmetro ser opcional, omesmo é atribuído a um valor padrão
Agoraéamelhorhoradeaprenderalgonovo
6.2PARÂMETROSDEFUNÇÃO
64 6.2PARÂMETROSDEFUNÇÃO
![Page 72: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/72.jpg)
(default)-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ão#idade:20
Agorapassandoapenasonome:
dados('joão')
#nome:joão#idade:nãoinformada
Eoqueacontecesepassarmosapenasaidade?
dados(20)
#nome:20#idade:nãoinformada
VejaqueoPythonobedeceaordemdosparâmetros.Nossaintençãoerapassaronúmero20comoidade,masointerpretadorvaientenderqueestamospassandoonomeporquenãoavisamosissoà
ele.Casoqueiramospassarapenasaidade,devemosespecificaroparâmetro:
dados(idade=20)File"<stdin>",line1,in<module>TypeError:dados()missing1requiredpositionalargument:'nome'
Ointerpretadoriráacusarumerro,jáquenãopassamosoatributoobrigatórionome.
Eseaoinvésdeapenasmostraroresultado,quisermosutilizaravelocidademédiaparafazeroutrocálculo,comocalcularaaceleração?Damaneiracomoestá,nossafunçãovelocidade()nãoconsegue
utilizarseuresultadofinalparacálculos.
Exemplo:aceleracao=velocidade(parametros)/tempo
Paraconseguirmosestecomportamento,precisamosquenossafunçãoretorneovalorcalculadoporela.EmPythoneemoutraslinguagensdeprogramação,istoéalcançadoatravésdocomandoreturn:
6.3FUNÇÃOCOMRETORNO
6.3FUNÇÃOCOMRETORNO 65
![Page 73: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/73.jpg)
defvelocidade(espaco,tempo):v=espaco/temporeturnv
Testando:
print(velocidade(100,20))#5.0
Ouainda,podemosatribuí-laaumavariável:
resultado=velocidade(100,20)print(resultado)#5.0
Econseguimosutilizá-lanocálculodaaceleração:
aceleracao=velocidade(100,20)/20print(aceleracao)#0.25
Umafunçãopodecontermaisdeumcomandoreturn.Porexemplo,nossafunçãodados() queimprimeonomeeaidade,podeagoraretornarumastring.Repareque,nestecaso,temosduassituaçõespossíveis: a que a idade é passada por parâmetro e a que ela não é passada. Aqui, teremos doiscomandosreturn:
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çãoencontraumcomandoreturn,elanãoexecutamaisnadaquevierdepoisdeledentrodeseuescopo.
Apesardeumafunçãoexecutarapenasumretorno,emPythonpodemosretornarmaisdeumvalor.Vamos fazer uma função calculadora que vai retornar os resultados de operações básicas entre doisnúmeros:adição(+)esubtração(-),nestaordem.
Pararetornarmúltiplosvalores,retornamososresultadosseparadosporvírgula:
defcalculadora(x,y):returnx+y,x-y
print(calculadora(1,2))
#(3,-1)
Qualseráotipoderetornodestafunção?Vamosperguntaraointerpretadoratravésdafunçãotype:
print(type(calculadora(1,2)))
6.4RETORNANDOMÚLTIPLOSVALORES
66 6.4RETORNANDOMÚLTIPLOSVALORES
![Page 74: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/74.jpg)
#<class'tuple'>
Damaneiraquedefinimosoretorno,afunçãodevolveumatupla.Nestecasoespecífico,poderíamosretornarumdicionárioeusarumlaçoforparaimprimirosresultados:
defcalculadora(x,y):return{'soma':x+y,'subtração':x-y}
resultados=calculadora(1,2)forkeyinresultados:print('{}:{}'.format(key,resultados[key]))
#soma:3#subtração:-1
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
1. Definaumafunçãochamadavelocidade_media()emumscriptchamadofuncoes.py que recebe
doisparâmetros:adistânciapercorrida(emmetros)eotempo(emsegundos)gasto.
defvelocidade_media(distancia,tempo):pass
2. Agoravamosinseriras instruções,ouseja,oqueafunçãodevefazer.Vamosinseriroscomandosparacalcularavelocidademé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çãopara os valores abaixo e compare os resultados com seus
EditoraCasadoCódigocomlivrosdeumaformadiferente
6.5EXERCÍCIOS:FUNÇÕES
6.5EXERCÍCIOS:FUNÇÕES 67
![Page 75: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/75.jpg)
colegas:
distância:100,tempo=20distância:150,tempo=22distâ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ça
entreeles.
8. Agora façauma funçãocalculadora() que recebe dois números como parâmetros e retorna o
resultadodasomaedasubtraçãoentreeles.
9. Modifiqueafunçãocalculadora()doexercícioanteriorefaçaelaretornartambémoresultadoda
multiplicaçãoedivisãodosparâmetros.
10. Chameafunçãocalculadora()comalgunsvalores.
11. (opcional)Definauma funçãodivisao() que recebedois números comoparâmetros, calcula e
retornaoresultadodadivisãodoprimeiropelosegundo.Modifiqueafunçãovelocidade_media()
utilizandoafunçãodivisao()paracalcularavelocidade.Testeoseucódigochamandoafunção
velocidade_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:*argse**kwargs.Muitosprogramadorestemdificuldadesementenderessasvariáveis.Vamosentenderoqueelassão.
Nãoénecessárioutilizarexatamenteestesnomes:*argse**kwargs.Apenasoasterisco(*),ou
doisdeles(**), serãonecessários.Podemosoptar, por exemplo, emescrever*var e**vars.Mas
*argse**kwargséumaconvençãoentreacomunidadequetambémseguiremos.
Primeiro, aprenderemos a usar o*args. É usado, assim como o**kwargs, em definições de
funções.*argse**kwargspermitempassarumnúmerovariáveldeargumentosdeumafunção.O
que 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.
6.6NÚMEROARBITRÁRIODEPARÂMETROS(*ARGS)
68 6.6NÚMEROARBITRÁRIODEPARÂMETROS(*ARGS)
![Page 76: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/76.jpg)
Vejaumexemplo:
defteste(arg,*args):print('primeiroargumentonormal:{}'.format(arg))forarginargs:print('outroargumento:{}'.format(arg))
teste('python','é','muito','legal')
Quevaigerarasaída:
primeiroargumentonormal:pythonoutroargumento:éoutroargumento:muitooutroargumento:legal
O parâmetro arg é como qualquer outro parâmetro de função, já o *args recebe múltiplos
parâmetros.Viucomoéfácil?Tambémpoderíamosconseguiromesmoresultadopassandoumlist
outupledeargumentos,acrescidodoasterisco:
lista=["é","muito","legal"]teste('python',*lista)
Ouainda:
tupla=("é","muito","legal")teste('python',*tupla)
O*argsentãoéutilizadoquandonãosabemosdeantemãoquantosargumentosqueremospassar
paraumafunção.Oasterisco(*)executaumempacotamentodosdadosparafacilitarapassagemde
parâmetros,eafunçãoquerecebeestetipodeparâmetroécapazdefazerodesempacotamento.
O**kwargspermitequepassemosotamanhovariáveldapalavra-chavedosargumentosparauma
função.Vocêdeveusaro**kwargssequisermanipularargumentosnomeadosemumafunção.Veja
umexemplo:
defminha_funcao(**kwargs):forkey,valueinkwargs.items():print('{0}={1}'.format(key,value))
>>>minha_funcao(nome='caelum')nome=caelum
Tambémpodemospassarumdicionárioacrescidodedoisasteriscos,jáquesetratadechaveevalor:
dicionario={'nome':'joao','idade':25}minha_funcao(**dicionario)idade=25nome=joao
Adiferençaéqueo*argsesperaumatupladeargumentosposicionais,enquantoo**kwargsum
6.7NÚMEROARBITRÁRIODECHAVES(**KWARGS)
6.7NÚMEROARBITRÁRIODECHAVES(**KWARGS) 69
![Page 77: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/77.jpg)
dicionáriocomargumentosnomeados.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Crieumarquivocomumafunçãochamadateste_args_kwargs()querecebetrêsargumentose
imprimecadaumdeles:
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**kwargs.Paraisso,crieumdicionáriocomtrêsargumentos:
kwargs={'arg3':3,'arg2':'dois','arg1':'um'}teste_args_kwargs(**kwargs)
Quedevegerarasaída:
arg1:umarg2:doisarg3:3
4. (Opcional)Tentechamaramesmafunção,masadicionandoumquartoargumentonavariávelargsekwargsdosexercíciosanteriores.Oqueaconteceseafunçãorecebemaisdoque3argumentos?
JáconheceoscursosonlineAlura?
6.8EXERCÍCIO-*ARGSE**KWARGS
70 6.8EXERCÍCIO-*ARGSE**KWARGS
![Page 78: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/78.jpg)
5. Dequemaneiravocêresolveriaoproblemadoexercícioanterior?
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
Emseguida,chameafunçãojogar()logoabaixodadefiniçãodafunçãonoarquivoforca.py:
>>>jogar()"*********************************""***BemvindoaojogodaForca!***""*********************************"['_','_','_','_','_','_']Qualletra?
Agoranossojogofuncionacomoesperado.
2. Façaomesmocomojogodaadivinhaçãoeexecuteojogo.
3. Agoravamoscriarummenuparaqueousuáriopossaescolherumjogo(adivinhaçãoouforca).Crieoarquivomenu.pydemodoqueanossaestruturadearquivosfiqueassim:
|_home|_jogos|_advinhacao.py|_forca.py|_menu.py
Importeosarquivosdecadajogodentrodomenu.py:
importadivinhacaoimportforca
Obs:Certifique-sede removerachamadada função jogar() logoabaixodadefiniçãodasmesmasnosarquivosforca.pyeadivinhação.py,poiscasoestaspermaneçamnosarquivos,aschamadasaosjogosserãorealizadasautomaticamenteaogerarosimportsnoarquivomenu.py!
Peçaparaousuárioescolherumadasopções:
#Importamódulos(códigoomitido)
print('*********************************')print('**********MENUDEJOGOS**********')print('*********************************')print("1.Adivinhação")print("2.Forca")escolha=int(input("Qualjogoquerjogar?Digiteonúmero:"))
6.9EXERCÍCIO-FUNÇÃOJOGAR()
6.9EXERCÍCIO-FUNÇÃOJOGAR() 71
![Page 79: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/79.jpg)
ifescolha==1:#Jogaradivinhaçãoelifescolha==2:#Jogarforca
Chameafunçãojogar()domódulodojogoescolhido:
#Importamóduloserecebeaescolhadousuário(códigoomitido)
ifescolha==1:adivinhacao.jogar()elifescolha==2:forca.jogar()
Agora toda vez que o usuário quiser jogar umde nossos jogos, ele poderá escolher pormeio domenucriado.
Aoimportaroarquivoforca.py,estamosimportandoummódulodenossoprograma,quenadamaisédoqueumarquivo.Vamosverificarotipodeforca:
print(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.
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
6.10MÓDULOSEOCOMANDOIMPORT
VocêpodetambémfazerocursodatadessaapostilanaCaelum
72 6.10MÓDULOSEOCOMANDOIMPORT
![Page 80: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/80.jpg)
CAPÍTULO7
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é
o nome do arquivo a ser aberto, e o segundo parâmetro é omodo que queremos trabalhar com essearquivo-sequeremoslerouescrever.Omodoépassadoatravésdeumastring:"w"(abreviaçãoparawrite)paraescritae"r"(abreviaçãopararead)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 omesmo existir. Se a intenção é apenas adicionar conteúdo aoarquivo,utilizamosomodo"a"(abreviaçãoparaappend).
Agoraquetemosoarquivo,vamosaprenderaescreveralgumconteúdonele.Bastachamarapartirdoarquivoafunçãowrite(),passandoparaelaoquesequerescrevernoarquivo:
>>>arquivo.write('banana')6>>>arquivo.write('melancia')8
Oretornodessafunçãoéonúmerodecaracteresdecadatextoadicionadonoarquivo.
ARQUIVOS
7.1ESCRITADEUMARQUIVO
7ARQUIVOS 73
![Page 81: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/81.jpg)
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
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á fechado, não vai surtir efeito algum, nem mesmo um erro. Abra o arquivo na pasta criada everifiqueseuconteúdo:
bananamelancia
Aspalavrasforamescritasemumamesmalinha.Mascomoescreverumanovalinha?
Aprimeiracoisaquedevemosfazeréabriroarquivonovamente,dessavezutilizandoomodo'a',deappend:
arquivo=open('palavras.txt','a')
Vamosescrevernovamentenoarquivo,masdessavezcomapreocupaçãodecriarumanovalinhaapóscadaconteúdoescrito.Pararepresentarumanovalinhaemcódigo,adicionamoso \nao finaldoquequeremosescrever:
>>>arquivo.write('morango\n')8>>>arquivo.write('manga\n')
Aofecharoarquivoeverificarnovamenteoseuconteúdo,vemos:
Seuslivrosdetecnologiaparecemdoséculopassado?
7.2FECHANDOUMARQUIVO
7.3ESCREVENDOPALAVRASEMNOVASLINHAS
74 7.2FECHANDOUMARQUIVO
![Page 82: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/82.jpg)
bananamelanciamorangomanga
Apalavramorangoaindaficounamesmalinha,mascomoespecificamosnasuaadiçãoqueapósapalavradeveráterumaquebradelinha,apalavramangafoiadicionadaabaixo,emumanovalinha.
Porfim,vamosmoverestearquivoparanossoprojetoeajeitarsuaspalavrasquebrandoaslinhas.
1. Vamosnavegaraténossapasta jogosdentrodehome.Lembrandoquenossaestruturadearquivosestáassim:
|_home|_jogos|_advinhacao.py|_forca.py|_menu.py
2. Crieumoutroarquivo,chamadoarquivo.pyeinsiraoseguintecódigo:
arquivo=open("palavras.txt","w")
Rodeoarquivoevejaoresultado.Oseudiretóriodeveráestarsimilara:
|_home|_jogos|_advinhacao.py|_forca.py|_arquivo.py|_menu.py|_palavras.txt
3. Vamoscomeçaraescrevernonossoarquivoutilizandoafunçãowrite()aspalavrasqueusaremos
nonossojogodaforca:
arquivo.write('banana\n')
arquivo.write('melancia\n')
arquivo.write('morango\n')
arquivo.write('manga\n')
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()
7.4EXERCÍCIOS
7.4EXERCÍCIOS 75
![Page 83: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/83.jpg)
PARASABERMAIS
Alémdor,weaexisteomodificadorbqueéutilizadoquandosedeseja trabalharnomodobinário.Paraabrirumaimagemnomodoleitura,devemosusar:
```pythonimagem=open('foto.jpg','rb')```
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
AindanoterminaldoPython3,veremosofuncionamentodaleituradeumarquivo.Comoagoraoarquivopalavras.txtestánapastadoprojetojogos,devemosexecutarocomandoqueabreoterminal
doPython3napastadoprojeto.
$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'
Agoraéamelhorhoradeaprenderalgonovo
7.5LENDOUMARQUIVO
76 7.5LENDOUMARQUIVO
![Page 84: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/84.jpg)
Comooarquivofrutas.txtnãoexistenapastajogos,oPyhtonnãoconsegueencontrareacusaquenã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íciodoarquivocomosefosseumcursor.Elevaidescendoelendooarquivo.Apóslertudo,eleficaposicionadonofinaldoarquivo.Quandochamamosafunçãoread()novamente,nãohámaisconteúdopoisele todo já foi
lido.
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ência,podemosutilizarumlaç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, a
7.6LENDOLINHAPORLINHADOARQUIVO
7.6LENDOLINHAPORLINHADOARQUIVO 77
![Page 85: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/85.jpg)
readline(),quelêapenasumalinhadoarquivo:
arquivo=open('palavras.txt','r')linha=arquivo.readline()print(linha)
'banana\n'
Háum\n ao final de cada linha, de cada palavra,mas queremos somente a palavra. Para tirar
espaçosembranconoinícioenofimdastring,bastautilizarafunçãostrip(),quetambémremove
caracteresespeciais,comoo\n-paramaisinformaçõesconsulteadocumentaçãodestrings.Sabendo
dissotudo,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(), que
recebe 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.
7.7GERANDOUMNÚMEROALEATÓRIO
78 7.7GERANDOUMNÚMEROALEATÓRIO
![Page 86: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/86.jpg)
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
1.Vamos começar abrindo o arquivo "palavras.txt" no nosso script forca.py que criamos no
exercícioanterior.Éimportantejáacrescentarocomandoparafechá-loparanãoesquecernofuturo:
defjogar():print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')
arquivo=open('palavras.txt','r')arquivo.close()
#restantedocódigo
1. Agoravamoscriarumalistachamadapalavrasefazerumlaçoforparaacessarcadalinhapara
guardarnalista:
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()
EditoraCasadoCódigocomlivrosdeumaformadiferente
7.8EXERCÍCIOS-LEITURADEARQUIVOS
7.8EXERCÍCIOS-LEITURADEARQUIVOS 79
![Page 87: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/87.jpg)
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úmerodeletrasde
acordocomnossapalavra_secreta.Vamosutilizarumfordentrodalistaparagerarum'_'para
cadaletradeacordocomotamanhodapalavra_secreta:
letras_acertadas=['_'forletrainpalavra_secreta]
6. Como já garantimos que a palavra_secreta está toda em letras maiúsculas com o código
palavras[numero].upper(),modificaremosochuteparaoprimeiroifcontinuarfuncionando
chute=input('Qualaletra?')chute=chute.strip().upper()
Podemosexecutarojogoenotarqueapalavraéselecionadaaleatoriamente!
80 7.8EXERCÍCIOS-LEITURADEARQUIVOS
![Page 88: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/88.jpg)
Mas agora a nossa função cresceu bastante, com várias funcionalidades e responsabilidades. Nopróximo capítulo organizaremosmelhor o nosso código, separando-o em funções e deixando-omaisfácildeentender.
Já falamosda importânciade fecharoarquivo, certo?Vejaocódigoabaixoque justamenteusaafunçãoclose():
arquivo=open('palavras.txt','r')palavras=logo.read()arquivo.close()
Imaginequealgumproblemaaconteçanahorada leituraquandoafunçãoread()échamada.Seráqueoarquivoéfechadoquandooerroocorre?
Seforalgumerrograve,oprogramapodepararaexecuçãosemterfechadooarquivoeistoseriabastanteruim.Paraevitaressetipodesituação,existenoPythonumasintaxeespecialparaaberturadearquivo:
withopen('palavras.txt')asarquivo:forlinhainarquivo:print(linha)
Repareocomandowithusaafunçãoopen(),masnãoafunçãoclose().Issonãoserámais
necessário, já que o comando with vai se encarregar de fechar o arquivo para nós, mesmo que
aconteçaalgumerronocódigodentrodeseuescopo.Muitomelhor,não?
Noscapítulosanteriorescriamosdoisjogos,avançamosnojogodaForcaeimplementamosleituradepalavrasemumarquivo.Agoravamosutilizaroqueaprendemosdefunçõesparaencapsularnossocódigo e deixá-lomais organizado.Vamos começar, comos conhecimentos que temos até aqui, paraestruturarnossojogodaForca.
A função jogar() possui um código muito complexo, com muitas funcionalidades e
responsabilidades.
Entre as funcionalidadesqueo códigopossui, está a apresentaçãodo jogo, a leiturado arquivo einicializaçãodapalavrasecreta,entreoutras.Vamosentãosepararas 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 da
funçãojogar():
7.9PARASABERMAIS-COMANDOWITH
7.10MELHORANDONOSSOCÓDIGO
7.9PARASABERMAIS-COMANDOWITH 81
![Page 89: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/89.jpg)
importrandom
defjogar():imprime_mensagem_abertura()
#códigoomitido
defimprime_mensagem_abertura():print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')
Aquinãoimportaolocaldafunção,elapodeserdeclaradaantesoudepoisdafunçãojogar().
Oquefizemosfoirefatorarnossocódigo.Refatoraçãoéoprocessodemodificarumprogramaparamelhoraraestruturainternadocódigo,semalterarseucomportamentoexterno.VejaqueseexecutarmosnossojogodaForca,tudofuncionacomoantes:
*********************************)***BemvindoaojogodaForca!************************************['_','_','_','_','_','_']Qualletra?
Nopróximoexercício,vamosrefatorarasdemaispartesdonossocódigo.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
1. Crieafunçãoimprime_mensagem_aberturaquevaiisolaramensagemdeaberturadojogo:
importrandom
defjogar():imprime_mensagem_abertura()
#códigoomitido
defimprime_mensagem_abertura():
JáconheceoscursosonlineAlura?
7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA
82 7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA
![Page 90: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/90.jpg)
print('*********************************')print('***BemvindoaojogodaForca!***')print('*********************************')
2. Agora, vamos separar o código que realiza a leitura do arquivo e inicializa a palavra secreta nafunçã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,ao
executarafunçãocarrega_palavra_secreta(),queelaretorneapalavrasecretaparanós,assim
poderemosguardá-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ção
carrega_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. Agora, vamos criar uma função que inicializa a lista de letras acertadas com o caractere '_'.Criaremosafunçãoinicializa_letras_acertadas():
7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA 83
![Page 91: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/91.jpg)
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ão
existedentroda função, jáqueumafunçãodefineumescopo,easvariá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ácomo
có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():
while(notacertouandnotenforcou):
84 7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA
![Page 92: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/92.jpg)
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.Assim,vamospassaressesvaloresporparâmetro:
if(chuteinpalavra_secreta):marca_chute_correto(chute,letras_acertadas,palavra_secreta)
Emodificamosnossafunçãoparareceberessesparâmetros:
defmarca_chute_correto(chute,letras_acertadas,palavra_secreta):posicao=0forletrainpalavra_secreta:if(chute==letra):letras_acertadas[posicao]=letraposicao+=1
1. Por fim, vamos remover a mensagem de fim de jogo e exportar os códigos que imprimem asmensagensdevencedoreperdedordojogo:
if(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()
letras_acertadas=inicializa_letras_acertadas(palavra_secreta)
7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA 85
![Page 93: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/93.jpg)
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.
************************************BemvindoaojogodaForca!************************************['_','_','_','_','_','_']Qualletra?
2. (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("\__/")print("\__/")print("\_______/")
Precisamospassarapalavra_secretaparafunçãoimprime_mensagem_perdedor():
86 7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA
![Page 94: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/94.jpg)
if(acertou):imprime_mensagem_vencedor()else:imprime_mensagem_perdedor(palavra_secreta)
Emodificamosocódigodeimprime_mensagem_vencedor()para:
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.
1. (opcional)Porfim,crieafunçãodesenha_forca(),queirádesenharumapartedaforca,baseado
noserrosdousuário.Comoelaprecisaacessaroserros,passe-oporparâmetroparaafunção:
defdesenha_forca(erros):pass
Ecopieoconteúdodocódigodafunçãodesenha_forca()doarquivofuncoesforca.pynapasta
docursoparasuafunção.
2. Parafinalizar,chameafunçãodesenha_forcaquandoojogadorerrareaumenteolimitedeerros
para7.
if(chuteinpalavra_secreta):marca_chute_correto(chute,letras_acertadas,palavra_secreta)else:erros+=1desenha_forca(erros)
enforcou=erros==7acertou="_"notinletras_acertadas
3. Tentefazeromesmocomojogodaadivinhação,refatorepartesdocódigoeisoleemfunções.Alémdisso,usesuacriatividadeparacustomizarmensagensparaousuáriodoseujogo.
Nesteexercício,praticamosbastantedoqueaprendemosnocapítulodefunçãoefinalizamosojogodaforca.
Vocêpodeestarseperguntandoporqueencapsulamosumasimpleslinhadecódigoemumafunção.Fizemosissosomenteparadeixarclarooqueestamosfazendo,melhorandoalegibilidadedocódigo.Masprecisamostomarcuidadocomacriaçãodefunções,poiscriarfunçõesdesnecessariamentepode
7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA 87
![Page 95: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/95.jpg)
aumentaracomplexidadedocódigo.
88 7.11EXERCÍCIO-REFATORANDOOJOGODAFORCA
![Page 96: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/96.jpg)
CAPÍTULO8
Considereumprogramaparaumbancofinanceiro.Éfácilperceberqueumaentidadeimportanteparaonosso sistema será uma conta.Primeiramente, suponhaquevocê temumaconta nessebanco 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
Nossobancopodeviracrescere termilharesdecontase,damaneiraqueestá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
8ORIENTAÇÃOAOBJETOS 89
![Page 97: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/97.jpg)
umaconta:
defcria_conta():conta={"numero":'123-4',"titular":"João","saldo":120.0,"limite":1000.0}returnconta
Mas ainda não é o ideal, já que queremos criar contas com outros valores e tornar a criaçãodinâmica.Vamosentãoreceberessevalorescomoparâmetrosdafunção,eporfimretornamosaconta:
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().Agorapodemostestaro
código(supondoqueomesmoestejaemumarquivochamadoteste.py):
8.1FUNCIONALIDADES
90 8.1FUNCIONALIDADES
![Page 98: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/98.jpg)
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(),eaofinalpudemoschecarosaldofinalcomafunçãoextrato().
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
1. Crieumapastachamadaooemsuaworkspaceecrieumarquivochamadoteste_conta.py
2. Crieafunçãochamadacria_conta(),querecebecomoargumentonumero,titular,saldoe
limite:
defcria_conta(numero,titular,saldo,limite):
3. Dentrodecria_conta(), crieumavariáveldo tipodicionáriochamadaconta comas chaves
recebendoosvaloresdosparâmetros(numero,titular,saldoelimite),eaofinal,retornea
conta:
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 como
argumentoumacontaeumvalor.Dentrodafunção,adicioneovaloraosaldodaconta:
VocêpodetambémfazerocursodatadessaapostilanaCaelum
8.2EXERCÍCIO:CRIANDOUMACONTA
8.2EXERCÍCIO:CRIANDOUMACONTA 91
![Page 99: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/99.jpg)
defdeposita(conta,valor):conta['saldo']+=valor
5. Crieoutrafunçãochamadasaca()querecebecomoargumentoumacontaeumvalor.Dentro
dafunção,subtraiaovalordosaldodaconta:
defsaca(conta,valor):conta['saldo']-=valor
6. E por fim, crie uma função chamada extrato(), que recebe como argumento uma conta e
imprimeonumeroeosaldo:
defextrato(conta):print("numero:{}\nsaldo:{}".format(conta['numero'],conta['saldo']))
1. Navegueatéapastaoo,digiteoscomandosnoarquivoteste_conta.pyetesteasfuncionalidades:
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
2. (Opcional)Acrescenteumadocumentaçãoparaoseumóduloteste_conta.pyeutilizeafunção
help()paratestá-la.
Nesteexercíciocriamosumacontaejuntamossuascaracterísticas(número,titular,limite,saldo)efuncionalidades (sacar,depositar, tirar extrato)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:
8.3CLASSESEOBJETOS
92 8.3CLASSESEOBJETOS
![Page 100: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/100.jpg)
conta3['saldo']=-3000.0
Devemosmanipularosdadosatravésdasfuncionalidadessaca() edeposita() e proteger os
dadosdaconta.Pensandonomundoreal,ninguémpodemodificarosaldodesuacontaquandoquiser,anãoserquandovamosfazerumsaqueouumdepósito.Amesmacoisadeveaconteceraqui.
Para isso, vamos primeiro entender o que é classe e objeto , conceitos importantes do
paradigmaorientadoaobjetosedepoisveremoscomoissofuncionanaprática.
Quandopreparamosumbolo,geralmenteseguimosumareceitaquedefineosingredienteseomodode preparação.A nossa conta é um objeto concreto assim como o bolo que também precisa de umareceitapré-definida.Ea"receita"nomundoOOrecebeonomedeclasse.Ouseja,antesdecriarmosumobjeto,definiremosumaclasse.
Outraanalogiaquepodemosfazeréentreoprojetodeumacasa(aplantadacasa)eacasaemsi.Oprojeto é aclasse 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. É comumo iniciante utilizar, obviamente de formaerrada,essasduaspalavrascomosinônimos.
OpróximopassoserácriarnossaclasseContadentrodeumnovoarquivoPython,quereceberáo
nomedeconta.py.CriarumaclasseemPythonéextremamentesimplesemtermosdesintaxe.Vamoscomeçar criando uma classe vazia. Depois criaremos uma instância, um objeto dessa classe, eutilizaremosafunçãotype()paraanalisaroresultado:
classConta:pass
#Emoutroarquivo:fromcontaimportConta
conta=Conta()print(type(conta))#<class'__main__.Conta'>
VemospoisomóduloondeseencontraaclasseConta énomóduloprincipal,ouseja,nanossa
__main__.Agora,temosumaclasseConta.
ComoPython é uma linguagem dinâmica, podemosmodificar esse objetoconta em tempo de
execução.Porexemplo,podemosacrescentaratributosaele:
conta.titular="João"print(conta.titular)#'João'
conta.saldo=120.0
8.3CLASSESEOBJETOS 93
![Page 101: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/101.jpg)
print(conta.saldo)#120.0
Mas o problema do código é que ainda não garantimos que toda instância deConta tenha um
atributotitular ousaldo. Portanto, queremosuma formapadronizadada conta demaneira que
possamoscriarobjetoscomdeterminadasconfiguraçõesiniciais.
Em linguagens orientadas a objetos, existe uma maneira padronizada de criar atributos em umobjeto.Geralmentefazemosissoatravésdeumafunçãoconstrutora-algoparecidocomnossafunçãocria_conta()doexercícioanterior.
EmPython,algunsnomesdemétodosestãoreservadosparaousodapróprialinguagem.Umdessesmétodos é o __init__() que vai inicializar o objeto. Seu primeiro parâmetro, assim como todo
métododeinstância,éaprópriainstância.Porconvenção,chamamosesteargumentodeself.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ãocriaum
objeto conta. Existe outro método, o __new__() que é chamado antes do __init_() pelo
interpretadordoPython.Ométodo__new__()érealmenteoconstrutoreéquemrealmentecriauma
instância deConta.Ométodo __init__() é responsável por inicializar o objeto, tanto é que já
recebeaprópriainstância(self)criadapeloconstrutorcomoargumento.Dessamaneira,garantimosquetodainstânciadeumaContatenhaosatributosquedefinimos.
Agora,seexecutarmosalinhadecódigoabaixo,vaiacusarumerro:
conta=Conta()Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:__init__()missing4requiredpositionalarguments:'numero','titular','saldo',and'limite
Oerro acusa a falta de4 argumentosnahorade criar umaConta.A classeConta agoranos
obrigaapassar4atributos(numero,titular,saldoelimite)paracriarumaconta:
conta=Conta('123-4','João',120.0,1000.0)
Veja que em nenhummomento chamamos ométodo__init__(). Quem está fazendo isso por
debaixodospanoséopróprioPythonquandoexecutaconta=Conta().Comovimos,elechamao
8.4CONSTRUTOR
94 8.4CONSTRUTOR
![Page 102: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/102.jpg)
método__new__()quedevolveuminstânciadoobjetoeemseguidachamaométodo__init__()
todavezquecriamosumaconta.Podemosveristofuncionandoimprimindoumamensagemdentrodométodo__init__():
def__init__(self,titular,numero,saldo,limite):print("inicializandoumaconta")self.titular=titularself.numero=numeroself.saldo=saldoself.limite=limite
etestarnovamente:
conta=Conta('123-4','João',120.0,1000.0)inicializandoumaconta
Ao criar uma Conta, estamos pedindo para o Python criar uma nova instância de Conta na
memória,ouseja,oPythonalocarámemóriasuficienteparaguardar todasas informaçõesdaConta
dentro da memória do programa. O __new__(), portanto, devolve uma referência, uma seta queapontaparaoobjetoemmemóriaeéguardadanavariávelconta.
Paramanipularmos nosso objeto conta e acessarmos seus atributos, utilizamos o operador "."
(ponto):
print(conta.titular)#'João'print(conta.saldo)#120.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 aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
8.4CONSTRUTOR 95
![Page 103: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/103.jpg)
Como vimos, além dos atributos, nossa conta deve possuir funcionalidades. No arquivoteste_conta.pycriamosasfunçõessaca(),deposita()eextrato().Noparadigmaorientado a
objetos,asfuncionalidadesdeumobjetosãochamadosdemétodos-dopontodevistadocódigo,sãoasfunçõesdentrodeumaclasse.
Vamoscriarométododeposita()naclasseConta.Aqui,assimcomoométodo__init__(),o
métododeposita()devereceberainstânciadoobjeto(self)alémdovaloraserdepositado:
classConta:
#método__init__()omitido
defdeposita(self,valor):self.saldo+=valor
Issoaconteceporqueométodoprecisasaberqualobjetocontaeledevemanipular,qualcontavaidepositarumdeterminadovalor-epodemostermuitascontascriadasnonossosistema.
Utilizamosooperador'.'(ponto)atravésdoobjetocontaparachamarométododeposita:
>>>conta.deposita(20.0)
Aoleressecódigo,ointerpretadorassociaoobjetocontaaoargumentoselfdométodo-note
quenã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:
conta=Conta('123-4','João',120.0,1000.0)conta.deposita(20.0)conta.extrato()#numero:'123-4'#saldo:140.0conta.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.
8.5MÉTODOS
96 8.5MÉTODOS
![Page 104: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/104.jpg)
Porfim,ocódigodenossaContavaificarassim:
classConta:
def__init__(self,numero,titular,saldo,limite):self.numero=numeroself.titular=titularself.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 -maspodemosretornaralgonométodosaca(),porexemplo,indicandoseaoperaçãofoibemsucedida
ounão.Nestecaso,podemosretornarumvalorbooleano:
defsaca(self,valor):if(self.saldo<valor):returnFalseelse:self.saldo-=valorreturnTrue
Veja que a declaração do método não mudou, mas agora ele nos retorna algo (um boolean). Apalavrachavereturnindicaqueométodovaiterminarali,retornandotalinformação.
Exemplodeuso:
minha_conta.saldo=1000consegui=minha_conta.saca(2000)if(consegui):print(“conseguisacar”)else:print(“nãoconseguisacar”)
#'nãoconseguisacar'
Ouentão,podemoseliminaravariáveltemporária,sedesejado:
minha_conta.saldo=1000if(minha_conta.saca(2000)):print(“conseguisacar”)else:print(“nãoconseguisacar”)
#'nãoconseguisacar'
8.6MÉTODOSCOMRETORNO
8.6MÉTODOSCOMRETORNO 97
![Page 105: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/105.jpg)
Maisadiante,veremosquealgumasvezesémaisinteressantelançarumaexceção(exception)nessescasos.
OprogramapodemanternamemórianãoapenasumaConta,masmaisdeuma:
minha_conta=Conta()minha_conta.saldo=1000
meu_sonho=Conta()meu_sonho.saldo=1500000
Quando criamos uma variável para associar a umobjeto, 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ávelreferência.Todavia,écomumouvirfrasescomo“tenhoumobjetoc1dotipoConta”,
mas issoéapenasumaabreviaçãoparaencurtarafrase“Tenhoumareferênciac1 a umobjeto tipo
Conta”.
Vamosanalisarocódigoabaixo:
c1=Conta('123-4','João',120.0,1000.0)c2=c1print(c2.saldo)#120.0c1.deposita(100.0)print(c1.saldo)#220.0c2.deposita(30.0)print(c2.saldo)#250.0print(c1.saldo)#250.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 se
encontranamemóriaprincipal.
8.7OBJETOSSÃOACESSADOSPORREFERÊNCIA
98 8.7OBJETOSSÃOACESSADOSPORREFERÊNCIA
![Page 106: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/106.jpg)
Aofazerc2=c1,c2passaa fazer referênciaparaomesmoobjetoquec1 referencia nesse
instante.Quandoutilizamosc1ouc2nestecódigo,estamosnosreferindoaoMESMOobjeto–são
duasreferênciasqueapontamparaomesmoobjeto.
Podemosnotarissoatravésdafunçãointernaid()queretornaareferênciadeumobjeto:
print(id(c1))#140059774918104print(id(c2))#140059774918104
Internamente,c1ec2vãoguardarumnúmeroqueidentificaemqueposiçãodamemóriaaquela
Contaseencontra.Dessamaneira,aoutilizarmoso“.”(ponto)paranavegar,oPythonvaiacessara
Conta que se encontra naquela posiçãodememória, e nãoumaoutra conta.Para quemconhece, é
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“==”vai
nosretornarTrue,poisovalorqueelascarregaméomesmo:
print(id(c1)==id(c2))#Trueprint(c1==c2)#True
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,esimoendereçoemqueeleseencontra.Comoemcadaumadessasvariáveisguardamosduascontascriadasdiferentemente,elasestãoemespaçosdiferentesdamemória,oquefazotestenoifvalerFalse.As
contas 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.
8.7OBJETOSSÃOACESSADOSPORREFERÊNCIA 99
![Page 107: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/107.jpg)
Para saber se dois objetos têm o mesmo 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,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
E a funcionalidade que transfere dinheiro entre duas contas? Podemos ficar tentados a criar ummétodoquerecebedoisparâmetros:conta1econta2dotipoConta.Cuidado:jásabemosqueos
métodosdenossaclasseContasemprerecebemareferência,oself-portantoométodorecebeapenasumparâmetrodotipoConta,acontadestino(alémdovalor):
classConta:
#códigoomitido
deftransfere(self,destino,valor):self.saldo-=valordestino.saldo+=valor
Agoraéamelhorhoradeaprenderalgonovo
8.8MÉTODOTRANSFERE
100 8.8MÉTODOTRANSFERE
![Page 108: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/108.jpg)
Para deixar o código mais robusto, poderíamos verificar se a conta possui a quantidade a sertransferidadisponível.Paraficaraindamaisinteressante,vocêpodechamarosmétodosdeposita e
sacajá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áqueo
objetoéclonado?
NoPython,apassagemdeparâmetrofuncionacomoumasimplesatribuiçãocomonousodo“=”.Então,esseparâmetrovaicopiarovalordavariáveldotipoContaqueforpassadocomoargumento
para a variáveldestino.E qual é o valor de uma variável dessas? Seu valor é um endereço, uma
referê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ês
queelatemumsentido:
conta1.transfere_para(conta2,50.0):
Aleituradestecódigoseria"conta1transfereparaconta250reais".
Os atributos deuma classepodem receber umvalor padrão - assimcomoos argumentosdeumafunção. Nosso banco pode ter um valor de limite padrão para todas as contas e apenas em casosespecíficospodeatribuirumvalorlimitediferente.
Paraaplicarmosessa regradenegócio,podemosatribuirumvalorpadrãoao limite,porexemplo,1000.0reais:
8.9CONTINUANDOCOMATRIBUTOS
8.9CONTINUANDOCOMATRIBUTOS 101
![Page 109: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/109.jpg)
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ão
de1000.0epodemosacessá-lopelaconta:
print(conta.limite)1000.0
Quando declaramos as variáveis na classe Conta, aprendemos que podemos atribuir um valor
padrão para cada uma delas. Imagine que comecemos a aumentar nossa classe Conta e adicionar
nome, sobrenome e cpf do titular da conta. Começaríamos a ter muitos atributos e, se você pensardireito,umaContanãotemnome,nemsobrenomenemcpf,quemtemessesatributoséumcliente.Assim, podemos criar uma nova classe e fazer uma agregação - agregar um cliente a nossa conta.Portanto,nossaclasseContatemumCliente.
OatributosdeumaContatambémpodemserreferênciasparaoutrasclasses.Suponhaaseguinte
classeCliente:
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:
cliente=Cliente('João','Oliveira','1111111111-1')minha_conta=Conta('123-4',cliente,120.0,1000.0)
Aquiaconteceuumaatribuição,ovalordavariávelclienteécopiadoparaoatributotitular
doobjetoaoqualminha_contaserefere.Emoutraspalavras,minha_contatemumareferênciaao
mesmoClientequeclienteserefere,epodeseracessadoatravésdeminha_conta.titular.
Vocêpoderealmentenavegarsobretodaestruturadeinformação,sempreusandooponto:
102 8.9CONTINUANDOCOMATRIBUTOS
![Page 110: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/110.jpg)
print(minha_conta.titular)#<__main__.Clienteobjectat0x7f83dac31dd8>
VejaqueasaídaéareferênciaaumobjetodotipoCliente,maspodemosacessarseusatributos
deumaformamaisdiretaeatémaiselegante:
print(minha_conta.titular.nome)#'João'
Pythonéumalinguagemtotalmenteorientadaaobjetos.TudoemPythonéumobjeto!Semprequeutilizamosumafunçãooumétodoquerecebeparâmetros,estamospassandoobjetoscomoargumentos.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.Por
estemotivo que aparece a palavra class quando pedimos para o Python nos devolver o tipo de umavariávelatravésdafunçãotype:
print(type(conta.numero))#<class'str'>print(type(conta.saldo))#<class'float'>print(type(conta.titular))#<class'__conta__.Cliente'>
Umsistemaorientadoaobjetoséumgrandeconjuntodeclassesquevaisecomunicar,delegandoresponsabilidadesparaquemformaisaptoarealizardeterminadatarefa.AclasseBancousaaclasse
Conta, queusa a classeCliente, queusa a classeEndereco, etc...Dizemosque esses objetos
colaboram,trocandomensagensentresi.Porisso,acabamostendomuitasclassesemnossosistema,eelascostumamterumtamanhorelativamentecurto.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
8.10TUDOÉOBJETO
EditoraCasadoCódigocomlivrosdeumaformadiferente
8.10TUDOÉOBJETO 103
![Page 111: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/111.jpg)
Fizemos, no ponto anterior, uma agregação. Agora nossa classe Conta tem um Cliente eassociamosestasduasclasses.Todavia,nossaclasseClienteexisteindependentedaclasseConta.
Suponha agoraquenossaConta possua um histórico, contendo a data de abertura da conta e suas
transaçõ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,aexistê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çõesde
seuHistorico:
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))
8.11COMPOSIÇÃO
104 8.11COMPOSIÇÃO
![Page 112: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/112.jpg)
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:
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.extrato
#numero:123-4#saldo:850.0
conta1.historico.imprime()
#dataabertura:2018-05-1019:44:07.406533#transações:#-depósitode100.0#-saquede50.0#-saquede200.0#-transferenciade200.0paraconta123-5#-tirouextrato-saldode850.0
conta2.historico.imprime()
#dataabertura:2018-05-1019:44:07.406553#transações:#-depósitode200.0
Quandoaexistênciadeumaclassedependedeoutraclasse,comoéa relaçãodaclasseHistóricocom a classe Conta, dizemos que a classe Historico compõe a classe Conta. Esta associação
chamamosComposição.
Mas,esedentrodanossaContanãocolocássemosself.historico=Historico(),eaoinvés
dissotentássemosacessá-lodiretamente?Fazalgumsentidofazerhistorico=Historico()?
Quandooobjetoéinicializado,elevaireceberovalordefaultquedefinimosnaclasse:
classConta:
def__init__(self,numero,cliente,saldo,limite):#iniciandooutrosparâmetrosself.historico=Historico()
Comessecódigo,todanovaContacriadajáteráumnovoHistoricoassociado,semnecessidade
deinstanciá-lologoemseguidadainstanciaçãodeumaConta.
8.11COMPOSIÇÃO 105
![Page 113: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/113.jpg)
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. Éimportantenessecomeçovocêestarsemprepensandonoestadodamemória.Alémdisso,lembrarquenoPython“umavariávelnuncacarregaumobjeto,esimumareferênciaparaele”facilitamuito.
Ointerpretadoradicionaalgunsatributosespeciaissomenteparaleituraaváriostiposdeobjetosdeumaclasse,sendoumdeleso__dict__.
Isso acontece porque a classe Conta possui alguns métodos, dentre eles o __init__() e o
__new__(),quesãochamadosparacriare inicializarumobjetodestaclasse, respectivamente.Caso
vocêqueirasaberquaisoutrosmétodossãoimplementadospelaclasseConta,vocêpodeusarafunção
embutidadir(),queirálistartodosmé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étodoseatributosquedefinimos
quandoconstruímosaclasseConta.Naverdade, quandousamos a funçãodir(), o interpretador
chamaoatributo__dir__dessalista.Umoutroatributobastanteútiléo__dict__,queretornaum
dicionáriocomosatributosdaclasse.
cliente=Cliente('João','Oliveira','111111111-11')conta=Conta('123-4',cliente,1000.0)print(conta.__dict__)#{'saldo':1000.0,'numero':'123-4','titular':<__main__.Clienteobjectat0x7f0b6d028f28>,'limite':1000.0}
Mas não é comum acessá-lo dessa maneira. Esses 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(),quechamaexatamenteo__dict__ de uma classe.
Obtemosomesmoresultadousandovars(conta):
vars(conta)#{'saldo':1000.0,'numero':'123-4','titular':<__main__.Clienteobjectat0x7f0b6d028f28>,'limite':1000.0}
Reparequeo__dict__eovars()retornamexatamenteumdicionáriodeatributosdeumaconta
como tínhamosmodelado no início deste capítulo. Portanto, nossas classes utilizam dicionários paraarmazenarinformaçõesdaprópriaclasse.
8.12PARASABERMAIS:OUTROSMÉTODOSDEUMACLASSE
106 8.12PARASABERMAIS:OUTROSMÉTODOSDEUMACLASSE
![Page 114: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/114.jpg)
Osdemaismétodosmágicosestãodisponíveisparausoenãoutilizaremosporenquanto.Voltaremosafalardelesemumoutromomento.
1. Crieumarquivochamadoconta.pynapastaoocriadanoexercícioanterior.
2. CrieaclasseContasemnenhumatributoesalveoarquivo.
classConta:pass
3. Vá até a pasta onde se encontra o arquivo conta.py e crie um novo arquivo, chamado
conta_teste.py.DentrodestearquivoimporteaclasseContadomóduloconta.
fromcontaimportConta
4. Crieumainstância(objeto)daclasseContaeutilizea funçãotype() para verificar o tipodo
objeto:
conta=Conta()type(conta)<class'conta.Conta'>
Alémdisso,criealgunsatributosetenteacessá-los.
5. Abra novamente o arquivo conta.py e escreva o método __init__(), recebendo os atributos
anteriormentedefinidospornósquetodacontadeveter(numerotitular,saldoelimite):
classConta:
def__init__(self,numero,titular,saldo,limite):self.numero=numeroself.titular=titularself.saldo=saldoself.limite=limite
6. Noarquivoconta_teste.py,Tentecriarumacontasempassarqualquerargumentonoconstrutor:
conta=Conta()Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>TypeError:__init__()missing4requiredpositionalarguments:'numero','titular','saldo',and'limite
Note que o interpretador acusou um erro.Ométodo__init__() exige 4 argumentos 'numero',
'titular','saldo'e'limite'.
7. Agoravamosseguiroexigidopelaclasse,pelareceitadeumaconta:
conta=Conta('123-4','João',120.0,1000.0)
8. Ointerpretadornãoacusounenhumerro.Vamosimprimironumeroetitulardaconta:
8.13EXERCÍCIO:PRIMEIRACLASSEPYTHON
8.13EXERCÍCIO:PRIMEIRACLASSEPYTHON 107
![Page 115: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/115.jpg)
print(conta.numero)'123-4'print(conta.titular)'João'
9. Crieométododeposita()dentrodaclasseConta.Essemétododevereceberumareferênciado
próprioobjetoeovaloraseradicionadoaosaldodaconta.
defdeposita(self,valor):self.saldo+=valor
10. Crieométodosaca()querecebecomoargumentoumareferênciadopróprioobjetoeovaloraser
sacado.Essemétodosubtrairáovalordosaldodaconta.
defsaca(self,valor):self.saldo-=valor
11. Crie ométodoextrato(), que recebe comoargumentouma referência dopróprioobjeto.Esse
métodoimprimiráosaldodaconta:
defextrato(self):print("numero:{}\nsaldo:{}".format(self.numero,self.saldo))
12. Modifiqueométodosaca() fazendo retornarumvalorque representa seaoperação foiounão
bemsucedida.Lembrequenãoépermitidosacarumvalormaiordoqueosaldo.
defsaca(self,valor):if(self.saldo<valor):returnFalseelse:self.saldo-=valorreturnTrue
13. Crieométodotransfere_para()querecebecomoargumentoumareferênciadopróprioobjeto,
umaContadestinoeovalorasertransferido.Essemétododevesacarovalordopróprioobjetoe
depositarnacontadestino:
deftransfere_para(self,destino,valor):retirou=self.saca(valor)if(retirou==False):returnFalseelse:destino.deposita(valor)returnTrue
14. Porfim,crieduascontasnoarquivoteste-conta.pyeverifiqueosmétodoscriados.
conta.deposita(50.0)conta.extrato()conta.saca(20.0)conta.extrato()
1. (Opcional) Crie uma classe para representar um cliente do nosso banco que deve ter nome ,
sobrenomeecpf.InstancieumaContaepasseumclientecomotitulardaconta.Modifique
108 8.13EXERCÍCIO:PRIMEIRACLASSEPYTHON
![Page 116: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/116.jpg)
ométodoextrato() da classeConta para imprimir, alémdonúmero e o saldo, os dadosdo
cliente.PodemoscriarumaContasemumCliente?EumClientesemumaConta?
2. (Opcional) Crie uma classe que represente uma data, com dia, mês e ano. Crie um atributodata_aberturanaclasseConta.CrieumanovacontaefaçatestesnoconsoledoPython.
3. (Desafio) Crie uma classe Historico que represente o histórico de uma Conta seguindo o
exemplodaapostila.FaçatestesnoconsoledoPythoncriandoalgumascontas,fazendooperaçõeseporúltimomostrandoohistóricodetransaçõesdeumaConta.Fazsentidocriarumobjetodotipo
HistoricosemumaConta?
Agora, além de funcionar como esperado, nosso código não permite criar uma conta sem osatributosquedefinimosanteriormente.Discutacomseuscolegaseinstrutorasvantagensdaorientaçãoaobjetosatéaqui.
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
JáconheceoscursosonlineAlura?
8.13EXERCÍCIO:PRIMEIRACLASSEPYTHON 109
![Page 117: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/117.jpg)
CAPÍTULO9
Umdosproblemasmaissimplesquetemosnonossosistemadecontaséqueométodosaca()permite
sacarmesmoqueosaldosejainsuficiente.Aseguir,você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):self.saldo-=valor
Vamostestarnossocódigo:
minha_conta=Conta('123-4','João',1000.0,2000.0)minha_conta.saca(500000)
Olimitedesaqueéultrapassado.Podemosincluirumifdentrodométodosaca()paraevitara
situação que resultaria em uma conta em estado inconsistente, com seu saldo menor do que zero.Fizemosissonocapítulodeorientaçãoaobjetosbásica.
Apesardemelhorarbastante,aindatemosumproblemamaisgrave:ninguémgarantequeousuáriodaclassevai sempreutilizarométodoparaalterarosaldodaconta.Ocódigoaseguiralteraosaldodiretamente:
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
110 9MODIFICADORESDEACESSOEMÉTODOSDECLASSE
![Page 118: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/118.jpg)
Essecódigoiriaserepetiraolongodetodanossaaplicação,oupior,alguémpodeesquecerdefazeressacomparaçãoemalgummomento,deixandoacontaemumasituaçãoinconsistente.Amelhorformaderesolver issoseriaforçarquemusaaclasseContaa invocarométodosaca(), para assimnão
permitiroacessodiretoaoatributo.
EmlinguagenscomoJavaeC#,bastadeclararqueosatributosnãopossamseracessadosdeforadaclasse 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áusando a classe, e sim por ela mesma, centralizando essa responsabilidade e facilitando futurasmudançasnosistema.
O Python não utiliza o termoprivate, que é ummodificador de acesso e também chamado demodificador de visibilidade. No Python, inserimos dois underscores ('__') ao atributo paraadicionarmosestacaracterística:
classPessoa:
def__init__(self,idade):self.__idade=idade
Dessamaneira,nãoconseguimosacessaroatributoidadedeumobjetodotipoPessoaforada
classe:
pessoa=Pessoa(20)pessoa.idadeTraceback(mostrecentcalllast):File"<stdin>",line1,in<module>AttributeError:'Pessoa'objecthasnoattribute'idade'
OinterpretadoracusaqueoatributoidadenãoexistenaclassePessoa.Masissonãogaranteque
ninguémpossaacessá-lo.NoPython,nãoexistematributos realmenteprivados, ele apenasalertaquevocênãodeveriatentaracessaresteatributo,oumodificá-lo.Paraacessá-lo,fazemos:
p._Pessoa__idade
Ao colocar o prefixo __ no atributo da classe, o Python apenas renomeia '__nome_do_atributo'para '_nomeda_Classe\_nome_do_atributo', como fez em __idade para _Pessoa__idade. Qualquerpessoaquesaibaqueosatributosprivadosnãosãorealmenteprivados,mas"desconfigurados",podelere atribuir umvalor ao atributo "privado" diretamente.Mas fazerpessoa._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__',
9MODIFICADORESDEACESSOEMÉTODOSDECLASSE 111
![Page 119: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/119.jpg)
'__repr__','__setattr__','__sizeof__','__str__','__subclasshook__','__weakref__']
Reparequenãoexistenenhumatributo__idadenoobjetopessoa.Agoravamostentaratribuirum
valorpara__idade:
pessoa.__idade=25
Epa,seráqueoPythondeveriadeixarissoocorrer?Vamosacessaravariávelnovamenteeverseamodificaçãorealmenteaconteceu:
print(pessoa._Pessoa__idade)#20
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__idadeapareceu, jáquefoi inicializadoemtempodeexecuçãoeé
diferentedo__idadedaclasse.Issopodegerarmuitaconfusãoeerros!OPythontambémtemuma
maneiradelidarcomesteproblemaatravé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 significado para o interpretador quando usado emnome de atributos, mas entre programadores Python é uma convenção que deve ser respeitada. Oprogramadoralertaqueesseatributonãodeveseracessadodiretamente:
def__init__(self,idade):self._idade=idade
Umatributocomapenasumunderscoreéchamadodeprotegido,masquandousadosinaliza quedevesertratadocomoumatributo"privado",fazendocomqueacessá-lodiretamentepossaserperigoso.
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 é,
112 9MODIFICADORESDEACESSOEMÉTODOSDECLASSE
![Page 120: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/120.jpg)
acessandoseusmétodos.Algomuitomaiseducadoquemexerdiretamenteemumatributoquenãoéseu.
Melhorainda!OdiaqueprecisarmosmudarcomoérealizadoumsaquenanossaclasseConta,
adivinheondeprecisaríamosmodificar?Apenasnométodosaca(),oquefazplenosentido.
Oquecomeçamosavernessecapítuloéaideiadeencapsular,istoé,'esconder'todososmembrosdeumaclasse(comovimosacima),alémdeescondercomofuncionamasrotinas(nocasomé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 uma maneira 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):
9.1ENCAPSULAMENTO
9.1ENCAPSULAMENTO 113
![Page 121: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/121.jpg)
self._titular=titularself._saldo=saldo
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ãousadosemmuitaslinguagensdeprogramaçãoorientadaaobjetosparagarantiroprincípiodoencapsulamentodedados.Oencapsulamentodedadosévistocomooagrupamentodedados com os métodos que operam nesses dados. Esses métodos são, obviamente, o getter pararecuperarosdadoseosetterparaalterarosdados.Deacordocomesseprincípio,osatributosdeumaclassesãotornadosprivadosparaocultá-loseprotegê-losdeoutrocódigo.
Infelizmente,éumacrençageneralizadaqueumaclassePythonadequadadeveencapsularatributosprivadosusandogettersesetters.Assimqueumdessesprogramadoresintroduziremumnovoatributo,elefarácomquesejaumavariávelprivadaecriará"automaticamente"umgettereumsetterparaessesatributos.
Os programadores de Java irão torcer o nariz quando lerem o seguinte: Amaneira pythônica deintroduzir atributos é torná-los públicos.Vamos explicar issomais tarde. Primeiro, demonstramos noexemploaseguir,comopodemosprojetarumaclasse,damesmamaneirausadanoJava,comgettersesettersparaencapsularumatributoprotegido:
classConta:
def__init__(self,saldo):self._saldo=saldo
defget_saldo(self):returnself._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.0conta2.get_saldo()#300.0conta3.set_saldo(conta1.get_saldo()+conta2.get_saldo())conta3.get_saldo()#500.0
114 9.1ENCAPSULAMENTO
![Page 122: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/122.jpg)
Oquevocêachadaexpressão"conta3.set_saldo(conta1.get_saldo()+conta2.get_saldo())"?Éfeio,nãoé?Émuitomaisfácilescreverumaexpressãocomoaseguinte:
conta3.saldo=conta1.saldo+conta2.saldo
Talatribuiçãoémaisfácildeescrevere,acimadetudo,maisfácilde lerdoqueaexpressãocomgettersesetters.VamosreescreveraclasseContadeummodoPythônico,semgetteresemsetter:
classConta:
def__init__(self,saldo):self.saldo=saldo
Neste caso, não há encapsulamento e não seria um problema.Mas o que acontece se quisermosmudar a implementação no futuro? O leitor atento deve ter reparado que no exemplo anteriordeclaramos uma variável do tipo Conta com saldo negativo, e isso não deveria acontecer. Para
evitarmosessasituação,osetteréjustificadoparaacrescentaraseguintevalidação:
classConta:
def__init__(self,saldo):self.saldo=saldo
defset_saldo(self,saldo):if(saldo<0):print("saldonãopodesernegativo")else:self.saldo=saldo
Podemostestarissocom:
conta1=Conta(200.0)print(conta1.saldo)#200.0conta2=Conta(300.0)print(conta2.saldo)#300.0conta3=Conta(100.0)conta3.set_saldo(-100.0)"saldonãopodesernegativo"print(conta3.saldo)#100.0
Mas há um problema, pois caso projetemos nossa classe com atributo público e sem métodos,acabamosquebrandoainterface:
conta1=Conta(100.0)conta1.saldo=-100.0
ÉporissoqueemJavarecomenda-sequeaspessoasusemsomenteatributosprivadoscomgettersesetters,paraquesejapossívelalteraraimplementaçãosemprecisaralterarainterface.OPythonofereceuma solução bastante parecida para este problema. A solução é chamada de properties. Mantemosnossosatributosprotegidosedecoramosnossosmétodoscomumdecoratorchamadoproperty.
9.1ENCAPSULAMENTO 115
![Page 123: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/123.jpg)
Aclassecomumapropriedadeficaassim:
classConta:
def__init__(self,saldo=0.0):self._saldo=saldo
@propertydefsaldo(self):returnself._saldo
@saldo.setterdefsaldo(self,saldo):if(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]ção
tivessesidochamadade"func",teríamosqueanotá[email protected].
PARASABERMAIS:DECORATOR
Umdecorador, oudecorator é um padrão de projeto de software que permite adicionar umcomportamento 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étodosextras,como 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._foofoo=property(foo)
Portanto, a função foo() é substituída pela propriedade property(foo). Então, se você usa
@foo.setter(),oquevocêestáfazendoéchamarométodoproperty().setter
116 9.1ENCAPSULAMENTO
![Page 124: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/124.jpg)
Desta maneira, podemos chamar esses métodos sem os parênteses, como se fossem atributospúblicos.É uma formamais elegante de encapsular nossos atributos.Vamos testar criar uma conta edepoisatribuirumvalornegativoaosaldo:
conta=Conta(1000.0)conta.saldo=-300.0"saldonãopodesernegativo"
Vejaquetemosumresultadomuitomelhordoqueusargettersandsettersdiretamente.Chamamosoatributopelasuaspropriedades,quepodemcontervalidações,enossosatributosestãosinalizadoscomo'protegidos'atravésdo'_'.
Aindapodemosmodificarosaldo,eistodeveriaserfeitoatravésdosmétodospúblicossaca()e
deposita().Então,[email protected]équestionável.Devemosapenasmanipular
osaldoatravésdosmétodossaca()edeposita(),nãoprecisamosdapropertysaldo.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, apropriedadesetter do saldonãodeveria ter sido criada, já quequeremosque todosusemosmétodosdeposita()esaca().
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
Nossobancotambémquercontrolaraquantidadedecontasexistentesnosistema.Comopoderíamosfazerisso?Bom,acadainstânciacriada,deveríamosincrementaressetotal:
total_contas=0conta=Conta(300.0)total_contas=total_contas+1conta2=Conta(100.0)
VocêpodetambémfazerocursodatadessaapostilanaCaelum
9.2ATRIBUTOSDECLASSE
9.2ATRIBUTOSDECLASSE 117
![Page 125: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/125.jpg)
total_contas=total_contas+1
Aquivoltaoproblemaderepetirummesmocódigoparatodaaplicação,alémdeterquelembrardeincrementaravariáveltotal_contas todavezapós instanciarumaConta.Comototal_contas
temvínculocomaclasseConta,eledeveserumatributocontroladopelaclasse,quedeveincrementá-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.Seriainteressanteque
essavariávelfosseprópriadaclasse,sendoúnicaecompartilhadaportodososobjetosdamesma.Dessamaneira,quandoamesmafossemudadaatravésdeumobjeto,ooutroenxergariaomesmovalor.Parafazerisso,vamosinicializaravariávelnaclasse,portanto,foradométodo__init__():
classConta:
total_contas=0
def__init__(self,saldo):self._saldo=saldoself.total_contas+=1
Vejaquesaldo é umatributode instância, etotal_contas umatributode classe.Vamosfazerumtesteparaversenossototal_contasfuncionacomoesperado:
c1=Conta(100.0)print(c1.total_contas)#1c2=Conta(200.0)print(c2.total_contas)#1
Criamosduasinstâncias,emesmoassimototal_contasnãomudou.Issoaconteceporcontado
self.total_contasserdiferentedetotal_contasdaclasse.Comototal_contaséumavariável
daclasse,devemoschamá-lapelaclasse:
classConta:
total_contas=0
def__init__(self,saldo):self._saldo=saldoConta.total_contas+=1
Etestamos:
c1=Conta(100.0)print(c1.total_contas)#1
118 9.2ATRIBUTOSDECLASSE
![Page 126: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/126.jpg)
c2=Conta(200.0)print(c2.total_contas)#2
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()ointerpretadorreclama,poisnãopassamosainstância:
c1=Conta(100.0)print(c1.get_total_contas())#1c2=Conta(200.0)print(c2.get_total_contas())#2Conta.get_total_contas()Traceback(mostrecentcalllast):File<stdin>,line17,in<module>Conta.get_total_contas()TypeError:get_total_contas()missing1requiredpositionalargument:'self'
Vejaqueoerroavisaquefaltapassaroargumentoself.Nãopodemoschamá-lo,poiselenãoestá
vinculado a qualquer instância de Conta. Além disso, ummétodo requer uma instância como seu
primeiroargumento:
c1=Conta(100.0)c2=Conta(200.0)
9.2ATRIBUTOSDECLASSE 119
![Page 127: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/127.jpg)
Conta.get_total_contas(c1)#2
Passamosainstânciac1deContaefuncionou.Masessanãoéamelhormaneiradesechamar
ummétodo.Achamadanãoéclarae levaum tempopara ler eentenderoquea terceira linhadessecó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 ummétodo que seja chamado via classe e via instância sem anecessidadedepassarareferênciadesteobjeto.OPythonresolveissousandométodosestáticos.
Métodos estáticos nãoprecisamdeuma referência, não recebemumprimeiro argumento especial(self).Écomoumafunçãosimplesque,poracaso,residenocorpodeumaclasseemvezdeserdefinidanoníveldomódulo.
Para que um método seja considerado estático, basta adicionarmos um decorador, assim comofizemoscomaspropriedadesnocapítuloanterior.Odecoradorsechama@staticmethod:
@staticmethoddefget_total_contas():returnConta._total_contas
Testando,vemosquefuncionatantochamadoporuminstânciaquantopelaclasse:
c1=Conta(100.0)c1.get_total_contas()#1c2=Conta(200.0)c2.get_total_contas()#2Conta.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é,umobjetodotipoclass,queporconvençãonomeamoscomo 'cls'. Eles podem ser chamados via instância ou pela classe e utilizam um outro decorador, o
9.3MÉTODOSDECLASSE
120 9.3MÉTODOSDECLASSE
![Page 128: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/128.jpg)
@classmethod:
classConta:
_total_contas=0
def__init__(self):type(self)._total_contas+=1
@classmethoddefget_total_contas(cls):returncls._total_contas
Epodemostestar:
c1=Conta(100.0)c1.get_total_contas()#1c2=Conta(200.0)c2.get_total_contas()#2Conta.get_total_contas()#2
Noiníciopodeparecerconfusoqualusar:@staticmethodou@classmethod?Issonãoétrivial.
Métodos de classe servem para definir ummé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 fundamental emOrientaçãoaObjetos.Veremosqueclassespodem ter filhaseaproveitarocódigodasclassesmães.Ummétododeclassepodemudaraimplementação,ouseja,podeserreescritopelaclassefilha.Jáosmétodosestáticosnãopodemserreescritospelasfilhas,jáquesã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 atributos
9.4PARASABERMAIS-SLOTS
9.4PARASABERMAIS-SLOTS 121
![Page 129: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/129.jpg)
incluindooprefixounderscore emseusnomes, seguindoa convençãoutilizadapelosprogramadores.Alémdisso,utilizamospropertiesparaacessaremodificarnossosatributos.MascomoPythonéumalinguagemdinâmica,nada impedequeusuáriosdenossaclasseConta criematributos em tempode
execução,fazendo,porexemplo:
>>>conta.nome="minhaconta"
Essecódigonãoacusaerroenossacontaficaabertaamodificaçõesferindoasegurançadaclasse.Paraevitar isso,podemosutilizarumavariávelembutidanoPythonchamada__slots__, quepode
guardarumalistadeatributosdaclassedefinidospornós:
classConta:
__slots__=['_numero','_titular','_saldo','_limite']
def__init__(self,numero,titular,saldo,limite=1000.0):#inicializaçãodosatributos
#códigoomitido
Agora,quandotentamosadicionarumatributonaclasse,recebemosumerro:
>>>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__.Aoatribuirumvalor
para__slots__,ointerpretadordoPythonvaientenderquequeremosexcluiro__dict__daclasse
Contanãosendopossívelcriaratributos,ouseja,impossibilitandoadicionaratributosaodicionárioda
classequeé responsávelporarmazenaratributosde instância.Portanto, tentarchamarvars(conta)
tambémvaigerarumerro:
>>>vars(conta)Traceback(mostrecentcalllast):File<stdin>,line1,in<module>TypeError:vars()argumentmusthave__dict__attribute
Embora__slots__ sejamuitoutilizadopara nãopermitir queusuários denossas classes criem
outrosatributos,essanãoésuaprincipalfunçãonemomotivodesuaexistência.Oqueaconteceéqueo
122 9.4PARASABERMAIS-SLOTS
![Page 130: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/130.jpg)
__dict__ desperdiça muita memória. Imagine um sistema grande, com milhões de instâncias de
Conta-teríamos,consequentemente,milhõesdedicionáriosdeclassearmazenandoseusatributosde
instância.OPythonnãopodesimplesmentealocarumaquantidadeestáticadememórianacriaçãodeobjetosparaarmazenartodososatributos.Porisso,consomemuitamemóriaRAMsevocêcriarmuitosobjetos.
Para contornar este problema é que se usa o __slots__, e este é seu principal propósito. O
__slots__avisaoPythonparanãousarumdicionárioeapenasalocarespaçoparaumconjuntofixo
deatributos.
Programadoresviramumareduçãodequase40a50%nousodeRAMusandoessatécnica.
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
1. Adicioneomodificadordevisibilidadeprivado(doisunderscores:__)paracadaatributoemétodo
dasuaclasseConta.
classConta:
def__init__(self,numero,titular,saldo,limite=1000.0):self.__numero=numeroself.__titular=titularself.__saldo=saldoself.__limite=limite
TentecriarumaContaemodificaroulerumdeseusatributos"privados".Oqueacontece?
2. Sabendo que no Python não existem atributos privados, como podemos modificar e ler essesatributos?Éumaboapráticafazerisso?
Dica: teste os comandos print(conta.__numero) e print(conta._Conta__numero. O que
Seuslivrosdetecnologiaparecemdoséculopassado?
9.5EXERCÍCIOS:
9.5EXERCÍCIOS: 123
![Page 131: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/131.jpg)
ocorre?
3. Modifiqueoacessopara'protegido'seguindoaconvençãodoPythonemodifiqueoprefixo__por
apenasumunderscore_. Criemétodos de acesso em sua classe Conta através do decorator
@property.
classConta:
def__init__(self,numero,titular,saldo,limite=1000.0):self._numero=numeroself._titular=titularself._saldo=saldoself._limite=limite
@propertydefsaldo(self):returnself._saldo
@saldo.setterdefsaldo(self,saldo):if(saldo<0):print("saldonãopodesernegativo")else:self._saldo=saldo
#restantedosmétodosescritosnoexercícioanterior
4. Crienovamenteumacontaeacesseemodifiqueseusatributos.Oquemudou?
Dica:tenteoscomandosnaseguinteordem:print(conta._numero),conta._numero='50'e
print(conta._numero).Oqueocorre?
5. Modifique sua classe Conta de modo que não seja permitido criar outros atributos além dos
definidosanteriormenteutilizando__slots__.
classConta:
__slots__=['_numero','_titular','_saldo','_limite']
def__init__(self,numero,titular,saldo,limite=1000.0):self._numero=numeroself._titular=titularself._saldo=saldoself._limite=limite
6. (Opcional)AdicioneumatributoidentificadornaclasseConta.Esseidentificadordeveterum
valorúnicoparacadainstânciadotipoConta.AprimeiraContainstanciadatemidentificador1,a
segunda2,eassimpordiante.
classConta:
identificador=1
def__init__(self,numero,titular,saldo,limite=1000.0):#códigoomitido
124 9.5EXERCÍCIOS:
![Page 132: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/132.jpg)
self.identificador=Conta.identificadorConta.identificador+=1
9.5EXERCÍCIOS: 125
![Page 133: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/133.jpg)
CAPÍTULO10
OPycharmé especialmenteútil durante a criaçãode códigoque envolveorientação aobjetos.Nestepróximo passo, criaremos umnovo projeto, desta vez para conter todo o conteúdo necessário para aimplementaçãodanossaaplicaçãodebanco.
Novamente no Pycharm, abra uma janela chamada Create Project aparecerá. É nela que
definimostodasasconfiguraçõesnecessárias.
Podemoscriarumnovoprojetoaqualquermomento.Parafazerisso,bastaclicaremFile->New
ProjectnomenusuperiordajanelaprincipaldoPyCharm.
Primeiro,especificamosonomedoprojeto-nonossocasoseráapenasbanco.NotequeoPyCharm
PYCHARMEORIENTAÇÃOAOBJETOS
10.1CRIANDOUMPROJETO
126 10PYCHARMEORIENTAÇÃOAOBJETOS
![Page 134: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/134.jpg)
sugereumlocalpadrãoparasalvaroprojeto.VocêpodeaceitarestelocalouconfigurarmanualmentenocampoLocation.Vamosoptarpelocaminhopadrão.Aofazerisso,aIDEvaicriarumapastachamada
PyCharmProjectsnasuapastahome.
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 com outras bibliotecas instaladas em seu computador. Por fim,clicamosemCreateenossoprojetoécriado.
Nosso projeto tem uma estrutura padrão. A pasta venv é o ambiente isolado do sistema
operacional.Nela contémaversãodo interpretadorPythonque selecionamosna criaçãodoprojeto eseus módulos embutidos (builtins) - você pode checar isso na pasta lib . A qualquer momento
podemosincluirnovasbibliotecasaoprojeto.
Vamos iniciar nosso projeto criando a classeConta.Antes, precisamos criar uma pasta raiz do
projeto.VáemFile->New->Directory.
Definimosumnomeparanossodiretórioe clicamosem 'OK'.Vamoscriarumdiretóriochamadosrc:
10.1CRIANDOUMPROJETO 127
![Page 135: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/135.jpg)
Paradefini-locomopastaraiz,vamosclicarcomobotãodireitodomousenodiretório,navegaratéMarkDirectoryaseescolherSourcesRoot.Vocênotaráqueapastamudadacorcinzaparaazul.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Agoravamoscriaroarquivoconta.pyqueconteránossaclasseConta.Paraisso,cliquecomo
Agoraéamelhorhoradeaprenderalgonovo
10.2CRIANDOUMACLASSE
128 10.2CRIANDOUMACLASSE
![Page 136: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/136.jpg)
botãodireitodomouseemsrceváemNew->PythonFile:
Digiteonomedoarquivoecliqueem'OK'.Vamosnomearoarquivocomoconta:
Umanovaabavaiaparecercomonomedomóduloquecriamos,àdireitadomenudenavegaçãodoprojeto. Vamos começar a escrever o código de nossa classe Conta. Você vai notar que quando
começamosadigitarapalavraclassoPyCharmvaiteoferecersugestõesparavocêescolher.Comece
escrevendoapalavraclass(exemplo:'cl')eelevaiterminardedigitarpravocê:
Vamos agora escrever ométodo__init__().Aqui tambémoPycharmvai nos ajudar.Escreva
apenas"defi"eoPyCharmvaitedarnovamentesugestões:
10.2CRIANDOUMACLASSE 129
![Page 137: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/137.jpg)
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 janeladoconsolevaiabrirabaixodoarquivo
conta:
Vamosimportaromódulocontacomocomandofromsrc.contaimportConta, instanciar
umaContaeacessarseusatributos:
10.3EXECUTANDOCÓDIGO
130 10.3EXECUTANDOCÓDIGO
![Page 138: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/138.jpg)
Reparequeoconsoletambémpossuiaferramentadeautocomplete.Parareiniciá-lobastaclicarnoprimeiroíconedomenuesquerdodoconsole.
AIDEtambémpermiteabriroterminaleusaromodointerativoparatestes.OatalhoparaabriroterminaléALT+F12.OPythonConsoledoPycharmémaisaconselhávelpara issoeo terminalé
maisutilizadoparainstalarnovaslibsaoseuprojeto.
Masusaremosoconsoleapenasparatestes.Vamosexecutarocódigodiretamentedonossoarquivoconta. Para isso precisamos acrescentar a condicional if __name__ == '__main__': e fazer os
mesmostestesquefizemosnoconsoledentrodestacondiçãoif.Bastavocêescrever"main"edigitar
ENTERqueoPycharmcriaacondicionalparavocê:
if__name__=='__main__':
AgoravamosinstanciareimprimirosatributosdeumaContacomofizemosutilizandooPython
Console.Nãoesqueçadeutilizarafunçãoprintnahorademostrarosatributos,já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ãodireitodomousenointeriordoarquivo
conta e escolha a opçãoRun'conta'.Ou ainda, digite o atalho CTRL+Shift+F10 que vai ter o
mesmoefeito.Depoisdeterrodadopelaprimeiravez,paravocêrodarnovamentebastaclicarnoíconedeumapequenasetaverdenomenusuperiordaIDE:
10.3EXECUTANDOCÓDIGO 131
![Page 139: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/139.jpg)
Vamos criar nosso primeiro método. Primeiro, dentro da condicional main , vamos digitar a
seguintelinhadecódigo:
conta.deposita(100.0)
Seexecutarmosessecódigo,onossoprogramaquebrajáqueaclasseConta aindanãopossuio
métododeposita().Paracriá-lo,coloqueocursordomousenapalavra"deposita"euseoatalhoALT
+ENTER,váriassugestõesdoPycharmirãoaparecer.CliqueemAddmethoddeposita()toclass
Conta:
EoPycharmvaicriaradeclaraçãodométodoparavocê:
Viucomoéfácilerápido?Agorabastatrocarapalavraparamporvalor,apagarapalavrapass
eadicionaraimplementaçãodométodo:
10.4CRIANDOMÉTODOS
132 10.4CRIANDOMÉTODOS
![Page 140: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/140.jpg)
defdeposita(self,valor):self._saldo+=valor
No próximo exercício, vamos criar nosso primeiro projeto do banco e nossa classe Conta
utilizandooPycharmepraticaroqueaprendemosdeorientaçã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,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
1. AbraoPycharmeváemFile->NewProject.Ajanelaabaixovaiaparecer.Troqueapalavra
untitledpelonomedonossoprojetoqueserábanco:
EditoraCasadoCódigocomlivrosdeumaformadiferente
10.5EXERCÍCIO-CRIANDOPROJETOBANCONOPYCHARM
10.5EXERCÍCIO-CRIANDOPROJETOBANCONOPYCHARM 133
![Page 141: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/141.jpg)
VerifiqueseaversãodoPythonestácorretaemBaseinterpreterecliqueemOK.
2. Nomenuesquerdovaiapareceraestruturadoprojeto.Vamosdefinirumapasta raizonde ficarãonossosarquivosdecódigopython.CliquecomobotãodireitonapastabancoeescolhaaopçãoNewFolder.Umanovajanelavaiaparecerparavocêentrarcomonomedodiretório,digitesrceOK:
3. Após isso, clicamos com o botão direito na pasta src e selecionamos Mark Directory as ->SourcesRoots para avisar o PyCharmque esta pasta será umdiretório fonte de nosso projeto,
ondeficarãonossosarquivos.py.
Reparequeapastaficarádacorazuldepoisdeexecutardestaação:
4. Agora vamos criar nossa classe Conta que ficará no arquivo conta.py. Vamos fazer isso
utilizandoumatalhodoPyCharm.ColoqueocursordomousenapastasrcedigiteALT+Insert.EscolhaaopçãoPythonFile.Umanovajanelavaiabrir,digite"conta"ecliqueemOK.
134 10.5EXERCÍCIO-CRIANDOPROJETOBANCONOPYCHARM
![Page 142: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/142.jpg)
5. Oarquivoseráabertoaesquerda.Vamoscomeçaracriarnossaclasse.AoescrevermosafunçãoinitaprópriaIDEvaimostrarasopçõesemumajanela,bastaclicarqueeleauto-completaparavocêjácomaargumento'self'.AdicioneosatributosdeumaContacomofizemosnoexercíciodocapítulo
anterior:
classConta:
def__init__(self,numero,titular,saldo,limite):self._numero=numeroself._titular=titularself._saldo=saldoself._limite=limite
Aproveiteacrieaspropertiesdecadaatributo.AbusedoCTRL+ESPAÇOparaaIDEautocompletar
paravocê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émfacilitaesta
criação,bastadigitarapalavra'main'eapertarCTRL+ESPAÇOqueaestruturadoiféconstruída
paravocê:
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
atalhoCtrl+Shift_F10.Ou ainda escolher a opção da barra de ferramentas com o símbolo de
playdacorverde.Oresultadovaiaparecernoconsole,najanelainferiordaIDE.
10.5EXERCÍCIO-CRIANDOPROJETOBANCONOPYCHARM 135
![Page 143: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/143.jpg)
8. Crieosmétodosdeposita(),saca(),extrato() etransfere_para() como fizemosno
últimoexercício.AproveiteosrecursosdaIDEqueaprendemosparacriartodosessesmétodos.Apropriedadesetterdosaldoénecessária?
9. Crieduascontasetesteosmétodosquevocêcriounoexercícioanterior.
10. (Opcional)Crieumarquivopythonchamadocliente.pyecrieaclasseClientecomnome,
sobrenomeecpf.TesteocódigopassandoumclientecomotitulardeumConta.Aproveitee
adicionealgunsmétodosaela.
VejaqueaIDEfacilitabastantenahoradodesenvolvimentoeganhamostempotambémrodandooscriptdiretamentenoPyCharm.
136 10.5EXERCÍCIO-CRIANDOPROJETOBANCONOPYCHARM
![Page 144: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/144.jpg)
CAPÍTULO11
Como toda empresa, nosso banco possui funcionários. Um funcionário tem um nome, 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==senha:print("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
11.1REPETINDOCÓDIGO?
11HERANÇAEPOLIMORFISMO 137
![Page 145: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/145.jpg)
Existeumjeitoderelacionarmosumaclassedetalmaneiraqueumadelasherdatudoqueooutratem. Isto é uma relação de herança, uma relação entre classe 'mãe' e classe 'filha'. No nosso caso,gostaríamosdefazercomqueGerentetivessetudoqueumFuncionariotem,gostaríamosqueela
fosseumaextensãodeFuncionario.Fazemosissoacrescentandoaclassemãeentreparentesesjuntoa
classefilha:
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émherde
osatributosdefinidosnaclasseFuncionario,poisumGerenteéumFuncionário.
ComoaclasseGerente já possui ummétodo__init__() comoutros atributos, ométododa
classe Funcionario é sobrescrito pelo Gerente. Se queremos incluir os mesmos atributos deinstância de Funcionario em um Gerente , devemos chamar o método __init__() de
Funcionariodentrodomé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
138 11.1REPETINDOCÓDIGO?
![Page 146: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/146.jpg)
DizemosqueaclasseGerenteherdatodososatributosemétodosdaclassemãe,nonossocaso,a
Funcionario.ComoPythontemtipagemdinâmica,precisamosgarantirissoatravésdoconstrutorda
classe.Alémdesenhaeqtd_funcionariospassamostambémosatributosnome,cpfesalario
quetodofuncioná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, podemos chamar estemétododa classe
mãecomofizemosnoexemploacimaoupodemosutilizarummétododoPythonchamadosuper():
classGerente(Funcionario):
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. O
super() é usado para fazer referência a superclasse, a classe mãe - no nosso exemplo a classe
Funcionario.
11.1REPETINDOCÓDIGO? 139
![Page 147: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/147.jpg)
PARASABERMAIS:SUPERESUBCLASSE
AnomenclaturamaisencontradaéqueFuncionarioéasuperclassedeGerente,eGerenteéasubclasse deFuncionario.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 classe
Presidente pode estender diretamente de Funcionario. Fique claro que essa é uma relação de
negócio.SeDiretor vai estender deGerente ou não, vai depender, para você,Diretor é um
Gerente?
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Todofimdeano,osfuncionáriosdonossobancorecebemumabonificação.Osfuncionárioscomunsrecebem10%dovalordosalárioeosgerentes,15%.
JáconheceoscursosonlineAlura?
11.2REESCRITADEMÉTODOS
140 11.2REESCRITADEMÉTODOS
![Page 148: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/148.jpg)
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())
O resultado aqui será 500.Não queremos essa resposta, pois o gerente deveria ter 750 de bônusnesse caso. Para consertar isso, uma das opções seria criar um novo método na classe Gerente,
chamado,porexemplo,get_bonificacao_do_gerente().Oproblemaéque teríamosdoismétodos
emGerente,confundindobastantequemforusaressaclasse,alémdequecadaumgerenciariauma
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
Agora, ométodo está correto para oGerente. Refaça o teste e veja que o valor impresso é o
correto(750):
gerente=Gerente('José','222222222-22',5000.0,'1234',0)print(gerente.get_bonificacao())
Utilizeométodovars()paraacessarosatributosdeGerenteeverqueaclasseherdatodosos
atributosdeFuncionario:
funcionario=Funcionario('João','111111111-11',2000.0)print(vars(funcionario))
gerente=Gerente('José','222222222-22',5000.0,'1234',0)print(vars(gerente))
11.2REESCRITADEMÉTODOS 141
![Page 149: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/149.jpg)
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,poisrealmentealteramososeucomportamento.Todavia,podemosinvocá-lonocasodeestarmosdentrodaclasse.
ImaginequeparacalcularabonificaçãodeumGerente, devemos fazer igual ao cálculodeum
Funcionario,adicionando1000.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 a novabonificação.Para evitar isso, o
get_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() de uma superclassede
Gerente.Nocaso,elelogovaiencontraressemétodoemFuncionario.
Essaéumapráticacomum,poisemmuitoscasosométodoreescritogeralmentefazalgoamaisqueométododaclassemãe.Chamarounãoométododecimaéumadecisãoedependedoseuproblema.Algumasvezes,nãofazsentidoinvocarométodoquereescrevemos.
Para escrever uma classe utilizando o Python 2, é preciso acrescentar a palavra 'object' quandodefinimosumaclasse:
classMinhaClasse(object):
11.3INVOCANDOOMÉTODOREESCRITO
142 11.3INVOCANDOOMÉTODOREESCRITO
![Page 150: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/150.jpg)
pass
Issoaconteceporquetodaclasseéfilhadeobject -queéchamadaamãede todasasclasses.NoPyhton, todaclasseherdadeobject.NoPython3,nãoprecisamosacrescentaroobject,masnãoquerdizerqueestaclasseeaherançanãoexistam,apenasqueamesmaé implícita.Quandocriamosumaclassevaziaeutilizamosométododir()parachecaralistadeseusatributos,reparamosqueelanãoé
vazia:
classMinhaClasse():pass
if__name__=='__main__':mc=MinhaClasse()print(dir(mc))
Gerandoasaí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__']
Todos estes atributos são herdados da classe object e podemos reescrever qualquer um deles nanossa subclasse. Todos eles são os conhecidos métodos 'mágicos' (começam e iniciam com doisunderscores,eporestemotivo,tambémchamadosdedunders).
Vimosocomportamentodo__init__(),__new__()edo__dict__.Outrosmétodosmágicos
famosossão__str__()e__repr__()-métodosqueretornamarepresentaçãodoobjetocomouma
string.Quandochamamosprint(mc)temosasaída
<__main__.MinhaClasseobjectat0x7f11c1f59a58>
Esseéomodelopadrãode impressãodeumobjeto, implementadonaclasseobject.A função
print() na verdade usa a string definida pelo método __str__() de uma classe. Vamos
reescreverestemé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émretornaumastring,epodemosutilizarafunçãorepr()para
checarseuretorno:
11.3INVOCANDOOMÉTODOREESCRITO 143
![Page 151: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/151.jpg)
classMinhaClasse():pass
if__name__=='__main__':mc=MinhaClasse()print(repr(mc))
Quevaigeraramesmasaídapadrãodo__str__():
<__main__.MinhaClasseobjectat0x7f11c1f59a58>
Masdiferentedo__str__(), não é comumsobrescrever estemétodo.Ele é sobrescrito quando
precisamosutilizá-lojuntocomafunçãoeval()doPython.Afunçãoeval()recebeumastringe
tentaexecutaressastringcomoumcomandodoPython.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.OPythonvaichamar
entãoométodo__repr__()daclassePonto,queretornaastring"Ponto(2,3)"jáquep1.x=1
ep1.y=2.Aopassá-ladeargumentoparaafunçãoeval(),teremos:p2=eval('Ponto(2,3)).
Comoafunçãoeval()vai tentarexecutaressastring comoumcomandoPythonválidoele terá
sucesso,eportantop2seráumanovainstânciadaclassePontocomp2.x=2ep2.y=3.
Para concluir, é importante entender que tanto__str__() quanto__repr__() retornam uma
string que representaoobjeto,mas compropósitosdiferentes.Ométodo__str__() é utilizado
para apresentar mensagens para os usuários da classe, de maneira mais amigável. Já o método
144 11.3INVOCANDOOMÉTODOREESCRITO
![Page 152: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/152.jpg)
__repr__()éusadopararepresentaroobjetodemaneiratécnica,inclusivepodendoutilizá-locomo
comandoválidodoPython,comovimosnoexemplodaclassePonto.
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__(), por
exemplo, serve para executar a adição de dois objetos e é chamada sempre quando fazemos aoperaçãodeadição(obj+obj)utilizandoooperador'+'.Porexemplo,quandofazemos1+1no
Python,oqueointerpretadorfazéchamarométodo__add__()daclasseint.Vimosqueuma
listtambémimplementaométodo__add__(),jáqueaoperaçãodeadiçãoédefinidaparaesta
classe:
>>>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 taismé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?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
11.4PARASABERMAIS-MÉTODOSMÁGICOS
VocêpodetambémfazerocursodatadessaapostilanaCaelum
11.5POLIMORFISMO
11.4PARASABERMAIS-MÉTODOSMÁGICOS 145
![Page 153: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/153.jpg)
OqueguardaumavariáveldotipoFuncionario?UmareferênciaparaumFuncionario,nuncao
objetoemsi.
Naherança,vimosquetodoGerenteéumFuncionario,poiséumaextensãodeste.Podemos
nos referir a um Gerente como sendo um Funcionario . Se alguém precisa falar com um
Funcionariodobanco,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 um mé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 conseguimospassar umGerente para ummétodo que "recebe" umFuncionario
como 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.
146 11.5POLIMORFISMO
![Page 154: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/154.jpg)
Qual será o valor resultante? Não importa que dentro do método registra() do
ControleDeBonificacoesrecebaFuncionario.Quandoelereceberumobjetoquerealmenteéum
Gerente,oseumétodoreescritoseráinvocado.Reafirmando:nãoimportacomonosreferenciamosaumobjeto,ométodoqueseráinvocadoésempreoqueédele.
No dia emque criarmos uma classeSecretaria, por exemplo, que é filha deFuncionario,
precisaremosmudaraclasseControleDeBonificacoes?Não.BastaaclasseSecretariareescrever
osmétodosquelhepareceremnecessários.Éexatamenteesseopoderdopolimorfismo,juntamentecomareescritademétodo:diminuiroacoplamentoentreasclasses,paraevitarquenovoscódigosresultememmodificaçõeseminúmeroslugares.
ReparequequemcriouControleDeBonificacoespodenunca ter imaginadoacriaçãodaclasse
Secretaria ouEngenheiro. Contudo, não será necessário reimplementar esse controle em cada
novaclasse:reaproveitamosaquelecódigo.
Pensardestamaneiraemlinguagenscomtipagemestáticaéomaiscorreto,jáqueasvariáveissãotipadas e garantem, através do compilador, que o método só funcionará se receber um tipoFuncionario.Masnãoéoqueaconteceem linguagensde tipagemdinâmicacomoPython.Vamos
suporquetemosumaclassepararepresentarosclientesdobanco:
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 que
acontece:
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ãopossuioatributo
get_bonificacao. Portanto, aqui não importa se o objeto recebidonométodoregistra() é um
Funcionario,masseelepossuiométodoget_bonificacao().
Ométodoregistra() utiliza ummétododa classeFuncionario e, portanto, funcionará com
11.5POLIMORFISMO 147
![Page 155: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/155.jpg)
qualquer instância de uma subclasse de Funcionario ou qualquer instância de uma classe que
implementeométodoget_bonificacao().
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()else:print('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 forma destring) - e
verificaseoobjetopossuiaqueleatributo,ouseja,seoatributoestácontidono__dict__doobjeto.
Então,fazemosapergunta:get_bonificacao()éatributodeFuncionario?Sesim,entranobloco
ifepodemoschamarométodotranquilamente,evitandoerros.
Agora,setentarmoschamarométodoregistra()passandoumClienterecebemosasaída:
'Cliente'objecthasnoattribute'get_bonificacao
Portanto,otipopassadoparaométodoregistra()nãoimportaaqui,esimseoobjetopassado
implementa ou não o método get_bonificacao() . Ou seja, basta que o objeto atenda a um
determinadoprotocolo.
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ão o tipo dele.A interface é o conjunto demétodos públicos de uma classe.No caso danossa classe ControleDeBonificacoes, o método registra() espera um objeto que possua o
métodoget_bonificacao(),enãoumobjetodotipoFuncionario.
148 11.5POLIMORFISMO
![Page 156: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/156.jpg)
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(pato.grasna())
ganso=Ganso()print(ganso.grasna())
Quegeraasaída:
quack!quack!
Vocêdeveescreverocódigoesperandosomenteumainterfacedoobjeto,nãoumtipodeobjeto.NocasodanossaclasseControleDeBonificacoes,ométodoregistra()esperaumobjetoquepossua
omé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,deixaoerroestourar
nafrentedoprogramador.
AmaneiraPythônicaparagarantiraconsistênciadosistemanãoéverificarostiposeatributosdeumobjeto,maspressuporaexistênciadoatributonoobjetoetratarumaexceção,casoocorra,atravésdocomandotry/except:
try:self._total_bonificacoes+=obj.get_bonificacao()exceptAttributeErrorase:print(e)
Estamospedindoaointerpretadorpara tentarexecutara linhadecódigodentrodocomandotry
(tentar).Casoocorraalgumerro,elevaitrataresteerrocomocomandoexcepteexecutaralgo,como
11.6DUCKTYPING
11.6DUCKTYPING 149
![Page 157: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/157.jpg)
imprimiroerro(similaraoexemplo).Nãosepreocupedeentenderosdetalhessobreestecódigoeousodotry/exceptnestemomento,teremosumcapítulosóparafalardeles.
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émuitoforteeissoacabafazendocomqueoprogramadordasclassesfilhas tenhaqueconhecera implementaçãodaclassemãeevice-versa-ficadifícilfazerumamudançapontualnosistema.
Por exemplo, imagine se tivermos quemudar algo na nossa classeFuncionario,masnão
quiséssemosquetodososfuncionáriossofressemamesmamudança.Precisaríamospassarporcadauma das filhas de Funcionario verificando se ela se comporta como deveria ou se devemos
sobrescreverotalmé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()queatualizaacontadeacordo
comataxapercentual:
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 a
ContaPoupanca deve atualizar-se com o triplo da taxa. Além disso, a ContaCorrente deve
reescrever o método deposita() a fim de retirar uma taxa bancária de dez centavos de cada
depósito.
11.7EXERCÍCIO:HERANÇAEPOLIMORFISMO
150 11.7EXERCÍCIO:HERANÇAEPOLIMORFISMO
![Page 158: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/158.jpg)
CrieaclasseContaCorrentenoarquivoconta.pyefaçacomqueelasejasubclasse(filha)daclasseConta.
classContaCorrente(Conta):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áriade
dezcentavos:
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ódulo
foriguala__main__paraexecutarmosnoconsolenoPyCharm.Instancieessasclasses,atualize-as
evejaoresultado:
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ção
11.7EXERCÍCIO:HERANÇAEPOLIMORFISMO 151
![Page 159: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/159.jpg)
maisamigáveldeumContacontendotodososseusatributos.
def__str__(self):return"DadosdaConta:\nNumero:{}\nTitular:{}\nSaldo:{}\nLimite:{}".format(self._numero,self._titular,self._limite,self._saldo)
Testechamandoométodoprint(cc).
5. Vamoscriarumaclassequesejaresponsávelporfazeraatualizaçãodetodasascontasbancáriasegerarumrelatóriocomosaldoanterioresaldonovodecadaumadascontas.Napastasrc,criea
classeAtualizadorDeContas:
```pythonclassAtualizadorDeContas:
def__init__(self,selic,saldo_total=0):self._selic=selicself._saldo_total=saldo_total
#propriedades
defroda(self,conta):print("SaldodaConta:{}".format(conta.saldo))self._saldo_total+=conta.atualiza(self._selic)print("SaldoFinal:{}".format(self._saldo_total))
Dica:Paraovalorde_saldo_totalseratualizadocorretamente,atualizetodasasfunçõesatualiza
nasoutrasclassespararetornaremovalorcorretocomreturnself._saldo
Nãoesqueçadefazeros_imports_necessáriosparaocódigofuncionar!
1. Na'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))
2. (opcional)SevocêprecisassecriarumaclasseContaInvestimento,eseumétodoatualiza()
fossecomplicadíssimo,vocêprecisariaalteraraclasseAtualizadorDeContas?
3. (opcional,Trabalhoso)CrieumaclasseBancoquepossuiumalistadecontas.Reparequeemuma
listadecontasvocêpodecolocartantoContaCorrentequantoContaPoupanca.Crieummétodo
adiciona()queadicionaumacontanalistadecontas;ummétodopegaConta()quedevolvea
contaemdeterminadaposiçãodalistaeoutropegaTotalDeContas()queretornaototaldecontas
na lista.Depois teste criandodiversas contas, insira-asnoBanco e depois, comum laçofor,
152 11.7EXERCÍCIO:HERANÇAEPOLIMORFISMO
![Page 160: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/160.jpg)
percorra todas as contas doBanco para passá-las como argumento para ométodoroda() do
AtualizadorDeContas.
4. (opcional) Que maneira poderíamos implementar o método atualiza() nas classes
ContaCorrenteeContaPoupançapoupandoreescritadecódigo?
5. (opcional)E se criarmosumaclassequenãoé filhadeConta e tentar passar uma instância no
métodorodadeAtualizadorDeContas?Comoqueaprendemosatéaqui, comopodemosevitar
queerrosaconteçamnestescasos?
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma 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:
Seuslivrosdetecnologiaparecemdoséculopassado?
11.8CLASSESABSTRATAS
11.8CLASSESABSTRATAS 153
![Page 161: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/161.jpg)
print('instânciade{}nãoimplementaométodoget_bonificacao()'.format(self.__class__.__name__))
#propriedades
Nossométodoregistra() recebeumobjetodequalquer tipo.Todavia, estamos esperandoque
seja um Funcionario já que este implementa ométodo get_bonificacao(), isto é, podem ser
objetos do tipo Funcionario e qualquer de seus subtipos. Dessa forma, qualquer subclasse que
eventualmente venha ser escrita, sem prévio conhecimento do autor da ControleDeBonificacao
podemserimplementadas.
EstamosutilizandoaquiaclasseFuncionarioparaopolimorfismo.Senãofosseporela,teríamos
umgrandeprejuízo:precisaríamoscriarummétodoregistra() para receber cadaumdos tiposde
Funcionario,umparaGerente,umparaDiretor,etc.Reparequeperderessepoderémuitopior
doqueapequenavantagemqueaherançatrazemherdarcódigo.
Todavia,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? Esta pergunta é bastante relevante, já que
instanciar um Funcionario pode gerar um objeto que não faz sentido no nosso sistema. Nossa
empresatemapenasDiretores,Gerentes,Secretários,etc...Funcionarioéapenasumaclasse
queidealizaumtipo,defineapenasumrascunho.
Vejamosumoutrocasoemquenãofazsentidoterumobjetodedeterminadotipo,apesardaclasseexistir.ImagineaclassePessoaeduasfilhas:PessoaFisicaePessoaJuridica.Quandopuxamos
umrelatóriodenossosclientes(umalistadeobjetosdetipoPessoa,porexemplo),queremosquecada
umdelessejaouumaPessoaFisicaouumaPessoaJuridica.AclassePessoa,nessecaso,estaria
sendo usada apenas para ganhar o polimorfismo e herdar algumas coisas - não faz sentido permitirinstanciá-la.
Paraonossosistema,éinadmissívelqueumobjetosejaapenasdotipoFuncionario(podeexistir
umsistemaemquefaçasentidoterobjetosdotipoFuncionarioouapenasPessoa,mas,nonosso
caso,não).Pararesolveressesproblemas,temosasclassesabstratas.
UtilizaremosumamódulodoPythonchamadoabcquepermitedefinirmosclassesabstratas.UmaclasseabstratadeveherdardeABC(AbstractBaseClasses).ABCéasuperclasseparaclassesabstratas.
Umaclasseabstratanãopodeserinstanciadaedeveconterpelomenosummétodoabstrato.Vamosverissonaprática.
VamostornarnossaclasseFuncionarioabstrata:
154 11.8CLASSESABSTRATAS
![Page 162: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/162.jpg)
importabc
classFuncionario(abc.ABC):
#métodosepropriedades
Definimos nossa classe Funcionario como abstrata. Agora vamos tornar nosso método
get_bonificacao()abstrato.Ummétodoabstratopodeter implementação,masnãofazsentidoem
nosso sistema, portanto vamos deixá-lo sem implementação. Para definirmos um método abstrato,utilizamosodecorador@abstractmethod:
classFuncionario(abc.ABC):
@abc.abstractmethoddefget_bonificacao(self):pass
Agora,setentarmosinstanciarumobjetodotipoFuncionario:
if__name__=='__main__':f=Funcionario()
Acusaumerro:
TypeError:Can'tinstantiateabstractclassFuncionariowithabstractmethodsget_bonificacao
ApesardenãoconseguirinstanciaraclasseFuncionario,conseguimosinstanciarsuasfilhasque
sã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ãoconseguimosinstanciarumasubclassedeFuncionario semimplementarométodoabstrato
get_bonificacao().Agora,tornamosométodoget_bonificacao()obrigatórioparatodoobjetoque é subclasse de Funcionario. Caso venhamos a criar outras classes, como Secretaria e
11.8CLASSESABSTRATAS 155
![Page 163: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/163.jpg)
Presidente , que sejam filhas de Funcionario , seremos obrigados e criar o método
get_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
#outrosmétodosepropriedades
2. Torneométodoatualiza()abstrato:
classConta(abc.ABC):
#códigoomitido
@abc.abstractmethoddefatualiza():pass
3. TenteinstânciarumaConta:
if__name__=='__main__':c=Conta()
Oqueocorre?
4. Agora, 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:
11.9EXERCÍCIOS-CLASSESABSTRATAS
156 11.9EXERCÍCIOS-CLASSESABSTRATAS
![Page 164: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/164.jpg)
ci=ContaInvestimento('123-6','Maria',1000.0)
7. Não conseguimos instanciar uma ContaInvestimento que herda Conta sem implementar o
método abstrato atualiza() . Vamos criar uma implementação dentro da classe
ContaInvestimento:
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
ContaInvestimento. Faça com que o tipo também seja impresso quando usamos a função
print().
11.9EXERCÍCIOS-CLASSESABSTRATAS 157
![Page 165: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/165.jpg)
CAPÍTULO12
ImaginequeumSistemadeControledoBancopodeseracessado,alémdosGerentes,pelosDiretoresdoBanco.TeríamosumaclasseDiretor.
classDiretor(Funcionario):
defautentica(self,senha):#verificaseasenhaconfere
EaclasseGerente:
classGerente(Funcionario):
defautentica(self,senha):#verificaseasenhaconfereetambémseoseudepartamentotemacesso
ReparequeométododeautenticaçãodecadatipodeFuncionariopodevariarmuito.Masvamos
aosproblemas.Considere oSistemaInterno e seu controle: precisamos receber umDiretor ou
Gerentecomoargumento,verificarseeleseautenticaecolocá-lodentrodosistema.
Vimos que podemos utilizar a função hasattr() para verificar se um objeto possui ométodo
autentica():
classSistemaInterno:
deflogin(self,funcionario):if(hasattr(obj,'autentica')):#chamamétodoautenticaelse:#imprimemensagemdeaçãoinválida
Maspodemosesquecer,nofuturo,quandomodelarmosaclassePresidente (que tambéméum
funcionário e autenticável), de implementar ométodoautentica().Não faz sentido colocarmos o
mé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
HERANÇAMÚLTIPLAEINTERFACES
158 12HERANÇAMÚLTIPLAEINTERFACES
![Page 166: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/166.jpg)
EasclassesDiretor,GerenteequalqueroutrotipodeFuncionarioAutenticavelqueviera
existir em nosso sistema bancário passaria a estender de FuncionarioAutenticavel. Repare que
FuncionarioAutenticaveléfortecandidataaclasseabstrata.Maisainda,ométodoautentica()
poderiaserummétodoabstrato.
Ousodeherançasimplesresolveocaso,masvamosaumaoutrasituaçãoumpoucomaiscomplexa:todososclientestambémdevempossuiracessoaoSistemaInterno.Oquefazer?
Umaopçãoéfazerumaherançasemsentidopararesolveroproblema,porexemplo,fazerCliente
estender deFuncionarioAutenticavel. Realmente resolve o problema,mas trará diversos outros.
ClientedefinitivamentenãoéumFuncionarioAutenticavel.Sevocêfizerisso,oClienteterá,
por exemplo, ummétodoget_bonificacao(), um atributo salario e outros membros que não
fazemomenorsentidoparaestaclasse.
Precisamos,pararesolveresteproblema,arranjarumaformadereferenciarDiretor,Gerentee
Clientedeumamesmamaneira,istoé,acharumfatorcomum.
Seexistisseumaformanaqualessasclassesgarantissemaexistê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,podemosnosreferenciaraum
GerentecomoumAutenticavel.
ComoPythonadmiteherançamúltipla,podemoscriaraclasseAutenticavel:
classAutenticavel:
defautentica(self,senha):#verificaseasenhaconfere
EfazerGerente,DiretoreClienteherdaremessaclasse:
classGerente(Funcionario,Autenticavel):#códigoomitido
classDiretor(Funcionario,Autenticavel):#códigoomitido
classCliente(Autenticavel):#códigoomitido
Ouseja,GerenteeDiretoralémdefuncionáriossãoautenticáveis!Assim,podemosutilizaro
12HERANÇAMÚLTIPLAEINTERFACES 159
![Page 167: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/167.jpg)
SistemaInternoparafuncionáriosautenticáveiseclientes:
classSistemaInterno:
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çássemosaestenderesse sistema, logoencontraríamosalgumascomplicações.Emumbancodeverdade, as divisões entre gerentes, diretores e clientes nem sempre são claras. Um Cliente, por
exemplo,podeserumFuncionario,umFuncionariopode teroutras subcategoriascomofixose
temporários.
NoPython,épossívelqueumaclasseherdedeváriasoutrasclasses.Poderíamos,porexemplo,criarumaclasseA, que será superclassedasclassesBeC.Aherançamúltipla não émuitodifícil de
entender se uma classe herda de várias classes que possuem propriedades completamente diferentes,masascoisasficamcomplicadasseduassuperclassesimplementamomesmométodoouatributo.
SeasclassesBeCherdaremaclasseAeaclasseDherdarasclassesBeC,easclassesBe
Ctêmummétodom2(),qualmétodoaclasseDherda?
classA:defm1(self):print('métododeA')
classB(A):defm2(self):print('métododeB')
classC(A):defm2(self):print('métododeC')
12.1PROBLEMADODIAMANTE
160 12.1PROBLEMADODIAMANTE
![Page 168: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/168.jpg)
classD(B,C):pass
Essaambiguidadeéconhecidacomooproblemadodiamante,ouproblemadolosango,ediferenteslinguagensresolvemesseproblemademaneirasdiferentes.OPythonsegueumaordemespecíficaparapercorrerahierarquiadeclasseseessaordeméchamadadeMRO:MethodResolutionOrder(OrdemdeResoluçãodeMétodos).
Toda classe temumatributo__mro__ que retorna uma tupla de referências das superclasses na
ordemMRO-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ão
encontreemB,vaiprocuraremCesóentãoprocuraremA-eporúltimonaclasseobject.
Tambémpodemosacessaroatributo__mro__atravésdométodomro()chamadopelaclasseque
retornaumalistaaoinvé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:
12.1PROBLEMADODIAMANTE 161
![Page 169: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/169.jpg)
d=D()d.m1()d.m2()
Saída:
métododeAmétododeB
Felizmente,afunçãosuper()sabecomolidardeformainteligentecomherançamúltipla.Seusá-
ladentrodométodo,todososmé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
162 12.1PROBLEMADODIAMANTE
![Page 170: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/170.jpg)
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Se usarmos herança múltipla, geralmente é uma boa ideia 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 para
acrescentarafuncionalidadedeserautenticável,ouseja,paraherdarseumétodoautentica.
NossaclasseAutenticaveljásecomportacomoumMix-In.NoPythonnãoexisteumamaneira
especí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
Agoraéamelhorhoradeaprenderalgonovo
12.2MIX-INS
12.2MIX-INS 163
![Page 171: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/171.jpg)
Epodemosmisturá-losnasclassesdenossosistema:
classGerente(Funcionario,AutenticavelMixIn,HoraExtraMixIn):pass
classDiretor(Funcionario,AutenticavelMixIn):pass
classCliente(AutentivavelMixIn):pass
classEscriturario(Funcionario,AtentimentoMixIn):pass
Reparequenossosmix-ins não têm ummétodo__init__() .Muitosmix-ins apenas fornecem
mé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árioqueherdamFuncionarioe
algunsmix-ins.
Essaéumadasabordagensdeseusarherançamúltipla,maselaébastantedesencorajada.Casovocêutilize, opte pormix-ins sabendo de suas desvantagens.Usando em sistemas grandes, podemocorrercolisõescomnomesdemétodos,métodossubstituídosacidentalmente,hierarquiadeclassespoucoclarae 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 paradigmaorientadoaobjetos,queé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:
12.3PARASABEMAIS-TKINTER
164 12.3PARASABEMAIS-TKINTER
![Page 172: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/172.jpg)
AimagemacimafoiretiradadolivroPythonFluentedeLucianoRamalho-mostrandopartedo
complicadomodelodeclassesutilizandoherançamúltipladopacoteTkinter.Asetasrepresentamo
MROquedeveiniciarnaclasseText.AclasseTextimplementaumcampodetextoeditáveletem
muitasfuncionalidadespróprias,alémdeherdarmuitosmétodosdeoutrasclasses.
UmaoutraclassedopacotequenãoaparecenestediagramaéaLabel,utilizadaparamostrarum
texto ou bitmap na tela. Você pode testar no Pycharm, aproveitando a ferramenta de autocomplete,chamandoTkinter.Label.eaIDEvai temostrar181sugestõesdeatributosemumaúnicaclasse!
Ouvocêpodeutilizarafunçãohelp()parachecaraorigemdecadaumdeles.
fromtkinterimport*
help(Label)
Essepacotetemmaisde20anoseéumexemplodecomoaherançamúltiplaerautilizadaquandoosprogramadoresnãoconsideravamsuasdesvantagens.Apesardamaioriadasclassessecomportaremcomomix-ins,opadrãodenomenclaturanãoerautilizado.Felizmente,oTkinter é um framework
estável.
1. Nossobancoprecisatributardinheirodealgunsbensquenossosclientespossuem.ParaissovamoscriarumaclasseTributavelcomummétodoquedevolveoimpostosobreaconta:
classTributavel:
defget_valor_imposto(self):pass
Lemosessaclassedaseguintemaneira:"Todosquequiseremsertributáveisprecisamsaberretornarovalordoimposto".Algunsbenssãotributáveiseoutrosnão.Porexemplo:ContaPoupancanãoé
tributável,jáparaContaCorrentevocêprecisapagar1%dacontaeoSeguroDeVida temuma
12.4EXERCÍCIOS-MIX-INS
12.4EXERCÍCIOS-MIX-INS 165
![Page 173: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/173.jpg)
faixafixade50reaismais5%dovalordoseguro.
2. TransformeaclasseTributavelemummix-in:
classTributavelMixIn:
defget_valor_imposto(self)pass
3. Faça a classe ContaCorrente herdar da classe TributavelMixIn e implemente o método
"exigido"peloMixIn:
classContaCorrente(Conta,TributavelMixIn):#códigoomitido
defget_valor_imposto(self):returnself._saldo*0.01
4. CrieaclasseSeguroDeVidaquevaiherdardeTributavelMixIn.Crieseusrespectivosatributos
eimplementeométododoMixIn:
classSeguroDeVida(TributavelMixIn):
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
5. VamoscriaraclasseManipuladorDeTributaveisemumarquivochamadomanipulador.py.Essa
classedeveterummétodochamadocalcula_impostos() que recebeuma listade tributáveis e
retornaototaldeimpostoscobrados:
classManipuladorDeTributaveis:
defcalcula_impostos(self,lista_tributaveis):total=0fortinlista_tributaveis:total+=t.get_valor_imposto()
returntotal
6. Ainda no arquivo manipulador.py , vamos testar o código. Crie alguns objetos de
ContaCorrente e de SeguroDeVida. Em seguida, crie uma lista de tributáveis e insira seus
objetosnela.InstancieumManipuladorDeTributaveisechameométodocalcula_impostos()
passandoalistadetributá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')
166 12.4EXERCÍCIOS-MIX-INS
![Page 174: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/174.jpg)
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)
print(total)
Vimosqueherançamúltiplapodeserperigosa,esenossosistemacrescerpodegerarmuitaconfusãoeconflitodenomesdemétodos.Umamaneiramaiseficaznestescasoséusarclassesabstratascomointerfaces,queveremosaseguir.
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
OPythonnãopossuiumapalavra reservada interface.Mesmosemumapalavra reservadaparaamesma,todaclassepossuiumainterface.Interfacessãoosatributospúblicosdefinidos(queemPythonsãotantoatributosquantométodos)emumaclasse-issoincluiosmétodosespeciaiscomo__str__()
e__add__().
Uma interface vista como um conjunto de métodos para desempenhar um papel é o que osprogramadoresdaSmallTalkchamavamdeprotocolo,eestetermofoidisseminadoemcomunidadesdeprogramadoresdelinguagensdinâ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.
EditoraCasadoCódigocomlivrosdeumaformadiferente
12.5INTERFACES
12.5INTERFACES 167
![Page 175: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/175.jpg)
Ométodo__str__(),porexemplo,éesperadoqueretorneumarepresentaçãodoobjetoemforma
destring.Nadaimpededefazermosoutrascoisasdentrodométodocomodeletaralgumconteúdoou
fazer algum cálculo; ao invés de retornarmos apenas a string. Mas há um entendimento prévio
comumdoqueestemé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 decompilação.
A partir do Python 2.6, a definição de interfaces utilizando omóduloABC é uma soluçãomaiselegantedoqueosmix-ins.NossaclasseAutenticavelpodeserumaclasseabstratacomométodo
abstratoautentica():
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çãodasenha.DevolveTrueseasenhaconfere,eFalsecasocontrário."""
EnossasclassesGerente,DiretoreClienteherdariamaclasseAutenticavel.Masquala
diferençadeherdarmuitosmix-insemuitasABCs?Realmente,aquinãohágrandediferençaevoltamosaoproblemaanteriordosmix-ins-muitoacoplamentoentreclassesquegeraaherançamúltipla.
MasanovidadedasABCséseumétodoregister().AsABCsintroduzemumasubclassevirtual,
quesãoclassesquenãoherdamdeumaclassemassãoreconhecidaspelosmétodosisinstance()e
issubclass() . Ou seja, nosso Gerente não precisa herdar a classe Autenticavel , basta
registrarmoselecomoumaimplementaçãodaclasseAutenticavel.
Autenticavel.register(Gerente)
Etestamososmétodosisinstance()eissubclass()comumainstânciadeGerente:
gerente=Gerente('João','111111111-11',3000.0)
168 12.5INTERFACES
![Page 176: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/176.jpg)
print(isinstance(Autenticavel))print(issubclass(Autenticavel))
Quevaigerarasaída:
TrueTrue
OPython não vai verificar se existe uma implementação dométodoautentica em Gerente
quando registrarmos a classe. Ao registrarmos a classe Gerente como uma Autenticavel ,
prometemosaoPythonqueaclasseimplementafielmenteanossainterfaceAutenticaveldefinida.O
PythonvaiacreditarnissoeretornarTruequandoosmétodosisinstance()eissubclass()foremchamados.Sementirmos,ouseja,nãoimplementarmosométodoautentica()emGerente, uma
exceçãoserálançadaquandotentarmoschamarestemétodo.
VejamosumexemplocomaclasseDiretor.Nãovamosimplementarométodoautentica()e
registrarumainstâ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 classesabstratas justifica a utilização deste tipo de verificação. A verificação não é de tipagem,mas se umobjetoestá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
12.5INTERFACES 169
![Page 177: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/177.jpg)
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. Classesabstratas complementam oduck typing, provendo umamaneira de definir interfaces quando técnicascomousarhasattr()sãoruinsousutilmenteerradas.Vocêpodelermaisarespeitonodocumentoda
PEP 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étodosconcretos,ou seja,nãoabstratos.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.Paraisso,vamoscriar uma classe Tributavel no módulo tributavel.py, e adicionar um método que devolve o
impostosobreaconta:
classTributavel:
defget_valor_imposto(self):pass
Lemosessaclassedaseguintemaneira:"todosquequiseremsertributáveisprecisamsaberretornarovalordoimposto".Algunsbenssãotributáveiseoutrosnão,ContaPoupancanãoétributável,já
paraContaCorrentevocêprecisapagar1%dacontaeoSeguroDeVidatemumafaixafixade50
reaismais5%dovalordoseguro.
2. TorneaclasseTributavelumaclasseabstrata:
importabc
classTributavel(abc.ABC):
defget_valor_imposto(self)pass
3. Ométodoget_valor_imposto()tambémdeveserabstrato:
importabc
12.6(OPCIONAL)EXERCÍCIOS-INTERFACESECLASSESABSTRATAS
170 12.6(OPCIONAL)EXERCÍCIOS-INTERFACESECLASSESABSTRATAS
![Page 178: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/178.jpg)
classTributavel(abc.ABC):
@abc.abstractmethoddefget_valor_imposto(self,valor):pass
4. Nada impede que os usuários de nossa classe tributavel implementem o métodoget_valor_impostodemaneiranãoesperadapornós.Então,vamosacrescentaradocumentação
utilizandodocstringqueaprendemosnocapítulodemódulos:
importabc
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:
classContaCorrente(Conta,Tributavel):#códigoomitido
defget_valor_imposto(self):returnself._saldo*0.01
7. Crie a classe SeguroDeVida, com os atributos valor, titular e numero_apolice, que
tambémdeve ser um tributável. Implementeométodoget_valor_imposto() de acordo coma
regradenegóciodefinidapeloexercício:
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
8. Vamos criar a classe ManipuladorDeTributaveis em um arquivo chamado
manipulador_tributaveis.py.Essaclassedeveterummétodochamadocalcula_impostos() que
recebeumaslistadetributáveiseretornaototaldeimpostoscobrados:
classManipuladorDeTributaveis:
defcalcula_impostos(self,lista_tributaveis):total=0fortinlista_tributaveis:total+=t.get_valor_imposto()
12.6(OPCIONAL)EXERCÍCIOS-INTERFACESECLASSESABSTRATAS 171
![Page 179: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/179.jpg)
returntotal
9. Nossas classes ContaCorrente e SeguroDeVida já implementam o método
get_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())
10. Crieuma listacomosobjetoscriadosnoexercícioanterior, instancieumobjetodo tipolist e
passealistachamandoométodocalcula_impostos().
if__name__=='__main__':
#códigoomitido
lista_tributaveis=[]lista_tributaveis.append(cc)lista_tributaveis.append(seguro)
mt=ManipuladorDeTributaveis()total=mt.calcula_impostos(lista_tributaveis)print(total)
11. Nosso código funciona, mas ainda estamos utilizando herança múltipla! Vamos melhorar nossocódigo.FaçacomqueContaCorrenteeSeguroDeVidanãomaisherdemdaclasseTributavel:
classContaCorrente(Conta):#códigoomitido
classSeguroDeVida:#códigoomitido
Vamos registrar nossas classes ContaCorrente e SeguroDeVida como subclasses virtuais de
Tributavel,demodoquefuncionecomoumainterface.
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)
172 12.6(OPCIONAL)EXERCÍCIOS-INTERFACESECLASSESABSTRATAS
![Page 180: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/180.jpg)
12. Modifiqueométodocalcula_impostos()daclasseManipuladorDeTributaveisparachecarse
oselementosdalistassãotributáveisatravésdométodoisinstance().Casoumobjetoda lista
nã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ícioanteriorevejasetudocontinuafuncionando.
13. ContaPoupanca nãoéum tributável.Experimente instanciarumaContaPoupanca, adicionar a
listadetributá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?
14. (Opcional) Agora, além de ContaCorrente e SeguroDeVida , nossa ContaInvestimento
tambémdeveserumtributável,cobrando3%dosaldo.InstancieumaContaInvestimento.
classContaInvestimento(Conta):
defatualiza(self,taxa):self._saldo+=self._saldo*taxa*5
defget_valor_imposto(self):returnself._saldo*0.03
RegistreaclasseContaInvestimentocomotributável.AdicioneaContaInvestimentocriadana
lista de tributáveis do exercício anterior e calcule o total de impostos através doManipuladorDeTributaveis.
if__name__=="__main__":
#códigoomitido
ci=ContaInvestimento('Ana','123-0')ci.deposita(100.0)Tributavel.register(ContaInvestimento)
12.6(OPCIONAL)EXERCÍCIOS-INTERFACESECLASSESABSTRATAS 173
![Page 181: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/181.jpg)
lista_tributaveis.append(ci)mt=ManipuladorDeTributaveis()
total=mt.calcula_impostos(lista_tributaveis)print(total)
Nestecapítulo,aprendemossobreherançamúltiplaesuasdesvantagensmesmoutilizandomix-ins.Alémdisso,aprendemosautilizarclassesabstratascomointerfacesregistrandoasclasseseevitandoosproblemas com a herança múltipla. Agora nossa classe abstrata Tributavel funciona como um
protocolo. No capítulo sobre omódulo collections, veremos na prática alguns conceitos vistos nestecapítulo.
174 12.6(OPCIONAL)EXERCÍCIOS-INTERFACESECLASSESABSTRATAS
![Page 182: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/182.jpg)
CAPÍTULO13
Voltando às contas que criamos no capítulo 8, o que aconteceria ao tentarmos chamar o métodosaca()comumvalorforadolimite?Osistemamostrariaumamensagemdeerro,masquemchamou
ométodosaca()nãosaberáqueissoaconteceu.
Comoavisaràquelequechamouométododequeelenãoconseguiufazeraquiloquedeveria?
Osmétodosdizemqualocontratoqueelesdevemseguir.Se,aotentarchamarométodosacar(),
elenãoconseguefazeroquedeveria,eleprecisa,aomenos,avisaraousuárioqueosaquenãofoifeito.
Vejanoexemploabaixo:estamosforçandoumaContaaterumvalornegativo,istoé,aestarem
umestadoinconsistentedeacordocomanossamodelagem.
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étodo,enãoaprópriaclasse!Portanto,nadamaisnaturalsinalizarqueumerroocorreu.
AsoluçãomaissimplesutilizadaantigamenteéademarcaroretornodeummétodocomobooleaneretornarTruesetudoocorreudamaneiraplanejada,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áquinadeautoatendimento
EXCEÇÕESEERROS
13EXCEÇÕESEERROS 175
![Page 183: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/183.jpg)
poderiaviraliberaraquantiadesejadadedinheiro,mesmoseosistemanãotivesseconseguidoefetuaromé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çãoseriaalteraroretornodebooleanparaint e retornarocó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 outros 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.
Paraaprendermososconceitosbásicosdasexceptions doPython, crieumarquivo 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')
176 13EXCEÇÕESEERROS
![Page 184: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/184.jpg)
if__name__=='__main__':print('iníciodomain')metodo1()print('fimdomain')
Reparequeduranteaexecuçãodoprogramachamamosometodo1()eesse,porsuavez,chamao
metodo2().Cadaumdessesmétodospodetersuasprópriasvariáveislocais,istoé:ometodo1()não
enxergaasvariáveisdeclaradasdentrodoexecutáveleporaíemdiante.
ComooPython(emuitasoutraslinguagens)fazisso?Todainvocaçãodemétodoéempilhadoemumaestruturadedadosqueisolaaáreaememóriadecadaum.Quandoummétodotermina(retorna),elevoltaparaométodoqueo invocou.Eledescobre issoatravésdapilhadeexecução (stack): bastaremoveromarcadorqueestánotopodapilha:
Porém, o nosso metodo2() propositalmente possui um enorme problema: está acessando uma
referênciaparaNonequandooíndiceforiguala6!
Rodeocódigo.Qualasaída?Oqueissorepresenta?Oqueelaindica?
Essasaídaéorastrodepilha,oTraceback.Éumasaídaimportantíssimaparaoprogramador-tantoque,emqualquerfórumoulistadediscussão,écomumosprogramadoresenviarem,juntamentecomadescriçãodoproblema,essaTraceback.Masporqueissoaconteceu?
13EXCEÇÕESEERROS 177
![Page 185: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/185.jpg)
O sistema de exceções do Python funciona da seguintemaneira: quando uma exceção é lançada(raise),ointerpretadorentraemestadodealertaevaiverseométodoatualtomaalgumaprecauçãoaotentarexecutaresse trechodecódigo.Comopodemosver,ometodo2() não tomanenhumamedida
diferentedoquevimosatéagora.
Como o metodo2() não está tratando esse problema, o interpretador para a execução dele
anormalmente, sem esperar ele terminar, e volta um stackframe para baixo, onde será feita novaverificação:"ométodo1() está se precavendodeumproblema chamadoAttributeError?"Se a
respostaénão,elevoltaparaoexecutável,ondetambémnãoháproteção,eointerpretadormorre.
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éinteressantequecadaexceçãonoPythontenhaumtipo,afinalelapodeteratributosemétodos.
Adicioneumtry/except emvoltadofor, 'pegando' umAttributeError.Oqueo código
imprime?
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')
178 13EXCEÇÕESEERROS
![Page 186: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/186.jpg)
Aoinvésdefazerotryemtornodoforinteiro,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')
13EXCEÇÕESEERROS 179
![Page 187: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/187.jpg)
Faça o mesmo, retirando o try/except novamente e colocando-o em volta da chamada do
metodo1().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:
13.1EXCEÇÕESETIPOSDEERROS
180 13.1EXCEÇÕESETIPOSDEERROS
![Page 188: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/188.jpg)
NameError
Quandotentamosacessarumavariávelquenãoexiste.
print(x)
Traceback(mostrecentcalllast):File"<stdin>",line1,in<module>NameError:name'x'isnotdefined
Noexemploacima,tentamosimprimirxsemdefini-loantes.Esteerrotambémémuitocomumde
ocorrerquandotentamosacessarumavariávellocalemumcontextoglobal.
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
Quandotentamosacessarumelementodeumasequênciacomumíndicemaiorqueototaldeseuselementosmenosum.
tupla=(1,2,3)print(tupla[3])
Traceback(mostrecentcalllast):
13.1EXCEÇÕESETIPOSDEERROS 181
![Page 189: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/189.jpg)
File"<stdin>",line2,in<module>IndexError:tupleindexoutofrange
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
Hámuitos outros erros de tempo de execução.Que tal dividir um número por zero? Será que ointerpretadorconseguefazeraquiloquenósdefinimosquenãoexiste?
n=2n=n/0
Traceback(mostrecentcalllast):File"<stdin>",line2,in<module>ZeroDivisionError:divisionbyzero
ReparequeumZeroDivisionErrorpoderiaserfacilmenteevitadocomumifquechecariaseo
denominador é diferente de zero, mas 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
Oconjuntode instruçõesdentrodoblocotry é executado (o interpretador tentará executar).Se
nenhumaexceçãoocorrer,ocomandoexceptéignoradoeaexecuçãoéfinalizada.Todavia,seocorrer
algumaexceçãoduranteaexecuçãodoblocotry,asinstruçõesremanescentesserãoignoradas,esea
exceçãolançadapreverumexcept,asinstruçõesdentrodoblocoexceptserãoexecutadas.
Ocomandotrypodetermaisdeumcomandoexceptparaespecificarmúltiplostratadorespara
JáconheceoscursosonlineAlura?
13.2TRATANDOEXCEÇÕES
182 13.2TRATANDOEXCEÇÕES
![Page 190: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/190.jpg)
diferentesexceções.Nomáximoumúnicotratadorseráativado.Tratadoressósãosensíveisàsexceçõeslevantadasnointeriordacláusulatry,enãoasquetenhamocorridonointeriordeoutrotratadornuma
mesmainstruçãotry.Umtratadorpodesersensívelamúltiplasexceções,desdequeasespecifiqueem
umatupla:
except(RuntimeError,TypeError,NameError):pass
Aúltimacláusulaexceptpodeomitironomedaexceção,funcionandocomoumcoringa.Nãoé
aconselhávelabusardesterecurso,jáqueissopodeescondererrosdoprogramadoredousuário.
Oblocotry/exceptpossuiumcomandoopcionalelseque,quandousado,devesercolocado
depoisdetodososcomandosexcept.Éumcomandoútilparacódigosqueprecisamserexecutadosse
nenhumaexceçã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. Por
exemplo:
raiseNameError('oi')Traceback(mostrecentcalllast):File"<stdin>",line1,in?NameError:oi
Oargumentoderaiseindicaaexceçãoaserlançada.Esseargumentodeveserumainstânciade
Exceptionouumaclassedealgumaexceção-umaclassequederivadeException.
Casovocêprecisedeterminarseumaexceçãofoi 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
13.3LEVANTANDOEXCEÇÕES
13.3LEVANTANDOEXCEÇÕES 183
![Page 191: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/191.jpg)
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.Onovocomportamento
simplesmentecriaoatributovalor.Classesdeexceçõespodemserdefinidasparafazerqualquercoisaquequalqueroutraclassefaz,masemgeralsãobemsimples,frequentementeoferecendoapenasalgunsatributosqueforneceminformaçõessobreoerroqueocorreu.
Aocriarummóduloquepodegerardiversoserros,umapráticacomumécriarumaclassebaseparaas exceções definidas por aquelemódulo, e as classes específicas para cada condição de erro comosubclassesdela:
classMeuErro(Exception):"""Classebaseparaoutrasexceções"""pass
classValorMuitoPequenoError(MeuErro):"""Élançadaquandoovalorpassadoémuitopequeno"""pass
classValorMuitoGrandeError(MeuErro):"""Élançadaquandoovalorpassadoémuitogrande"""pass
EssaéamaneirapadrãodedefinirexceçõesnoPython,masoprogramadornãoprecisaficarpresoaela.É comumquenovas exceções sejamdefinidas comnomes terminando em“Error”, semelhante amuitasexceçõesembutidas.
13.4DEFINIRUMAEXCEÇÃO
184 13.4DEFINIRUMAEXCEÇÃO
![Page 192: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/192.jpg)
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
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'
Reparequeoblocofinallyéexecutadoemtodososcasos.AexceçãoTypeError levantadapela
divisãodeduasstringsenãoétratadanoexcepteportantoérelançadadepoisqueofinallyéexecutado.
Emaplicaçõesreais,o finallyéútilpara liberar recursosexternos(comoarquivosouconexõesde
VocêpodetambémfazerocursodatadessaapostilanaCaelum
13.5PARASABERMAIS:FINALLY
13.5PARASABERMAIS:FINALLY 185
![Page 193: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/193.jpg)
rede),independentementedousodorecursotersidobemsucedidoounão.
NoPython,todasasexceçõessãoinstânciasdeumaclassederivadadeBaseException.Todavia,
ela não serve para ser diretamente herdada por exceções criadas por programadores. Para isso,utilizamosException,quetambéméfilhadeBaseException.
AbaixoestáahierarquiadeclassesdeexceçõesdoPython.Paramaisinformaçõessobrecadaumadelas,consulteadocumentaçã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|+--TabError+--SystemError
13.6ÁRVOREDEEXCEÇÕES
186 13.6ÁRVOREDEEXCEÇÕES
![Page 194: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/194.jpg)
+--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 chamada
ValueError,que jáfazpartedabibliotecapadrãodoPython,semprequeovalorpassadocomo
argumentoforinvá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 o
motivo.Vamosacrescentarumamensagemparadeixaroerromaisclaro:
defdeposita(self,valor):if(valor<0):raiseValueError('Vocêtentoudepositarumvalornegativo.')else:self._saldo+=valor
Obs.:modifiquetambémaimplementaçãodométododeposita()daclasseContaPoupancada
mesmamaneiraquefizemosnaclasseConta,lançandoumValueErrorcasoovalorpassadoseja
negativo.
3. Façaomesmoparaométodosaca()daclasseContaCorrente,afinaloclientetambémnãopode
sacarumvalornegativo.
defsaca(self,valor):if(valor<0):raiseValueError('Vocêtentousacarumvalornegativo.')else:self._saldo-=valor
4. Vamosvalidartambémqueoclientenãopodesacarumvalormaiordoqueosaldodisponívelemconta.CriesuaprópriaexceçãochamadaSaldoInsuficienteError.Napastasrc,crieoarquivo
13.7EXERCÍCIOS:EXCEÇÕES
13.7EXERCÍCIOS:EXCEÇÕES 187
![Page 195: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/195.jpg)
excecoes.pyeaclasseSaldoInsuficienteErrorquedeveherdardeRuntimeError.
classSaldoInsuficienteError(RuntimeError):pass
NométodosacadaclasseContaCorrente,vamosutilizarestanovaexceção:
classContaCorrente(Conta):#códigoomitido
defsaca(self,valor):if(valor<0):raiseValueError('Vocêtentousacarumvalornegativo.')if(self._saldo<valor):raiseSaldoInsuficienteError('Saldoinsuficiente.')self._saldo-=(valor+0.10)
Obs.:modifiquetambémaimplementaçãodométodosaca()daclasseConta,lançandooserros
ValueError e SaldoInsuficienteError da mesma maneira que fizemos na classe
ContaCorrente.
5. AgoracrieumaContaCorrenteechameométodosaca(),passandoumvalornegativo:
if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)
valor=-1000.0cc.saca(valor)
Oqueacontece?
6. Precisamostrataroerroparanãopararaexecuçãodoprograma.Utilizeumblocotry/exceptpara
isso:
if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)
valor=-1000.0
try:cc.saca(valor)print('Saquede{}realizadocomsucesso'.format(valor))exceptValueError:print('Ovalorasersacadodeveserumnúmeropositivo.')
Rodeoprogramaacimaevejaoqueacontece.
7. Agoratentesacarumvalormaiordoqueosaldo:
if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)
valor=5000.0
try:cc.saca(valor)print('Saquede{}realizadocomsucesso.'.format(valor))
188 13.7EXERCÍCIOS:EXCEÇÕES
![Page 196: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/196.jpg)
exceptValueError:print('Ovalorasersacadodeveserumnúmeropositivo.')
Oqueacontece?
8. ModiqueoprogramaefaçacomqueoerroSaldoInsuficienteErrornãosejalançadoquandoo
valorformaiordoqueosaldodaconta.
if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)
valor=5000.0
try:cc.saca(valor)print('Saquede{}realizadocomsucesso.'.format(valor))exceptValueError:print('Ovalorasersacadodeveserumnúmeropositivo.')exceptSaldoInsuficienteError:print('Vocênãopossuisaldosuficienteparaconcluirestaoperação.')
Nãoesqueçadefazerosimportsnecessários.
9. Façatestescomométododeposita().Tentedepositarumvalornegativoevejaoqueacontece.
if__name__=='__main__':cc=ContaCorrente('123-4','João',1000.0)
valor=-1000.0
try:cc.deposita(valor)print('Depósitode{}realizadocomsucesso.'.format(valor))exceptValueError:print('Ovaloraserdepositadodeveserumnúmeropositivo.')
10. (Desafio)Este código simula uma operação de saque feito por um caixa eletrônico e poderia serencapsuladoemumaclasseque representeocaixa.CrieumaclassechamadaCaixaEletronico
comosmétodosque representeasoperaçõesdedepósitoesaque.Depois, instancieumobjetodotipoCaixaEletronicoetesteseusmétodos.
13.7EXERCÍCIOS:EXCEÇÕES 189
![Page 197: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/197.jpg)
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
ErrosdesintaxeUmdoserrosmaiscomunséoSyntaxError.Geralmentesuasmensagensnãodizemmuito,amaiscomuméaSyntaxError:invalidsyntax.Poroutro lado,amensagem
diz o local onde o problema ocorreu. - onde o Python encontrou o problema. São descobertosquando o interpretador está traduzindo o código fonte para o bytecode. Indicamque há algo deerradocomaestruturadoprograma.Porexemplo:esquecerdefecharaspas,simplesouduplas,nahorade imprimirummensagem;esquecerdecolocardoispontos (":")aofinaldeuma 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ãomais difíceis de encontrarporqueointerpretadornãofornecenenhumainformaçãojáquenãosabeoqueoprogramadeveriafazer.Sãoerrosnaregradenegócio.Utilizarafunçãoprint()emalgunslugaresdocódigoonde
vocêsuspeitaqueestágerandooerropodeajudar.
OdepuradordoPython,opdb,éummóduloembutidoquefuncionacomoumconsoleinterativoondeépossívelrealizardebugdecódigospython.Vocêpodelermaisarespeitonadocumentação:https://docs.python.org/3/library/pdb.html
Seuslivrosdetecnologiaparecemdoséculopassado?
13.8OUTROSERROS
13.9PARASABERMAIS-DEPURADORDOPYTHON
190 13.8OUTROSERROS
![Page 198: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/198.jpg)
CAPÍTULO14
Objetivos:
conheceromódulocollectionsconheceromódulocollections.abc
No capítulo 5, vimos uma introdução das principais estruturas de dados do Python como listas,tuplas,conjuntosedicionários.TambémaprendemosemorientaçãoaobjetosquetudoemPythonéumobjeto,inclusiveestasestruturas.
O Python possui uma biblioteca chamada collections , que reúne outros tipos de dados
alternativosaojáapresentadosnocapítulo5.Essestipostrazemnovasfuncionalidadesquepodemserimplementadasparamelhoraraeficiênciadonossocódigo.
Omódulocollectionstambémprovêummódulodeclassesabstratas,omóduloabc.collections,
quepodemserusadaspara testarsedeterminadaclasseprovêumainterfaceparticular.Aprenderemosumpoucosobreelaseseuuso.
AsestruturasdedadospadrãodoPythonsãodegrandevaliaemuitoutilizadasnalinguagem,masexistem momentos em que precisamos de funcionalidades extras que são comuns de projeto paraprojeto.Nessesentido,surgeomódulocollections,praacrescentaressasfuncionalidades.
Porexemplo,nolivroPythonFluentedeLucianoRamalho,éapresentadoumexemploemque
precisamosacrescentarfuncionalidadesextras:
COLLECTIONS
14.1USERLIST,USERDICTEUSERSTRING
14COLLECTIONS 191
![Page 199: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/199.jpg)
"Um caso de uso concreto é o projeto Pingo.io (http://www.pingo.io/docs/), em que uma placaprogramável com pinos GPIO (por exemplo, Raspberry Pi ou Arduino) é representada por umobjeto board com um atributo board.pins ; esse atributo contém um mapeamento das
localizaçõesfísicasdospinosparaobjetosquerepresentamospinos.Alocalizaçãofísicapodeserumnúmeroouumastring como"A0"ou"P912".Porquestõesdeconsistência, édesejável quetodas as chaves com board.pins sejam _strings, mas é conveniente que a consulta a
my_arduino.pin[13] também funcione de modo que programadores iniciantes não tenham
problemasquandoquiseremfazerpiscaroLEDnopino13deseusArduinos."
Precisamos usar índices que são strings, portanto, um dicionário. Além disso, nosso dicionáriopoderiaapenasaceitarstringscomochavesparaesteobjetivoespecífico.Paranãotratarissoduranteaexecuçãodenossoprograma,podemoscriarumaclassequetenhaocomportamentodeumdicionáriocomessacaracterísticaespecífica.
Para isso, criamos uma classe que herda de uma classe chamada UserDict do pacote
collections:
classMeuDicionario(UserDict):pass
AclasseUserDict nãoherdadedict,mas simulaumdicionário.AUserDict possui uma
instânciadedictinternachamadadata,quearmazenaositenspropriamenteditos.
Criarsubclassesdetiposembutidoscomodictoulistdiretamenteépropensoaerros,porque
seusmétodos geralmente ignoramas versões sobrescritas.Alémde que cada implementação pode secomportardemaneiradiferente.OfatodeherdarmosdeUserDictenãodiretamentededictépara
evitarmosessesproblemas.
Criandoaclassedestamaneira,temosumaclassenossaquefuncionacomoumdicionário.Masnãofazsentidocriá-lasemacrescentarfuncionalidades,jáqueoPythonjápossuiessaestruturaprontaqueéodict.
Vamoscriarnossodicionário,demodoquesóaceitechavescomostrings evai representaros
pinosdaplacadoRasbperryPi,porexemplo:
fromcollectionsimportUserDict
classPins(UserDict):
def__contains__(self,key):returnstr(key)inself.keys()
def__setitem__(self,key,value):
192 14.1USERLIST,USERDICTEUSERSTRING
![Page 200: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/200.jpg)
self.data[str(key)]=value
Notequeasobrescritade__setitem__garantequeachavesempreseráumastring.Podemos
testaressaclasse:
if__name__=='__main__':pins=Pins(one=1)print(pins)pins[3]=1lista=[1,2,3]pins[lista]=2print(pins)
Percebaquequandoimprimimosodicionário,todassuaschavessãostrings.
Se você está gostando dessa apostila, certamente vai aproveitar os cursosonlinequelançamosnaplataformaAlura.VocêestudaaqualquermomentocomaqualidadeCaelum.Programação,Mobile,Design,Infra,Front-Ende
Business,entreoutros!Ex-estudantedaCaelumtem10%dedesconto,sigaolink!
ConheçaaAluraCursosOnline.
Outros tipos que existem no módulo collections são: defaultdict , counter , deque e
namedtuple.
Aocontráriododict,nodefaultdictnãoénecessárioverificarseumachaveestápresenteou
não.
fromcollectionsimportdefaultdict
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'])]
Agoraéamelhorhoradeaprenderalgonovo
14.2PARASABERMAIS
14.2PARASABERMAIS 193
![Page 201: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/201.jpg)
SemacusarKeyError.
Counter
O Counter é um contador e permite contar as ocorrências de um determinado item em uma
estruturadedados:
fromcollectionsimportCounter
cores=['amarelo','azul','azul','vermelho','azul','verde','vermelho']
contador=Counter(cores)
print(contador)
Vaiimprimir:
Counter({'azul':3,'vermelho':2,'amarelo':1,'verde':1})
UmCounteréumdict epode receberumobjeto iterávelouummapacomoargumentopara
realizaracontagemdeseuselementos.
deque
Odequeéumaestruturadedadosqueforneceumafila comduasextremidadese épossível
adicionareremoverelementosdeambososlados:
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índicesinteiros
paraacessarseuselementosepodemosutilizarstrings-similaraosdicionários.Masaocontráriodosdicionários,namedtupleéimutável:
fromcollectionsimportnamedtuple
Conta=namedtuple('Conta','numerotitularsaldolimite')conta=Conta('123-4','João',1000.0,1000.0)
194 14.2PARASABERMAIS
![Page 202: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/202.jpg)
print(conta)#saída:Conta(numero='123-4',titular='João',saldo=1000.0,limite=1000.0)
print(conta.titular)#saída:João
Note que para acessar o elemento nomeado utilizamos o operador '.' (ponto).Umanamedtuple
possuidoisargumentosobrigatóriosquesão:onomedatuplaeseuscampos(separadosporvírgulaouespaço).Noexemplo,a tupla sechamaConta epossui4campos:numero,titular,saldo e
limite.Comosãoimutáveis,nãopodemosmodificarosvaloresdeseuscampos:
conta.titular="José"
Issovaigeraroseguinteerro:
Traceback(mostrecentcalllast):File<stdin>,line5,in<module>conta.titular="José"AttributeError:can'tsetattribute
Anamedtupletambémécompatívelcomumatuplanormal.Issoquerdizerquevocêtambémpode
usaríndicesinteirosparaacessarseuselementos.
print(conta[0])#saída:'123-4'
Maisdetalhesdecadaumadessasestruturasestãonadocumentaçãoepodeseracessadasporestelink: https://docs.python.org/3/library/collections.html.Outra alternativa é usar a função help() no
objetoparaacessaradocumentação.
Omódulocollections.abc fornece classes abstratas quepodem ser usadaspara testar se uma
classeforneceumainterfaceespecífica.Porexemplo,seelaéiterávelounão.
Imaginequeobanconosentregouumarquivocomváriosfuncionáriosepediuquecalculássemosabonificação de cada umdeles. Precisamos acrescentar este arquivo emnossa 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.Este
arquivo está no padrão Comma-separated-values, também conhecido como csv e são comumenteusados.OPythondásuportedeleituraparaeste tipodearquivo.Assim,vamosacrescentaromódulo
14.3COLLECTIONSABC
14.3COLLECTIONSABC 195
![Page 203: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/203.jpg)
csv,quevaiajudarnatarefadeleroarquivo:
importcsv
arquivo=open('funcionarios.txt','r')leitor=csv.reader(arquivo)
forlinhainleitor:print(linha)
arquivo.close()
Oprogramaacimaabreumarquivoeum leitordomódulocsv, oreader - recebeo arquivo
comoparâmetroedevolveumleitorquevai ler linhaa linhaeguardarseuconteúdo.Podemos iterarsobreesteleitorepedirparaimprimiroconteúdodecadalinha-queéexatamenteoqueéfeitonolaçofor.Porúltimo,fechamosoarquivo.
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']
Reparequeoreaderguardacadalinhadeumarquivoemumalista,ecadavalordelimitadopor
vírgulasetornaumelementodestalista,oquefacilitaoacessoaosdados.
Agoracomestesdadosemmãos,podemosconstruirnossosobjetosdetipoFuncionario:
forlinhainleitor:funcionario=Funcionario(linha[0],linha[1],float(linha[2]))
Masaindaprecisamosdeumaestruturaparaguardá-los.Vamosutilizarumalista:
funcionarios=[]
forlinhainleitor:funcionario=Funcionario(linha[0],linha[1],float(linha[2]))funcionarios.append(funcionario)
Porfim,imprimimosossaldosdalista:
forfinfuncionarios:print(f.salario)
Acontecequenadaimpede,posteriormente,deinserirmosnestalistaqualqueroutroobjetoquenãoumfuncionário:
funcionarios.append('Python')funcionarios.append(1234)funcionarios.append(True)
Alist da bibliotecapadrão aceita qualquer tipodeobjeto comoelemento.Nãoqueremos este
196 14.3COLLECTIONSABC
![Page 204: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/204.jpg)
comportamento, já que iremos calcular a bonificaçãode cadaumdeles, ondedependendodo tipodeobjetosinseridonalista,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__.
PrecisamosconstruirumcontainerdeobjetosdetipoFuncionario.Podemosconstruirumaclasse
querepresentaráessaestrutura,quedevesersubclassedeContainer:
fromcollections.abcimportContainer
classFuncionarios(Container):pass
if__name__=='__main__':funcionarios=Funcionarios()
OcódigoacimaacusaumTypeError:
TypeError:Can'tinstantiateabstractclassFuncionarioswithabstractmethods__contains__
Precisamos implementar ométodo__contains__, já que Funcionarios deve implementar a
classeabstrataContainer.Aideiaéquenossocontainersecomportecomoumalista,entãoteremos
umatributodotipolistaemnossaclasseparaguardarosobjetoseimplementarométodocontains:
fromcollections.abcimportContainer
classFuncionarios(Container):
_dados=[]
def__contains__(self,item):returnself._dados.__contains__(self,item)
if__name__=='__main__':funcionarios=Funcionarios()
14.4CONSTRUINDOUMCONTAINER
14.4CONSTRUINDOUMCONTAINER 197
![Page 205: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/205.jpg)
Editorastradicionaispoucoligamparaebooksenovastecnologias.Nãodominamtecnicamente o assunto para revisar os livros a fundo. Não têm anos deexperiênciaemdidáticascomcursos.ConheçaaCasadoCódigo,umaeditoradiferente,comcuradoriadaCaelumeobsessãoporlivrosdequalidadeapreçosjustos.
CasadoCódigo,ebookcompreçodeebook.
Otamanhodonossocontainertambéméumainformaçãoimportante.NossaclasseFuncionarios
devesaberretornaressevalor.UtilizamosaclasseabstrataSizedparagarantiressafuncionalidade.A
classeSizedprovêométodolen()atravésdométodoespecial__len__():
fromcollections.abcimportContainer
classFuncionarios(Container,Sized):
_dados=[]
def__contains__(self,item):returnself._dados.__contains__(self,item)
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 nossocontainer seja iterável, ou seja, que consigamos iterar sobre seus elementos em um laço for, porexemplo.Omódulocollection.abctambémprovêumaclasseabstrataparaestecomportamento,éa
classeIterable.Iterablesuportaiteraçãocomométodo__iter__:
fromcollections.abcimportContainer
classFuncionarios(Container,Sized,Iterable):
_dados=[]
EditoraCasadoCódigocomlivrosdeumaformadiferente
14.5SIZED
14.6ITERABLE
198 14.5SIZED
![Page 206: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/206.jpg)
def__contains__(self,item):returnself._dados.__contains__(self,item)
def__len__(self):returnlen(self._dados)
def__iter__(self):returnself._dados.__iter__(self)
if__name__=='__main__':funcionarios=Funcionarios()
TodacoleçãodeveherdardessasclassesABCs:Container,IterableeSized.Ouimplementar
seusprotocolos:__contains__,__iter__e__len__.
Alémdessasclasses,existemoutrasque facilitamesse trabalhoe implementamoutrosprotocolos.Vejaahierarquiadeclassedomódulocollections.abc:
Figura14.1:legendadaimagem
Alémdoque já foi implementado,a ideiaéquenossaclasseFuncionario funcione comouma
listacontandoapenasobjetosdotipoFuncionario.Comoaprendemosnocapítulo4,umalistaéuma
sequência.Alémdeumasequência,éumasequênciamutável-podemosadicionarelementosemumalista.NossaclasseFuncionariotambémdevepossuiressafuncionalidade.
Segundo o diagrama de classes do módulo collections.abc , a classe que representa essa
estruturaéaMutableSequence.NotequeMutableSequenceherdadeSequencequerepresentauma
sequência;queporsuavezherdadeContainer,IterableeSized.
Figura14.2:legendadaimagem
Portanto, devemos implementar 5 métodos abstratos (em itálico na imagem) segundo adocumentaçãodeMutableSequence:__len__,__getitem__,__setitem__,__delitem__ e
insert.Ométodo__getitem__garantequeaclasseéumContainereIterable. Segundo a
14.6ITERABLE 199
![Page 207: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/207.jpg)
PEP234(https://www.python.org/dev/peps/pep-0234/)umobjetopodeseriterávelcomumlaçoforseimplementa__iter__ou__getitem__.
Então,bastanossaclasseFuncionarioherdardeMutableSequenceeimplementarseusmétodos
abstratos:
fromcollections.abcimportMutableSequence
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:
importcsv
arquivo=open('funcionarios.txt','r')leitor=csv.reader(arquivo)
funcionarios=Funcionarios()
forlinhainleitor:funcionario=Funcionario(linha[0],linha[1],float(linha[2]))funcionarios.append(funcionario)
arquivo.close()
Ométodoinsert() garante o funcionamento dométodo append(). E podemos imprimir os
valoresdossalá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 alguns
comportamentos.
Queremosquenossa lista de funcionários apenas aceite objetos da classeFuncionario. Vamos
200 14.6ITERABLE
![Page 208: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/208.jpg)
sobrescreverosmétodos__setitem__()queatribuiuumvaloremdeterminadaposiçãonalista.Este
métodopodeapenasatribuiraumadeterminadaposiçãoumobjetoFuncionario.
Paraisso,vamosusarométodoisinstance()quevaiverificarseoobjetoaseratribuídoéuma
instância de Funcionario . Caso contrário, vamos lançar uma exceção TypeError com uma
mensagemdeerro:
def__setitem__(self,posicao,valor):if(isinstance(valor,Funcionario)):self._dados[posicao]=valorelse:raiseTypeError('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__raiseTypeError('ValoratribuídonãoéumFuncionario')TypeError:ValoratribuídonãoéumFuncionario
Faremosomesmocomométodoinsert():
definsert(self,posicao,valor):if(isinstance(valor,Funcionario)):returnself._dados.insert(posicao,valor)else:raiseTypeError('ValorinseridonãoéumFuncionario')
EpodemostestarnossaclasseimprimindonãoapenasosaláriomasovalordabonificaçãodecadaFuncionarioatravésdométodoget_bonificacao()quedefinimosnoscapítulospassados:
if__name__=='__main__':importcsv
arquivo=open('funcionarios.txt','r')leitor=csv.reader(arquivo)
funcionarios=Funcionarios()
forlinhainleitor:funcionario=Funcionario(linha[0],linha[1],float(linha[2]))funcionarios.append(funcionario)
print('salário-bonificação')forfinfuncionarios:print('{}-{}'.formar(f.salario,f.get_bonificacao()))
arquivo.close()
AsclassesABCsforamcriadasparaencapsularconceitosgenéricoseabstraçõescomoaprendemosnocapítulode classes abstratas.Sãocomumenteutilizadas emgrandes aplicações e frameworkspara
14.6ITERABLE 201
![Page 209: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/209.jpg)
garantiraconsistênciadosistemaatravésdosmétodosisinstance()eissubclass().Nodiaadia
é raramenteusadoebastaousocorretodasestruturas já fornecidaspelabibliotecapadrãodoPythonparaamaiorpartedastarefas.
1. Vánapastanocursoecopieoarquivocontas.txtnapastasrcdoprojetobancoquecontém
váriosdadosdecontascorrentesdeclientesdobanco.
2. Crieumarquivochamadocontas.pynapastasrcdoprojetobanco.Crie uma classe chamada
ContasqueherdedaclasseabstrataMutableSequence:
fromcollections.abcimportMutableSequence
classContas(MutableSequence):pass
3. Vamoscriarumatributonaclassechamado_dadosdotipolistparaarmazenarnossascontas:
fromcollections.abcimportMutableSequence
classContas(MutableSequence):
_dados=[]
4. TenteinstanciarumobjetodetipoContas:
if__name__=='__main__':contas=Contas()
Note que não podemos instanciar este objeto. A interface MutableSequence nos obriga a
implementaralgunsmé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):
14.7EXERCÍCIO:CRIANDONOSSASEQUÊNCIA
202 14.7EXERCÍCIO:CRIANDONOSSASEQUÊNCIA
![Page 210: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/210.jpg)
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.Vamosacrescentar
essavalidaçãonosmétodos__setitem__einsert.CasoovalornãosejaumaConta,vamos
lançarumTypeErrorcomasdevidasmensagensdeerro:
def__setitem__(self,posicao,valor):if(isinstance(valor,Conta)):self._dados[posicao]=valorelse:raiseTypeError("valoratribuídonãoéumaConta")
definsert(self,posicao,valor):if(isinstance(valor,Conta)):returnself._dados.insert(posicao,valor)else:raiseTypeError('valorinseridonãoéumaConta')
7. Vamosiniciaraleituradosdadosdoarquivoparaarmazenaremnossoobjetocontas:
if__name__=='__main__':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],float(linha[2]),float(linha[3]))
arquivo.close()
14.7EXERCÍCIO:CRIANDONOSSASEQUÊNCIA 203
![Page 211: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/211.jpg)
9. Queremosinserircadacontacriadaemnossasequênciamutávelcontas.Vamospedirparaqueo
programaacrescentecadacontacriadaemcontas:
forlinhainleitor:conta=ContaCorrente(linha[0],linha[1],float(linha[2]),float(linha[3]))contas.append(conta)
arquivo.close()
10. Nossa classeContas implementaMutableSequence. Isso quer dizer que ela é iterável já que
MutableSequenceimplementaoprotocolo__iter__atravésdométodo__getitem__.Vamos
iterar através de uma laço for nossoobjetocontas e pedir para imprimir o saldo e o valor do
impostodecadaumadelas:
if__name__=='__main__':#códigoanterioromitido
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.01700.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 com
algumas contas poupanças, faça a leitura, construa os objetos e acrescente em uma estrutura dedadosdotipoMutableSequence.
13. (Desafio Opcional) Refaça o exercício utilizando MutableMapping ao invés de
MutableSequence.
204 14.7EXERCÍCIO:CRIANDONOSSASEQUÊNCIA
![Page 212: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/212.jpg)
AAluraoferececentenasdecursosonlineemsuaplataformaexclusivadeensinoquefavoreceoaprendizadocomaqualidadereconhecidadaCaelum.VocêpodeescolherumcursonasáreasdeProgramação,Front-end,Mobile,
Design&UX,Infra,Business,entreoutras,comumplanoquedáacessoatodososcursos.Ex-estudantedaCaelumtem10%dedescontonestelink!
ConheçaoscursosonlineAlura.
JáconheceoscursosonlineAlura?
14.7EXERCÍCIO:CRIANDONOSSASEQUÊNCIA 205
![Page 213: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/213.jpg)
CAPÍTULO15
Caso você esteja iniciando seus estudos na linguagem Python ou começando um projeto novo,aconselhamosfortementequevocêutilizeoPython3.
OPython2vemsendochamadodePython legadoouPythonantigoporboapartedacomunidadeque está em constante atividade para fazer amigraçãoda base de código existente (bemgrande, 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 noPython3 ou não está emprocesso demudança.Outro caso é quando seu servidor de hospedagem sópermiteusarPython2-aquioaconselháveléprocurarporoutroserviçoqueatendasuademanda.
Nomais,vocêencontrarámuitomaterialsobreoPython2nainterneteaospoucosvaiconhecendomelhorasdiferençasentreumaversãoeoutra.
Nesteartigovocêvai encontrar a respostahttps://docs.python.org/3/whatsnew/3.0.html.Masnestecapítulomostramosasdiferençasmaisbásicaseimportantesparavocêiniciarseusestudos.
APÊNDICE-PYTHON2OUPYTHON3?
15.1QUAISASDIFERENÇAS?
206 15APÊNDICE-PYTHON2OUPYTHON3?
![Page 214: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/214.jpg)
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
No Python2 o comando print funciona de maneira diferente já que não é uma função. Para
imprimiralgofazemos:
#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
VocêpodetambémfazerocursodatadessaapostilanaCaelum
15.2AFUNÇÃOPRINT()
15.3AFUNÇÃOINPUT()
15.4DIVISÃODECIMAL
15.2AFUNÇÃOPRINT() 207
![Page 215: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/215.jpg)
No Python3 a divisão tem o mesmo comportamento da matemática. E se quisermos o resultadointeirodadivisãoutilizamos//:
#nopython3>>>5/22.5>>>5//22
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
NoPython2suasclassesdevemherdardeobject:
#nopython2>>>classMinhaClasse(object):defmetodo(self,attr1,attr2):returnattr1+attr2
NoPython3essaherançaéimplícita,nãoprecisandoherdarexplicitamentedeobject:
#nopython3>>>classMinhaClasse():defmetodo(self,attr1,attr2):returnattr1+attr2
Seuslivrosdetecnologiaparecemdoséculopassado?
15.5HERANÇA
208 15.5HERANÇA
![Page 216: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/216.jpg)
CAPÍTULO16
OPython já vem instalado nos sistemas Linux eMacOSmas será necessário fazer o download daúltima versão (Python 3.6) para acompanhar a apostila. O Python não vem instalado por padrão noWindowseodownloaddeverá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.
Figura16.1:TeladedownloaddoPythonparaoWindows
Apósodownload ser finalizado, abra-oenaprimeira telamarqueaopçãoAddPython3.Xto
PATH.EssaopçãoéimportanteparaconseguirmosexecutaroPythondentrodoPromptdeComandodo
Windows. Caso você não tenha marcado esta opção, terá que configurar a variável de ambiente noWindowsdeformamanual.
APÊNDICE-INSTALAÇÃO
16.1INSTALANDOOPYTHONNOWINDOWS
16APÊNDICE-INSTALAÇÃO 209
![Page 217: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/217.jpg)
Figura16.2:Checkboxselecionado
Selecioneainstalaçãocustomizadasomenteparaverainstalaçãocommaisdetalhes.
Figura16.3:Instalaçãocustomizada
Natelaseguintesãoasfeaturesopcionais,secertifiquequeogerenciadordepacotespip esteja
selecionado, ele que permite instalar pacotes e bibliotecas no Python. Clique em Next para dar
210 16.1INSTALANDOOPYTHONNOWINDOWS
![Page 218: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/218.jpg)
seguimentonainstalação.
Figura16.4:OptionalFeatures
Jána terceira tela,deixe tudocomoestá,masseatenteaodiretóriode instalaçãodoPython,paracasoqueiraprocuraroexecutáveloualgoqueenvolvaoseudiretório.
Figura16.5:AdvancedOptions
16.1INSTALANDOOPYTHONNOWINDOWS 211
![Page 219: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/219.jpg)
Porfim,bastaclicaremInstalleaguardarotérminodainstalação.
Figura16.6:InstalaçãoConcluídacomSucesso
Terminadaainstalação,testeseoPythonfoiinstaladocorretamente.AbraoPromptdeComandoeexecute:
python-V
OBS:ParaquefuncionecorretamenteénecessárioquesejanoPromptdeComandoenãoemalgumprogramaGitBashinstaladoemsuamáquina.Eocomandopython-Véimportantequeestejacomo
Vcomletramaiúscula.
Esse comando imprime a versão do Python instalada no Windows. Se a versão for impressa,significaqueoPythonfoiinstaladocorretamente.Agora,rodeocomandopython:
python
AssimvocêteráacessoaoconsoledopróprioPython,conseguindoassimutilizá-lo.
212 16.1INSTALANDOOPYTHONNOWINDOWS
![Page 220: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/220.jpg)
Querendoaprenderaindamaissobre?Esclarecerdúvidasdosexercícios?Ouvirexplicaçõesdetalhadascomuminstrutor?ACaelum oferece o cursodata presencial nas cidades de São Paulo, Rio deJaneiroeBrasília,alémdeturmasincompany.
ConsulteasvantagensdocursoPythoneOrientaçãoaObjetos
Os sistemasoperacionaisbaseadosnoDebian jápossuemoPython3pré-instalado.Verifique seoseusistemajápossuioPython3instaladoexecutandooseguintecomandonoterminal:
python3-V
OBS:Ocomandopython3-VéimportantequeestejacomoVcomletramaiúscula.
EstecomandoretornaaversãodoPython3instalada.Sevocêaindanãotivereleinstalado,digiteosseguintescomandosnoterminal:
sudoapt-getupdatesudoapt-getinstallpython3
AmaneiramaisfácildeinstalaroPython3noMacOSéutilizandooHomebrew.ComoHomebrew
instalado,abraoterminaledigiteosseguintescomandos:
brewupdatebrewinstallpython3
PodemosrodaroPythondiretamentedoseupróprioPrompt.
Podemos procurar pelo Python na caixa de pesquisa doWindows e abri-lo, assim o seu consolepróprioseráaberto.UmaoutraformaéabriraIDLEdoPython,queseparecemuitocomoconsolemasvemcomummenuquepossuialgumasopçõesextras.
VocêpodetambémfazerocursodatadessaapostilanaCaelum
16.2INSTALANDOOPYTHONNOLINUX
16.3INSTALANDOOPYTHONNOMACOS
16.4OUTRASFORMASDEUTILIZAROPYTHON
16.2INSTALANDOOPYTHONNOLINUX 213
![Page 221: Python e Orientação a Objetos](https://reader030.vdocuments.com.br/reader030/viewer/2022012508/6185e70fc1395f7cd223a00c/html5/thumbnails/221.jpg)
Conheça aCasa do Código, uma nova editora, com autores de destaque nomercado, foco em ebooks (PDF, epub, mobi), preços imbatíveis e assuntosatuais.Coma curadoria daCaelum e excelentes autores, é uma abordagemdiferenteparalivrosdetecnologianoBrasil.
CasadoCódigo,LivrosdeTecnologia.
Seuslivrosdetecnologiaparecemdoséculopassado?
214 16.4OUTRASFORMASDEUTILIZAROPYTHON