O documento apresenta um tutorial básico sobre programação orientada a objetos em Python ministrado por Ronaldo F. Ramos no IFCE em 20 de abril de 2017. O tutorial introduz conceitos como classes, objetos, herança, encapsulamento, construtores e importação de módulos e pacotes.
1. Programação Orientada a Objetos
Tutorial Básico em Python
Ronaldo F. Ramos
IFCE
20 de abril de 2017
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 1 / 84
2. Introdução a POO
Conteúdo
1 Introdução a POO
2 POO em Python
3 Reaproveitamento de Código
4 Controle de Erros
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 2 / 84
3. Introdução a POO
Introdução a POO
Programação orientada a objetos...
A arte de programar usando classes e objetos
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 3 / 84
4. Introdução a POO
Introdução a POO
Programação orientada a objetos...
A arte de programar usando classes e objetos
Pilares
Tem como pilares a abstração, encapsulamento, herança, polimorfismo e
agregação
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 3 / 84
5. Introdução a POO
Introdução a POO
Programação orientada a objetos...
A arte de programar usando classes e objetos
Pilares
Tem como pilares a abstração, encapsulamento, herança, polimorfismo e
agregação
Origem
Origem nos anos 60 na Noruega através da linguagem SIMULA que depois
foi aperfeiçoada no smalltalk
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 3 / 84
6. Introdução a POO
Introdução a POO
Programação orientada a objetos...
A arte de programar usando classes e objetos
Pilares
Tem como pilares a abstração, encapsulamento, herança, polimorfismo e
agregação
Origem
Origem nos anos 60 na Noruega através da linguagem SIMULA que depois
foi aperfeiçoada no smalltalk
Uso
Quase todas as linguagens modernas implementam os conceitos de OO.
Java, Python, Ruby, Julia, Lua, etc ...
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 3 / 84
7. Introdução a POO
Linha de tempo das linguagens baseadas em Objetos
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 4 / 84
8. Introdução a POO
Princípios
Objetos
As ações dos programas são realizadas pelos objetos. Um programa em
execução é um conjunto de objetos em ação.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 5 / 84
9. Introdução a POO
Princípios
Objetos
As ações dos programas são realizadas pelos objetos. Um programa em
execução é um conjunto de objetos em ação.
Serviços
Objetos realizam tarefas através da requisição de serviços.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 5 / 84
10. Introdução a POO
Princípios
Objetos
As ações dos programas são realizadas pelos objetos. Um programa em
execução é um conjunto de objetos em ação.
Serviços
Objetos realizam tarefas através da requisição de serviços.
Classes
Cada objeto pertence a uma determinada classe.Uma classe agrupa
objetos similares.Um classe possui comportamentos associados ao objeto.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 5 / 84
11. Introdução a POO
Princípios
Objetos
As ações dos programas são realizadas pelos objetos. Um programa em
execução é um conjunto de objetos em ação.
Serviços
Objetos realizam tarefas através da requisição de serviços.
Classes
Cada objeto pertence a uma determinada classe.Uma classe agrupa
objetos similares.Um classe possui comportamentos associados ao objeto.
Hierarquia
Classes são organizadas em hierarquias.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 5 / 84
12. POO em Python
Mãos a Obra
Primeira classe em Python.
1 #!/usr/bin/env python3
2 #
3 # Primeira Classe em Python
4 #
5 class MinhaPrimeiraClasse :
6 pass
#
Execute o código digitando
python -i minhaPrimeiraClasse.py
Desta forma o Python criará a classe e retornará para o interpretador.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 6 / 84
13. POO em Python
Criando Objetos
Depois de executar o script no arquivo minhaPrimeiraClasse.py, crie
objetos "a"e "b"conforme segue.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 7 / 84
14. POO em Python
Adicionando Atributos a Objetos já Instanciados
Ao contrário da maioria das linguagens, Python permite adicionar
atributos a objetos já criados. Segue um programa exemplo.
1 class Triangulo:
2 pass
3
4 t1 = Triangulo ()
5 t2 = Triangulo ()
6
7 t1.catetoA = 10
8 t1.catetoB = 20
9 t2.catetoA = 15
10 t2.catetoB = 25
11
12 print(t1.catetoA , t1.catetoB , t2.catetoA , t2.catetoB)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 8 / 84
15. POO em Python
Adicionando Funções(Comportamentos) nas Classes
Agora adicionamos comportamentos (funções) a classe e por consequência
nos objetos que pertecem a mesma.
1 #!/usr/bin/env python3
2 ’’’
3 Fazendo alguma coisa
4 ’’’
5 class MinhaClasse:
6 def darUmAlo(self):
7 print("Olá mundo cruel")
8
9 objeto = MinhaClasse ()
10 objeto.darUmAlo ()
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 9 / 84
16. POO em Python
Função do Self
Todo método pertencente a uma classe deve receber um argumento de
auto referência. Este argumento possibilitará o acesso a outros métodos
(comportamentos) e atributos do objeto que chamou a função.
Outros argumentos podem vir após o self e o nome self é uma convenção.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 10 / 84
17. POO em Python
Curiosidade
Um método nada mais é que uma função global condicionada ao escopo
da classe. Experimente chamar MinhaClasse.darUmAlo(objeto) e ver o que
acontece.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 11 / 84
18. POO em Python
Uma Classe Completa
1 import math
2 class Triangulo:
3 base = 0
4 altura = 0
5 def receberDadosCatetos (self ,b,h):
6 self.base = b
7 self.altura = h
8 def calcularHipotenusa (self):
9 return math.sqrt(self.base **2+ self.altura **2)
10 t = Triangulo ()
11 t. receberDadosCatetos (3,4)
12 print("Hipotenusa = ",t. calcularHipotenusa ())
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 12 / 84
19. POO em Python
Construtores
Fuções ou métodos especialmente indicados para a inicialização dos
atributos de uma classe (Não obrigatoriamente). Veja exemplo abaixo.
1 import math
2 class Triangulo:
3 def __init__(self ,ca ,cb):
4 self.catetoA = ca
5 self.catetoB = cb
6 def calculaHipotenusa (self):
7 return math.sqrt(self.catetoA **2 + self.catetoB
**2)
8
9 t = Triangulo (3,4)
10 print("Hipotenusa = ",t. calculaHipotenusa ())
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 13 / 84
20. POO em Python
Módulos e Pacotes
Pequenos programas costumam ser colocados em apenas um arquivo
texto. Grandes programas costumam ser divididos em vários arquivos
(módulos). O módulos são importados e podem ser organizadas em pastas
hierárquicas com indexação. Abaixo um exemplo simples de importação.
Módulo classeBasicaTriangulo.py
1 import math
2 class Triangulo:
3 def __init__(self ,ca ,cb):
4 self.catetoA = ca
5 self.catetoB = cb
6 def calculaHipotenusa (self):
7 return math.sqrt(self.catetoA **2 + self.catetoB
**2)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 14 / 84
21. POO em Python
Módulos e Pacotes
... Módulo usaTriangulo.py
1 # modulo que importa o modulo que contem triangulo
2 #
3 import class eBasicaTriangulo
4 t = class eBasicaTriangulo .Triangulo (3,4)
5 print("Hipotenusa = ",t. calculaHipotenusa ())
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 15 / 84
22. POO em Python
Módulos e Pacotes
... Ouras formas de import:
1 # modulo que importa o modulo que contem triangulo
2 #
3 import class eBasicaTriangulo as cbt
4 t = cbt.Triangulo (3,4)
5 print("Hipotenusa = ",t. calculaHipotenusa ())
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 16 / 84
23. POO em Python
Módulos e Pacotes
... Ou ainda:
1 # modulo que importa o modulo que contem triangulo
2 #
3 from class eBasicaTriangulo import *
4 t = Triangulo (3,4)
5 print("Hipotenusa = ",t. calculaHipotenusa ())
Podemos especificar exatamente o que quisermos importar.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 17 / 84
24. POO em Python
Pacotes
Uma coleção de módulos em uma pasta se chama de Pacote.
O nome do pacote é o nome do folder (pasta)
O folder deve conter o arquivo __init__.py possivelmente vazio
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 18 / 84
25. POO em Python
Exemplo de Pacote - Geometria
geometria/
main.py
poligonos/
__init__.py
hexagono.py
triangulo.py
ovals/
__init__.py
circulo.py
elipse.py
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 19 / 84
26. POO em Python
Imports
Imports de Endereçamento Absoluto
import poligonos.hexagono
import poligonos.ovals.elipse
from poligonos import ovals
Atenção: As pastas a serem verificadas são: a pasta atual (.), o site
package (ex. /usr/lib/python3.5/site-packages) e aquelas definidas na
variável PYTHONPATH
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 20 / 84
27. POO em Python
Imports
Imports de Endereçamento Relativo
from .ovals import elipse
from ..poligonos import retangulo
CONSELHO : NÃO USE
Porém, se vc, digamos usar a seguinte linha em circulo.py :
from . import elipse
Saiba que pra executar corretamente vc teria que digitar na pasta superior:
python3 -m ovals.circulo
(Prolixo ...)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 21 / 84
28. POO em Python
Controle de Acesso
Diversas linguagens implementam controle de acesso aos dados das
classes diferenciando-as entre públicas e privadas.
Python NÃO
Muitos programadores python usam o _ (sublinha) antes de iniciar o
nome de uma variável com o intuito de sinalizar que se trata de uma
variável sensível(a ser tratada como privada)
O __ (duplo sublinha) em Python faz com que o nome da classe seja
prefixado ao nome da variável em questão (name mangling)
dificultando, mas não impedindo o acesso a mesma.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 22 / 84
29. Reaproveitamento de Código
Herança Simples
Observe as relações entre as duas classes. A filha herda todas as
propriendades (Atributos e métodos da mãe)
1 import math
2 class Circulo :
3 raio = 0
4 def calculaArea ( self ,r ) :
5 return math.pi*r**2
6 class CoroaCircular (Circulo):
7 raioInterno = 0
8 def calculaAreaCoroa (self):
9 return self. calculaArea (self.raio)-self. calculaArea (self. raioInterno )
10 circ = Circulo () # Instanciando Objeto
11 circ.raio =10
12 # variável da instância
13 print("Circulo de raio % d possui área de % f "%( circ.raio ,circ. calculaArea (circ.
raio)))
14 ccirc = CoroaCircular ()
15 ccirc.raio =10
16 ccirc. raioInterno = 7
17 print(" Coroa de raio externo % d raio interno % d possui área : % f "%( ccirc.raio ,
ccirc.raioInterno ,ccirc. calculaAreaCoroa ()))
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 23 / 84
30. Reaproveitamento de Código
Uma Pequena Ajuda dos Construtores
Observe que na classe filha deve haver uma chamada explicita ao
construtor da mãe.
1 import math
2 class Circulo:
3 def __init__(self ,r):
4 self.raio = r
5
6 def calculaArea(self ,r):
7 return math.pi*r**2
8
9 class CoroaCircular (Circulo):
10 def __init__(self ,re ,ri):
11 Circulo.__init__(self ,re)
12 self. raioInterno = ri
13
14 def calculaArea(self ,re ,ri):
15 return super (). calculaArea (re) - super ().calculaArea(ri)
16
17 x = input("Digite qualquer merdaa")
18 circ = Circulo (10) # Instanciando Objeto
19 print("Circulo de raio %d possui área de %f "%( circ.raio ,circ.calculaArea(circ.raio)
))
20 ccirc = CoroaCircular (20 ,10)
21 print("Área da Coroa: ",ccirc. calculaArea (ccirc.raio ,ccirc.raioInterno))
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 24 / 84
31. Reaproveitamento de Código
Variáveis de Classe
Variáveis com os valores compartilhados entre todos os objetos de uma
determinada classe.
1 class Pessoa:
2 def __init__(self ,nome ,end ,fone):
3 self.nome ,self.endereco ,self.telefone = nome ,end ,fone
4 def __str__(self):
5 return "NOME: "+self.nome+" END. "+self.endereco+" FONE: "+self.telefone
6
7 class Estudante(Pessoa):
8
9 listaEstudantes = []
10
11 def __init__(self ,nome ,end ,fone ,curso ,periodo):
12 #Pessoa.__init__(self , nome ,end ,fone)
13 super ().__init__(nome ,end ,fone)
14 self.curso = curso
15 self.periodo = periodo
16 Estudante. listaEstudantes .append(self)
17
18 def calculaIra(self):
19 return 0
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 25 / 84
32. Reaproveitamento de Código
Variáveis de Classe
Variáveis com os valores compartilhados entre todos os objetos de uma
determinada classe.
1 from class eEstudante import *
2 def main ():
3 #Criando estudantes
4 st1 = Estudante("Pedro","Rua das Acácias , 42","91119999","In for mática" ,3)
5 st2 = Estudante("Maria","Rua das Amêndoas , 32","91118741","Letras" ,5)
6 st3 = Estudante("João","Rua das Oiticicas , 21","91113232","Engenharia" ,2)
7 st4 = Estudante("Fatima","Rua das Bromélias , 79,","91114142","Direito" ,1)
8
9 #Imprimido um estudante
10 print("Um estudante : ",st2)
11
12 #Imprimindo a lista de estudantes a partir da classe
13 print("Lista: ")
14 for i in Estudante. listaEstudantes : print(i)
15 print(" ------------------------------")
16 #imprimido a lista de uma instância
17 for i in st1. listaEstudantes : print(i)
18
19 #lasca
20 if __name__ =="__main__":
21 main ()
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 26 / 84
33. Reaproveitamento de Código
Variáveis de Classe
Observe abaixo a saída do programa
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 27 / 84
34. Reaproveitamento de Código
Variáveis de Classe
Adicionando mais uma classe filha.
1 from class eEstudante import *
2
3 class Bolsista(Estudante):
4 def __init__(self , nome ,end ,fone ,curso ,periodo ,horario):
5 Estudante.__init__(self , nome , end , fone , curso , periodo)
6 self.horario = horario
7 def getHorario(self):
8 return self.horario
9 def __str__(self):
10 return "NOME: "+self.nome+" END. "+self.endereco+" nFONE: "+self.telefone
11 +" PERIODO: "+str(self.periodo)+" Horario: "+self.horario
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 28 / 84
35. Reaproveitamento de Código
Variáveis de Classe
Observe as diferenças.
1 from bolsista import *
2
3 def main ():
4 #Criando estudantes
5 st1 = Estudante("Pedro","Rua das Acácias , 42","91119999","In for mática" ,3)
6 st2 = Bolsista("Maria","Rua das Amêndoas , 32","91118741","Letras" ,5,"8-12 14 -18"
)
7 st3 = Bolsista("João","Rua das Oiticicas , 21","91113232","Engenharia" ,2,"8-12
14 -18")
8 st4 = Estudante("Fatima","Rua das Bromélias , 79","91114142","Direito" ,1)
9 #Imprimido um estudante
10 print("Um estudante : ",st1)
11 print("Um bolsista : ",st3)
12 #Imprimindo a lista de estudantes a partir da classe
13 print("Lista: ")
14 for i in Estudante. listaEstudantes : print(i)
15 print(" ------------------------------")
16 #imprimido a lista de uma instância
17 for i in st1. listaEstudantes : print(i)
18 #lasca
19 if __name__ =="__main__":
20 main ()
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 29 / 84
36. Reaproveitamento de Código
Resultado Final
Observe abaixo a saída do programa
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 30 / 84
37. Reaproveitamento de Código
Reaproveitamento das Classes do Python
Reaproveitando a classe list
1 from random import randint
2 class listaSimples (list):
3
4 def append(self , dado):
5 if dado not in self:
6 list.append(self ,dado)
7 return
8
9 def main ():
10 k = list () # ou k = []
11 z = listaSimples ()
12 for i in range (25):
13 numero = randint (1 ,50)
14 k.append(numero)
15 z.append(numero)
16 print("Normal ",k)
17 print("Simples ",z)
18
19 if __name__ == "__main__":
20 main ()
Saída:
Normal [22, 39, 15, 33, 18, 35, 28, 29, 30, 5, 35, 1, 32, 23, 16, 36, 28, 11, 14, 12, 30, 2, 1, 2, 12]
Simples [22, 39, 15, 33, 18, 35, 28, 29, 30, 5, 1, 32, 23, 16, 36, 11, 14, 12, 2]
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 31 / 84
38. Reaproveitamento de Código
Sobreescrita (Override)
Observemos as seguintes situações.
A classe coroa circular (primeira vez) é derivada da classe círculo.
Neste caso foi adicionado um método a mais chamado de
calculaAreaCoroa na classe filha.
Na segunda vez que criamos a coroa circular criamos a função
calulaArea identica a da classe Círculo
Na classe listaSimples foi escrito o método append que já estava
presente na classe mãe. O que aconteceu? —
O que vimos no dois últimos casos foi uma coisa chamada sobre-escrita ou
(overriding). Vimos que podemos usar a função super() ou até mesmo o
identificador da classe mãe para acessarmos a função re-escrita.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 32 / 84
39. Reaproveitamento de Código
Herança Múltipla
Observemos classe Pessoa abaixo.
1 class Pessoa:
2 def __init__(self ,nome ,end ,fone):
3 print("Executando Costrutor de Pessoa ")
4 self.nome ,self.endereco ,self.telefone =
nome ,end ,fone
5 def __str__(self):
6 return "NOME: "+self.nome+" END. "+self.
endereco+" FONE: "+self.telefone
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 33 / 84
40. Reaproveitamento de Código
Herança Múltipla
E agora a classe Estudante.
1 from pessoa import *
2 class Estudante(Pessoa):
3 listaEstudantes = []
4 def __init__(self ,nome ,end ,fone ,curso ,periodo):
5 print("Executando o construtor de Estudante
")
6 Pessoa.__init__(self , nome ,end ,fone)
7 self.curso = curso
8 self.periodo = periodo
9 Estudante. listaEstudantes .append(self)
10
11 def calculaIra(self):
12 return 0
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 34 / 84
41. Reaproveitamento de Código
Herança Múltipla
E agora a classe Professor.
1 from pessoa import *
2 class Professor(Pessoa):
3 listaProfessores = []
4 def __init__(self ,nome ,end ,fone ,listaCursos):
5 print("Executando o construtor de Professor
")
6 Pessoa.__init__(self , nome ,end ,fone)
7 self.listaCursos = listaCursos
8 Professor. listaProfessores .append(self)
9
10 def calculaCargaHoraria (self):
11 return 0
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 35 / 84
42. Reaproveitamento de Código
Herança Múltipla
Agora imagine um aluno que também é professor. Uma espécie de
estagiário de ensino.
1 from estudante import *
2 from professor import *
3 class EstagiarioEnsino (Estudante ,Professor):
4 def __init__(self ,nome ,end ,fone ,curso ,periodo ,
listaCursos ,duracaoEstagio ):
5 print("Iniciando construtor de estagiário "
)
6 Estudante.__init__(self , nome , end , fone ,
curso , periodo)
7 Professor.__init__(self , nome , end , fone ,
listaCursos)
8 self.duracaoEstagio = duracaoEstagio
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 36 / 84
43. Reaproveitamento de Código
Herança Múltipla
Agora vamos usar tudo.
1 from estagiario import *
2 def main ():
3 print("Atenção para a ordem de chamada dos
construtores ")
4 st = EstagiarioEnsino ("Pedro","Rua das Acacias
43", "98213344","Mecânica" ,6,["logica","
Programação"],24)
5 print("Estagiário criado")
6
7 if __name__ =="__main__":
8 main ()
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 37 / 84
45. Reaproveitamento de Código
Herança Múltipla - O problema do Diamante
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 39 / 84
46. Reaproveitamento de Código
Vejamos algumas modificações no código anterior.Classe
Estudante
1 from pessoa import *
2 class Estudante(Pessoa):
3 listaEstudantes = []
4 def __init__(self ,nome ,end ,fone ,curso ,periodo):
5 print("Executando o construtor de Estudante
")
6 super ().__init__(self ,nome ,end ,fone)
7 self.curso = curso
8 self.periodo = periodo
9
10 def calculaIra(self):
11 return 0
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 40 / 84
47. Reaproveitamento de Código
Classe Professor.
1 from pessoa import *
2 class Professor(Pessoa):
3 listaProfessores = []
4 def __init__(self ,nome ,end ,fone ,listaCursos):
5 print("Executando o construtor de Professor
")
6 super ().__init__(nome ,end ,fone)
7 self.listaCursos = listaCursos
8
9 def calculaCargaHoraria (self):
10 return 0
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 41 / 84
48. Reaproveitamento de Código
Classe Estagiário.
1 from estudanteModificado import *
2 from professorModificado import *
3 class EstagiarioEnsino (Estudante ,Professor):
4 def __init__(self ,nome ,end ,fone ,curso ,periodo ,
listaCursos ,duracaoEstagio ):
5 print("Iniciando construtor de estagiário "
)
6 super ().__init__(nome , end , fone , curso ,
periodo)
7 self.duracaoEstagio = duracaoEstagio
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 42 / 84
49. Reaproveitamento de Código
Finalmente usando tudo.
1 from pessoa import *
2 from estudanteModificado import *
3 from professorModificado import *
4 from estagiarioModificado import *
5
6 def main ():
7 print("Atenção para a ordem de chamada dos
construtores ")
8 st = EstagiarioEnsino ("Pedro","Rua das Acacias
43", "98213344","Mecânica" ,6,["logica","
Programação"],24)
9 print("Estagiário criado")
10
11 if __name__ =="__main__":
12 main ()
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 43 / 84
50. Reaproveitamento de Código
Saída ...
Isso ocorre devido ao algoritmo e MRO (method resolution order). Ver
documentação.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 44 / 84
51. Reaproveitamento de Código
ATENÇÃO. Probleminha com argumentos.
Os argumentos mudam ao chamar funções da classe mãe pela classe ou
pela função super()
Pessoa.__init__(self,nome,end,fone)
super().__init__(nome,end,fone)
As classes mães podem ter listas de argumentos diferentes. Como quem
decide é o compilador, poderemos ter problemas.
Classe Estudante:
def __init__(self,nome,end,fone,curso,periodo):
˙..
Classe Professor:
def __init__(self,nome,end,fone,listaCursos):
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 45 / 84
52. Reaproveitamento de Código
Solução: Sobrecarga?? Argumentos Flexíveis
Assinatura de Método
O tipo de retorno, o nome do método e o conjunto de argumentos formam
o que chamamos assinatura do método.
Linguagens como C++ e Java pemitem a sobrecarga de métodos pelo uso
de métodos com assinaturas diferentes.
Ex (em Java).
void imprime(String str,int i){System.out.println(str+i);}
void imprime(int i){ System.out.println(" "+i);}
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 46 / 84
53. Reaproveitamento de Código
Solução: Sobrecarga?? Argumentos Flexíveis
Python usa argumentos flexíveis de várias formas.
Tipos e Retorno dinâmicos (Duck Typing)
def calcula(a,b):
˙..
calcula(3,4)
Argumentos default
def calcula(a=1,b=3,c="maria"):
˙..
calcula(1)
calcula(1,2)
calcula(1,2,"pedro")
˙.
Listas de argumentos
def calcula(*list):
continua ..
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 47 / 84
54. Reaproveitamento de Código
Listas de Argumentos
Observe a definição da função calcula(*lista). O operador * em lista
implica que o compilador aceitará qualquer lista de argumentos e colocará
em uma lista de strings de nome lista.
1 def imprimeArgs (* args):
2 print("nLista de argumentos:",end="")
3 for a in args: print(a,end=",")
4 def main ():
5 imprimeArgs ()
6 imprimeArgs("Uma String")
7 imprimeArgs (23)
8 imprimeArgs("Uma string" ,2,"Segunda String"
,[1,2,3,4]," e muito mais")
9 if __name__ =="__main__":
10 main ()
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 48 / 84
55. Reaproveitamento de Código
Listas de Argumentos - Saída
Observe a saída do programa anterior.
Lista de argumentos:
Lista de argumentos:Uma String,
Lista de argumentos:23,
Lista de argumentos:Uma string,2,Segunda String,[1, 2, 3, 4], e muito
mais,
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 49 / 84
56. Reaproveitamento de Código
Listas de Argumentos
O duplo ** nos remete a criação de uma estrutura de dados chamada
dicionário. Veja.
1 def imprimeArgs (** kwargs):
2 print(kwargs)
3
4 if __name__ =="__main__":
5 imprimeArgs(nome="maria",idade =25, estadoCivil="
solteira")
Saída.
’nome’: ’maria’, ’idade’: 25, ’estadoCivil’: ’solteira’
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 50 / 84
57. Reaproveitamento de Código
Listas de Argumentos
Trabalhando um pouco os argumentos
1 def imprimeArgs (** kwargs):
2 for rotulo ,valor in kwargs.items ():
3 print("%s = %s"%(rotulo , valor))
4 if __name__ =="__main__":
5 imprimeArgs(nome="maria",idade =25, estadoCivil="
solteira")
Saída.
idade = 25
estadoCivil = solteira
nome = maria
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 51 / 84
58. Reaproveitamento de Código
Sobrecarga de Operadores
Observe as operações aritméticas:
2 + 2 = 4 (inteiro + inteiro = inteiro)
3.5 + 1.5 = 5.0 (float + float = float)
"xica "+"da"+"silva"= "xica da silva" (string + string = string)
Sobrecarga de Operadores
A redefinição do comportamento dos operadores para trabalhar com
diferentes tipos de dados.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 52 / 84
59. Reaproveitamento de Código
Sobrecarga de Operadores - Exemplo
Observe a classe Racional.
1 import math
2 class Racional:
3 def __init__(self , dividendo , divisor):
4 self.dividendo = dividendo
5 self.divisor = divisor
6 def __str__(self):
7 return str(self.dividendo) + ’/’ + str(self
.divisor)
8 def __mul__(self , outro):
9 divisor = self.divisor*outro.divisor
10 dividendo = self.dividendo*outro.dividendo
11 return Racional(dividendo , divisor)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 53 / 84
60. Reaproveitamento de Código
Sobrecarga de Operadores - Exemplo-Continuação
1 def mmc(self ,menor ,maior):
2 if(menor >maior):
3 menor ,maior = maior ,menor
4 mmc=maior
5 while mmc%maior != 0 and mmc%menor !=0:
mmc +=1
6 return mmc
7 def __add__(self ,outro):
8 divisor = self.mmc(self.divisor , outro.
divisor)
9 dividendo = int(divisor/self.divisor*self.
dividendo + divisor/outro.divisor*outro.
dividendo)
10 return Racional(dividendo ,divisor)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 54 / 84
61. Reaproveitamento de Código
Sobrecarga de Operadores - Exemplo-Continuação
1 from racional import *
2 a = Racional (1,2)
3 b = Racional (3,4)
4 c = a*b
5 d = a+b
6 print("Seja o racional a = ",a)
7 print("Seja o racional b = ",b)
8 print("Seja o racional c (a * b) = ",c)
9 print("Seja o racional d (a + b) = ",d)
Seja o racional a = 1/2
Seja o racional b = 3/4
Seja o racional c (a * b) = 3/8
Seja o racional d (a + b) = 5/4
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 55 / 84
62. Reaproveitamento de Código
Operadores Sobrecarregáveis
__add__: Adição.
__sub__: Subtração.
__mul__: Multiplicação.
__truediv__: Divisão.
__mod__: Resto da divisão.
__pos__: Identidade.
__neg__: Negativo.
__abs__: Absoluto.
Ver documentação do Python para maiores informações.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 56 / 84
63. Reaproveitamento de Código
Polimorfismo
Nas linguagens modernas, polimorfismo se refere ao fato de que o
compilador seja capaz de identificar em tempo de execução (durante a
execução do programa) qual a subclasse, dentro de uma hierarquia de
classes, que responderá a uma determinada chamada de método.
1 class Video:
2 def __init__(self , arquivo):
3 if not arquivo.endswith(self.ext):
4 raise Exception("Formato de vídeo
Inválido")
5 self.arquivo = arquivo
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 57 / 84
64. Reaproveitamento de Código
Polimorfismo
1 from arquivoVideo import *
2 class VideoMP4(Video):
3 ext = "mp4"
4 def reproduzir(self):
5 print("Reproduzindo {} como mp4".for mat(self.
arquivo))
6 class VideoAVI(Video):
7 ext = "avi"
8 def reproduzir(self):
9 print("Reproduzindo {} como avi".for mat(self.
arquivo))
10 class VideoMOV(Video):
11 ext = "mov"
12 def reproduzir(self):
13 print("Reproduzindo {} como mov".for mat(self.
arquivo))
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 58 / 84
65. Reaproveitamento de Código
Polimorfismo
1 from videoMP4 import *
2
3 mp4 = VideoMP4("filme.mp4")
4 mp4.reproduzir ()
5 avi = VideoAVI("filme.avi")
6 avi.reproduzir ()
7 mov = VideoMOV("filme.mov")
8 mov.reproduzir ()
9 #outro = VideoMP4 (" filme.avi")
Saída Normal
Reproduzindo filme.mp4 como mp4
Reproduzindo filme.avi como avi
Reproduzindo filme.mov como mov
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 59 / 84
66. Reaproveitamento de Código
Polimorfismo
1 from videoMP4 import *
2
3 outro = VideoMP4("filme.avi")
Saída Normal
Traceback (most recent call last): File "/home/ramos/googleDrive/in-
Progress/tutorialPOO/latex/fontes/reproduz2.py", line 3, in <module>
outro = VideoMP4("filme.avi")
raise Exception("Formato de vídeo Inválido")
Exception: Formato de vídeo Inválido
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 60 / 84
67. Reaproveitamento de Código
Polimorfismo
Duck Typing (Tipos dinâmicos) do Python provêm uma forma muito mais
poderosa de polimorfismo que o apresentado pelas linguagens que usam
tipos estáticos.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 61 / 84
68. Controle de Erros
Exceções
Erros durante a execução do programa que normalmente interrompem a
sua sequência natural.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 62 / 84
69. Controle de Erros
Exceções
Erros de sintaxe
>>>print "hello world"
File "<stdin>", line 1
print "hello world"
SyntaxError: invalid syntax
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 63 / 84
70. Controle de Erros
Exceções
Divisão por zero.
>>> x = 5 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: int division or modulo by zero
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 64 / 84
71. Controle de Erros
Exceções
Passsando dos limites.
>>> lst = [1,2,3]
>>> print(lst[3])
Traceback (most recent call last):
File «stdin>", line 1, in <module>
IndexError: list index out of range
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 65 / 84
72. Controle de Erros
Exceções
Operação impossível.
>>> lst + 2
Traceback (most recent call last):
File «stdin>", line 1, in <module>
TypeError: can only concatenate list (not "int") to list
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 66 / 84
73. Controle de Erros
Exceções
Exceções são disparadas pelo Python ou por você.
1 def media(a,b):
2 if not(isinstance(a, int) and isinstance(b, int
)):
3 raise TypeError("Somente numeros")
4 return (a+b)/2.0
5 print("A media entre 3 e 4 é ",media (3,4))
6 print("a média entre maira e pedro é ",media("maria
","pedro"))
Saída
TypeError: Somente numeros
A media entre 3 e 4 é 3.5
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 67 / 84
74. Controle de Erros
Tratamento de Exceções
As exceções podem ser tratadas evitando que o programa seja
interrompido de forma que se tente contornar a situação de erro.
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 68 / 84
75. Controle de Erros
Tratamento de Exceções - Construção try . . . except.
1 import math
2 def raizes(a,b,c):
3 try:
4 x1 = -b+math.sqrt(b*b-4*a*c)/(2*a)
5 x2 = -b-math.sqrt(b*b-4*a*c)/(2*a)
6 except ValueError:
7 return "Equação não tem raízes"
8 return x1 ,x2
9 print("Raizes de 3,4,5 : ",raizes (3,4,5))
Saída
Raizes de 3,4,5 : Equação não tem raízes
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 69 / 84
76. Controle de Erros
Tratamento de Exceções - Construção try . . . except.
1 import math
2 def raizes(a,b,c):
3 try:
4 x1 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
5 x2 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
6 except ValueError:
7 return "Equação não tem raízes"
8 return x1 ,x2
9 print("Raizes de 3,4,-5 : ",raizes (3,4,-5))
Saída
Raizes de 3,4,-5 : (0.7862996478468913, -2.119632981180225)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 70 / 84
77. Controle de Erros
Tratamento de Exceções - try - except aninhados.
1 import math
2 def raizes(a,b,c):
3 try:
4 try:
5 x1 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
6 x2 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
7 except ValueError:
8 return "Equação não tem raízes"
9 except ZeroDivisionError :
10 return "Valores nulos"
11 return x1 ,x2
12 print("Raízes de 3,4,5 : ",raizes (3,4,5))
13 print("Raizes de 0,0,0 : ",raizes (0,0,0))
Saída
Raízes de 3,4,5 : Equação não tem raízes
Raizes de 0,0,0 : Valores nulos
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 71 / 84
78. Controle de Erros
Tratamento de Exceções - try - except aninhados.
1 import math
2 def raizes(a,b,c):
3 try:
4 x1 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
5 x2 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
6 except ValueError:
7 return "Equação não tem raízes"
8 except ZeroDivisionError :
9 return "Valores nulos"
10 return x1 ,x2
11 print("Raízes de 3,4,5 : ",raizes (3,4,5))
12 print("Raizes de 0,0,0 : ",raizes (0,0,0))
Saída
Raízes de 3,4,5 : Equação não tem raízes
Raizes de 0,0,0 : Valores nulos
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 72 / 84
79. Controle de Erros
Tratamento de Exceções - try - except aninhados.
1 import math
2 def raizes(a,b,c):
3 try:
4 x1 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
5 x2 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
6 except ValueError:
7 return "Equação não tem raízes"
8 except Exception:
9 return "Valores nulos"
10 return x1 ,x2
11 print("Raízes de 3,4,5 : ",raizes (3,4,5))
12 print("Raizes de 0,0,0 : ",raizes (0,0,0))
Saída
Raízes de 3,4,5 : Equação não tem raízes
Raizes de 0,0,0 : Valores nulos
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 73 / 84
80. Controle de Erros
Tratamento de Exceções - Argumentos
1 import math
2 def raizes(a,b,c):
3 try:
4 x1 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
5 x2 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
6 except Exception as inst:
7 return "Erro: {0}".for mat(inst)
8 return x1 ,x2
9 print("Raízes de 3,4,5 : ",raizes (3,4,5))
10 print("Raizes de 0,0,0 : ",raizes (0,0,0))
Saída
Raízes de 3,4,5 : Erro: math domain error
Raizes de 0,0,0 : Erro: float division by zero
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 74 / 84
81. Controle de Erros
Tratamento de Exceções - Customização
1 import math
2 class DeltaNegativo(Exception):
3 def __init__(self):
4 super ().__init__("Delta negativo. A equação
não possui raízes reais")
5 def raizes(a,b,c):
6 try:
7 delta = b*b - 4 * a * c
8 if delta < 0:
9 raise DeltaNegativo
10 else:
11 x1 = (-b+math.sqrt(b*b-4*a*c))/(2*a)
12 x2 = (-b-math.sqrt(b*b-4*a*c))/(2*a)
13 except DeltaNegativo as de:
14 return "Erro {0}".for mat(de.args)
15 return x1 ,x2
16 print("Raízes de 3,4,5 : ",raizes (3,4,5))
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 75 / 84
82. Controle de Erros
Tratamento de Exceções - Customização
Saídas
Raízes de 3,4,5 : Erro (’Delta negativo. A equação não possui raízes
reais’,)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 76 / 84
83. Controle de Erros
Properties - Propriedades???
Controle de acesso a dados "privados". Veja o código abaixo.
1 class Pessoa:
2 def __init__(self ,nome="",endereco=""):
3 self._nome ,self._endereco = nome ,endereco
4 def _setNome(self ,nome):
5 print("Registrando nome.")
6 self._nome = nome
7 def _getNome(self):
8 print("Recuperando nome.")
9 return self._nome
10 nome = property(_getNome ,_setNome)
11 p = Pessoa ()
12 p.nome = "Raimundo dos Santos Pereira"
13 print("Pessoa = ",p.nome)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 77 / 84
84. Controle de Erros
Properties - Propriedades???
Saídas
Registrando nome.
Recuperando nome.
Pessoa = Raimundo dos Santos Pereira
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 78 / 84
85. Controle de Erros
Properties - Solução mais completa
1 class Pessoa:
2 def _setNome(self ,nome):
3 print("Registrando nome.")
4 self._nome = nome
5 def _getNome(self):
6 print("Recuperando nome.")
7 return self._nome
8 def _delNome(self):
9 print("Apagando o nome")
10 del self._nome
11 nome = property(_getNome ,_setNome ,_delNome ,"
Propriedade Nome ")
12 p = Pessoa ()
13 p.nome = "Raimundo dos Santos Pereira"
14 print("Pessoa = ",p.nome)
15 del p.nome
16 help(Pessoa)
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 79 / 84
86. Controle de Erros
Properties - Solução mais completa
Saídas
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 80 / 84
87. Controle de Erros
Properties - Usando Decorator
1 class Pessoa:
2 @property
3 def nome(self):
4 print("Recuperando nome.")
5 return self._nome
6 @nome.setter
7 def nome(self ,nome):
8 print("Registrando nome.")
9 self._nome = nome
10 @nome.deleter
11 def nome(self):
12 print("Apagando o nome")
13 del self._nome
14 p = Pessoa ()
15 p.nome = "Raimundo dos Santos Pereira"
16 print("Pessoa = ",p.nome)
17 del p.nome
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 81 / 84
88. Controle de Erros
Properties - Usando Decorator
Saída
Registrando nome.
Recuperando nome.
Pessoa = Raimundo dos Santos Pereira
Apagando o nome
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 82 / 84
89. Controle de Erros
Quando Usar o Quê
Modele objetos reais como objetos em código
Use propriedades para adicionar comportamento aos dados da
classe.
Use decorators para criar properties
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 83 / 84
90. Controle de Erros
Reutilização de Código na Prática
Agregação Ou composição
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 84 / 84
91. Controle de Erros
Estruturas de Dados em Python
tuplas dicionários, etc
Ronaldo F. Ramos (IFCE) Programação Orientada a Objetos 20 de abril de 2017 85 / 84