Classes e Objetos
Prof. Alysson Filgueira Milanez
alysson.milanez@academico.ifpb.edu.br
Programação 2
Classes e objetos
2
Classes
Fazendo uma analogia entre a planta de uma casa e a casa em si: a planta é a classe e a casa construída é o objeto
3
Classes
Uma definição de uma classe pode ser feita assim:
class Point:
pass
4
Classes
Uma definição de uma classe pode ser feita assim:
class Point:
pass
5
pass não tem efeito, serve só para estar no corpo da classe
Classes
A definição de uma classe pode aparecer em qualquer lugar no código
6
Classes
Criando a classe Point nós criamos um novo tipo, também chamado Point
7
Classes
Quando uma classe é criada, todos os seus atributos serão inicializados pelo método __init__()
8
Classes
__init__() é o método que vai inicializar o objeto
9
Classes
Os membros deste tipo são chamados de instâncias do tipo ou objetos
Criar uma nova instância é uma instanciação
vazio = Point()
10
Classes
O método __new__() é o construtor e é quem realmente cria uma instância de Point
Ele é chamado pelo interpretador de Python antes do __init__()
11
Classes
Nós podemos adicionar novos dados a uma instância com a notação "." (ponto)
p = Point()
p.x = 10
p.y = 5
12
Classes
Os itens que compõem uma classe são chamados de atributos
13
Classes
Nós podemos passar instâncias como argumentos para funções
def printPoint(p):
print('(' + str(p.x) + ', ' + str(p.y) + ')')
14
Classes
Se nós criarmos dois objetos p1 e p2:
p1 = Point()
p1.x = 3
p1.y = 4
p2 = Point()
p2.x = 3
p2.x = 4
p1 == p2?
15
Classes
Não, pois o == irá comparar apenas as referências aos objetos, não o seu conteúdo
16
Classes
Exercício:
Crie a função samePoint que é capaz de determinar se o conteúdo de dois pontos é o mesmo
17
Classes
Vamos criar uma classe Conta
class Conta:
def __init__(self, numero, titular, saldo, limite):
self.numero = numero
self.titular = titular
self.saldo = saldo
self.limite = limite
18
Classes
Instanciando a classe Conta
conta = Conta('123-4', 'João', 120.0, 1000.0)
19
Classes
Para manipularmos nosso objeto conta e acessar seus atributos utilizamos o operador "." (ponto)
conta.titular
20
Classes
Como o self é a referência do objeto, ele chama self.titular e self.saldo da classe Conta
21
Classes
Objetos são mutáveis, logo, podemos alterar o saldo da conta de João:
conta.saldo = 200.0
22
Classes
Usualmente não queremos editar os valores dos nossos atributos diretamente
Quando usamos classes em nossas estruturas de dados tínhamos gets e sets
23
Classes
Exercício:
Crie os métodos get e set para cada atributo da classe Conta
24
Métodos
25
Classes
Vamos criar o método deposita() na classe Conta
O método deve receber a instância do objeto (self) além do valor a ser depositado
26
Classes
def deposita(self, valor):
self.saldo += valor
27
Classes
Usamos o self para saber a que instância da classe Conta nos referimos
28
Classes
Vamos criar também os métodos saca e extrato
29
Classes
def saca(self, valor):
self.saldo -= valor
def extrato(self):
print("numero: {} \nsaldo: {}".format(self.numero, self.saldo))
30
Classes
Testando nossos métodos
>>> conta = Conta('123-4', 'João', 120.0, 1000.0)
>>> conta.deposita(20)
>>> conta.extrato()
numero: 123-4
saldo: 140.0
>>> conta.saca(15)
>>> conta.extrato()
numero: 123-4
saldo: 125.0
31
Classes
Nosso método saca tem um problema, conseguem identificar?
Como podemos resolver?
32
Classes
# metodo saca considerando que o valor pode ser > que o saldo
def saca(self, valor):
if valor <= self.saldo:
self.saldo -= valor
return True
return False
33
Classes
Objetos são acessados por referências
A função id() retorna a referência de um objeto
34
Classes
Vamos criar o método transfere que transfere valores de uma conta a outra
35
Classes
# transfere checa se a conta origem tem saldo suficiente
def transfere(self, destino, valor):
retirou = self.saca(valor)
if not retirou: return False
destino.deposita(valor)
return True
36
Classes
O método transfere pode ser mais sucinto
Como?
37
Classes
def transfere(self, destino, valor):
if not self.saca(valor): return False
destino.deposita(valor)
return True
38
Classes
Uma classe pode ter outra(s) classe(s) como atributo(s)
Uma conta tem um cliente, então podemos definir a nossa classe Cliente com os atributos adequados
39
Classes
# Classe Cliente
class Cliente:
def __init__(self, nome, sobrenome, cpf):
self.nome = nome
self.sobrenome = sobrenome
self.cpf = cpf
40
Classes
A partir de agora, o titular de cada conta passa a ser um objeto do tipo Cliente
Essa relação entre Conta e Cliente é uma agregação: um objeto existe independentemente do outro
41
Classes
Mas podemos ter o caso de composição: a existência de um objeto depende do outro
Um exemplo seria termos um histórico das transações da nossa Conta
42
Classes
Para impedir o acesso a um atributo no Python, inserimos dois underscores ('__') para isto
43
Classes
class Pessoa:
def __init__(self, idade):
self.__idade = idade
44
Classes
Para evitarmos acessos indevidos, o ideal é o uso de gets e sets
Como vimos nas classes No, List, Stack, ...
45
Classes
Podemos usar properties em Python para esconder de fato os atributos
46
Classes
class Conta:
def __init__(self, saldo=0.0):
self._saldo = saldo
@property
def saldo(self):
return self._saldo
@saldo.setter
def saldo(self, saldo):
if(self._saldo < 0):
print("saldo não pode ser negativo")
else:
self._saldo = saldo
47
Classes
Esta é uma forma elegante de encapsular os nossos atributos
>>> conta = Conta(1000.0)
>>> conta.saldo = -300.0
"saldo não pode ser negativo"
48
Classes
Você só deve criar properties se tiver real necessidade
49
Classes
Podemos ter a necessidade de que um atributo seja da classe e não do objeto, para isso, declaramos o atributo fora do método __init__()
50
Classes
class Conta:
total_contas = 0 # atributo da classe Conta
def __init__(self, saldo):
self._saldo = saldo
Conta.total_contas += 1
51
Classes
>>> c = Conta(100)
>>> c.total_contas
1
>>> c2 = Conta(1000)
>>> c.total_contas
2
52
Classes
Métodos de classe servem para definir um método que opera na classe, e não em instâncias
Para usar, basta anotar o método com @classmethod
53
Classes
@classmethod
def get_total_contas(cls):
return cls._total_contas
cls é uma convenção da linguagem Python
54
Herança e Polimorfismo
55
Herança
Herança é a habilidade de definir uma classe como sendo uma versão modificada de uma classe existente
56
Herança
A ideia para herança surge quando passamos a repetir código
Exemplo: em uma empresa temos vários tipos de funcionários e, sem herança, teremos uma boa quantidade de repetição de código entre as classes
57
Herança
Existe um jeito de relacionarmos uma classe de tal maneira que uma delas herda tudo que o outra tem
Isto é uma relação de herança, uma relação entre classe 'mãe' e classe 'filha'
58
Herança
Fazemos isso acrescentando a classe mãe entre parênteses junto a classe filha
59
Herança
# Classe mae
class Funcionario:
def __init__(self, nome, cpf, salario):
self._nome = nome
self._cpf = cpf
self._salario = salario
60
Herança
# Classe filha
class Gerente(Funcionario):
def __init__(self, nome, cpf, salario, senha, qtd_func):
super().__init__(nome, cpf, salario)
self._senha = senha
self._qtd_funcionarios = qtd_func
61
Herança
62
Funcionario
Gerente
Herança
A classe Gerente herda todos os métodos e atributos da classe Funcionario
63
Herança
Claro que podemos ter diversas outras classes que herdam de Funcionario: Diretor, Secretario, Presidente, ...
64
Herança
No Python, quando herdamos um método, podemos alterar seu comportamento
65
Herança
Supondo que temos uma bonificação natalina de 10% para o funcionário comum e de 15% para o gerente
66
Herança
Em Funcionario fica:
def get_bonificacao(self):
return self._salario * 0.10
67
Herança
Em Gerente:
def get_bonificacao(self):
return self._salario * 0.15
68
Herança
Exemplo usando cartas e baralhos
69
Herança
class Card:
suitList = ["Clubs", "Diamonds", "Hearts", "Spades"]
rankList = ["narf", "Ace", "2", "3", "4", "5", "6", "7","8", "9", "10", "Jack", "Queen", "King"]
def __init__(self, suit=0, rank=2):
self.suit = suit
self.rank = rank
def __str__(self):
return (self.rankList[self.rank] + " of " + self.suitList[self.suit])
70
Herança
class Deck:
def __init__(self):
self.cards = []
for suit in range(4):
for rank in range(1, 14):
self.cards.append(Card(suit, rank))
def print_deck(self):
for card in self.cards:
print(card)
71
Herança
def shuffle(self):
import random
nCards = len(self.cards)
for i in range(nCards):
j = random.randrange(i, nCards)
self.cards[i], self.cards[j] = self.cards[j], self.cards[i]
def remove_card(self, card):
if card in self.cards:
self.cards.remove(card)
return True
return False
def is_empty(self):
return len(self.cards) == 0
72
Herança
# heranca
class Hand(Deck):
def __init__(self, name=""):
self.cards = []
self.name = name
def add_card(self, card):
self.cards.append(card)
73
Polimorfismo
Polimorfismo é a capacidade de um objeto poder ser referenciado de várias formas
74
Polimorfismo
Para determinarmos se uma função pode ser aplicada a um novo tipo, usamos a regra: Se todas as operações dentro da função podem ser aplicadas ao tipo, a função pode ser aplicada ao tipo
75
Polimorfismo
Objetivo: diminuir o acoplamento entre as classes, para evitar que novos códigos resultem em modificações em inúmeros lugares
76
Polimorfismo
# Classe com metodo polimorfico
class ControleDeBonificacoes:
def __init__(self, total_bonificacoes=0):
self._total_bonificacoes = total_bonificacoes
# metodo polimorfico
def registra(self, funcionario):
self._total_bonificacoes += funcionario.get_bonificacao()
@property
def total_bonificacoes(self):
return self._total_bonificacoes
77
Polimorfismo
Classes abstratas podem ser usadas para definirmos classes que não podem ser instanciadas
Em Python, usamos o módulo abc para isso e todas as classes abstratas precisam herdar de ABC
78
Polimorfismo
Vamos tornar Funcionario uma classe abstrata
import abc
class Funcionario(abc.ABC):
# ...
79
Polimorfismo
Agora vamos tornar nosso método get_bonificacao() abstrato
Para isso usamos o @abstractmethod
80
Polimorfismo
@abc.abstractmethod
def get_bonificacao(self):
pass
81
Herança Múltipla
82
Herança Múltipla
Python suporta herança múltipla: uma classe pode herdar de mais de uma
83
Herança Múltipla
class Autenticavel:
def autentica(self, senha):
# verifica se a senha confere
class Gerente(Funcionario, Autenticavel):
# ...
84
Herança Múltipla
Agora Gerente terá acesso aos métodos e atributos de ambas as classes
85
Exercícios
86
Exercícios
87
Exercícios
4. Crie a classe Ponto com as coordenadas x e y sendo opcionais.
5. Crie o método __str__() para as classes Ponto e Tempo.
6. Crie a classe ContaCorrente e faça com que ela seja subclasse (filha) da classe Conta
88
Exercícios
7. Crie a classe ContaPoupanca e faça com que ela seja subclasse (filha) da classe Conta
8. Adicione na classe Conta um novo método chamado atualiza() que atualiza a conta de acordo com a taxa percentual
89
Referências
90
Referências
Downey, A.; Elkner, J; Meyers, C. How to Think Like a Computer Scientist: Learning with Python
Caps. 12, 13, 14 e 16
Python e Orientação a Objetos. Curso Py-14. Caelum
Caps. 7, 8, 10 e 11
91
Veja mais
92
Veja mais
93
Classes e Objetos
Prof. Alysson Filgueira Milanez
alysson.milanez@academico.ifpb.edu.br
Programação 2