1 of 94

Classes e Objetos

Prof. Alysson Filgueira Milanez

alysson.milanez@academico.ifpb.edu.br

Programação 2

2 of 94

Classes e objetos

2

3 of 94

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

4 of 94

Classes

Uma definição de uma classe pode ser feita assim:

class Point:

pass

4

5 of 94

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

6 of 94

Classes

A definição de uma classe pode aparecer em qualquer lugar no código

6

7 of 94

Classes

Criando a classe Point nós criamos um novo tipo, também chamado Point

7

8 of 94

Classes

Quando uma classe é criada, todos os seus atributos serão inicializados pelo método __init__()

8

9 of 94

Classes

__init__() é o método que vai inicializar o objeto

9

10 of 94

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

11 of 94

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

12 of 94

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

13 of 94

Classes

Os itens que compõem uma classe são chamados de atributos

13

14 of 94

Classes

Nós podemos passar instâncias como argumentos para funções

def printPoint(p):

print('(' + str(p.x) + ', ' + str(p.y) + ')')

14

15 of 94

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

16 of 94

Classes

Não, pois o == irá comparar apenas as referências aos objetos, não o seu conteúdo

16

17 of 94

Classes

Exercício:

Crie a função samePoint que é capaz de determinar se o conteúdo de dois pontos é o mesmo

17

18 of 94

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

19 of 94

Classes

Instanciando a classe Conta

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

19

20 of 94

Classes

Para manipularmos nosso objeto conta e acessar seus atributos utilizamos o operador "." (ponto)

conta.titular

20

21 of 94

Classes

Como o self é a referência do objeto, ele chama self.titular e self.saldo da classe Conta

21

22 of 94

Classes

Objetos são mutáveis, logo, podemos alterar o saldo da conta de João:

conta.saldo = 200.0

22

23 of 94

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

24 of 94

Classes

Exercício:

Crie os métodos get e set para cada atributo da classe Conta

24

25 of 94

Métodos

25

26 of 94

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

27 of 94

Classes

def deposita(self, valor):

self.saldo += valor

27

28 of 94

Classes

Usamos o self para saber a que instância da classe Conta nos referimos

28

29 of 94

Classes

Vamos criar também os métodos saca e extrato

29

30 of 94

Classes

def saca(self, valor):

self.saldo -= valor

def extrato(self):

print("numero: {} \nsaldo: {}".format(self.numero, self.saldo))

30

31 of 94

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

32 of 94

Classes

Nosso método saca tem um problema, conseguem identificar?

Como podemos resolver?

32

33 of 94

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

34 of 94

Classes

Objetos são acessados por referências

A função id() retorna a referência de um objeto

34

35 of 94

Classes

Vamos criar o método transfere que transfere valores de uma conta a outra

35

36 of 94

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

37 of 94

Classes

O método transfere pode ser mais sucinto

Como?

37

38 of 94

Classes

def transfere(self, destino, valor):

if not self.saca(valor): return False

destino.deposita(valor)

return True

38

39 of 94

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

40 of 94

Classes

# Classe Cliente

class Cliente:

def __init__(self, nome, sobrenome, cpf):

self.nome = nome

self.sobrenome = sobrenome

self.cpf = cpf

40

41 of 94

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

42 of 94

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

43 of 94

Classes

Para impedir o acesso a um atributo no Python, inserimos dois underscores ('__') para isto

43

44 of 94

Classes

class Pessoa:

def __init__(self, idade):

self.__idade = idade

44

45 of 94

Classes

Para evitarmos acessos indevidos, o ideal é o uso de gets e sets

Como vimos nas classes No, List, Stack, ...

45

46 of 94

Classes

Podemos usar properties em Python para esconder de fato os atributos

46

47 of 94

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

48 of 94

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

49 of 94

Classes

Você só deve criar properties se tiver real necessidade

49

50 of 94

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

51 of 94

Classes

class Conta:

total_contas = 0 # atributo da classe Conta

def __init__(self, saldo):

self._saldo = saldo

Conta.total_contas += 1

51

52 of 94

Classes

>>> c = Conta(100)

>>> c.total_contas

1

>>> c2 = Conta(1000)

>>> c.total_contas

2

52

53 of 94

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

54 of 94

Classes

@classmethod

def get_total_contas(cls):

return cls._total_contas

cls é uma convenção da linguagem Python

54

55 of 94

Herança e Polimorfismo

55

56 of 94

Herança

Herança é a habilidade de definir uma classe como sendo uma versão modificada de uma classe existente

56

57 of 94

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

58 of 94

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

59 of 94

Herança

Fazemos isso acrescentando a classe mãe entre parênteses junto a classe filha

59

60 of 94

Herança

# Classe mae

class Funcionario:

def __init__(self, nome, cpf, salario):

self._nome = nome

self._cpf = cpf

self._salario = salario

60

61 of 94

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

62 of 94

Herança

62

Funcionario

Gerente

63 of 94

Herança

A classe Gerente herda todos os métodos e atributos da classe Funcionario

63

64 of 94

Herança

Claro que podemos ter diversas outras classes que herdam de Funcionario: Diretor, Secretario, Presidente, ...

64

65 of 94

Herança

No Python, quando herdamos um método, podemos alterar seu comportamento

65

66 of 94

Herança

Supondo que temos uma bonificação natalina de 10% para o funcionário comum e de 15% para o gerente

66

67 of 94

Herança

Em Funcionario fica:

def get_bonificacao(self):

return self._salario * 0.10

67

68 of 94

Herança

Em Gerente:

def get_bonificacao(self):

return self._salario * 0.15

68

69 of 94

Herança

Exemplo usando cartas e baralhos

69

70 of 94

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

71 of 94

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

72 of 94

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

73 of 94

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

74 of 94

Polimorfismo

Polimorfismo é a capacidade de um objeto poder ser referenciado de várias formas

74

75 of 94

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

76 of 94

Polimorfismo

Objetivo: diminuir o acoplamento entre as classes, para evitar que novos códigos resultem em modificações em inúmeros lugares

76

77 of 94

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

78 of 94

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

79 of 94

Polimorfismo

Vamos tornar Funcionario uma classe abstrata

import abc

class Funcionario(abc.ABC):

# ...

79

80 of 94

Polimorfismo

Agora vamos tornar nosso método get_bonificacao() abstrato

Para isso usamos o @abstractmethod

80

81 of 94

Polimorfismo

@abc.abstractmethod

def get_bonificacao(self):

pass

81

82 of 94

Herança Múltipla

82

83 of 94

Herança Múltipla

Python suporta herança múltipla: uma classe pode herdar de mais de uma

83

84 of 94

Herança Múltipla

class Autenticavel:

def autentica(self, senha):

# verifica se a senha confere

class Gerente(Funcionario, Autenticavel):

# ...

84

85 of 94

Herança Múltipla

Agora Gerente terá acesso aos métodos e atributos de ambas as classes

85

86 of 94

Exercícios

86

87 of 94

Exercícios

  1. Crie a classe Tempo com os atributos horas, minutos e segundos.

  • Crie o método imprimeTempo que imprime o tempo no formato horas:minutos:segundos.

  • Crie o método incremento que recebe um valor em segundos como parâmetro e adiciona o valor à hora atual.

87

88 of 94

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

89 of 94

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

90 of 94

Referências

90

91 of 94

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

92 of 94

Veja mais

92

93 of 94

Veja mais

93

94 of 94

Classes e Objetos

Prof. Alysson Filgueira Milanez

alysson.milanez@academico.ifpb.edu.br

Programação 2