• Python
  • 12. Python intermediário
  • Classes

Classes

Herança

Uma característica importante de classes é que podemos criar extensões de uma classe, adicionando mais atributos ou métodos, ou até mesmo modificando métodos que já existiam anteriormente. Não vamos entrar em detalhes, pois isso será o foco de discussões do próximo semestre, mas apresentaremos algumas noções neste handout.

Suponha que estamos implementando um sistema para o controle do aluguel de carros. Nesse sistema, nós temos diversos tipos de usuário, mas todos os usuários possuem um login e senha.

Exercício 1

Qual das opções abaixo é uma classe válida para o nosso objetivo de armazenar dados de usuários no nosso sistema?

Resposta

O __init__ é o construtor da classe Usuario. Ele recebe os argumentos login e senha e armazena esses valores no objeto recém criado (self).

Agora, suponha que queremos criar um tipo especial de usuário, o colaborador. O usuário colaborador possui um atributo adicional, o salário. Assim, queremos que o colaborador tenha tudo o que o usuário tem e mais algumas coisas. Um detalhe importante aqui: o colaborador é um Usuario com mais algumas coisas, ou seja, ele estende a classe Usuario. Esse é o conceito de herança em programação: podemos criar uma classe herda os atributos e métodos de outra e adiciona ou modifica a sua funcionalidade. Isso é feito em Python1 colocando o nome da classe da qual estamos herdando entre parênteses: class Colaborador(Usuario).

Vamos agora pensar no restante do código da classe Colaborador.

Exercício 2

Qual é o problema com o código abaixo:

class Colaborador(Usuario):
    def __init__(self, salario):
        self.salario = salario

Resposta

Como um Colaborador é um Usuario, ele deveria ter um login e senha, mas ele possui apenas um atributo salario.

Todo Usuario possui login e senha, portanto o Colaborador também deveria ter esses atributos. O código abaixo poderia resolver esse problema:

class Colaborador(Usuario):
    def __init__(self, login, senha, salario):
        self.login = login
        self.senha = senha
        self.salario = salario

Entretanto, o construtor da classe Usuario já armazena o login e a senha. Para utilizar o construtor da classe mãe (também chamda de superclasse) a partir do código da classe filha, podemos usar a função super():

class Colaborador(Usuario):
    def __init__(self, login, senha, salario):
        super().__init__(login, senha)  # Chama o construtor da superclasse
        self.salario = salario

É possível fazer muito mais com herança, mas deixaremos essa discussão para o segundo semestre.


  1. Cuidado! É muito comum abusarmos do uso de herança quando aprendemos esse conceito. A herança deve ser usada com moderação, apenas quando realmente faz sentido. Uma maneira de avaliar se uma herança faz sentido é utilizando o "é um". Se for razoável dizer que um objeto de uma classe filha também é um objeto da classe mãe, a herança pode fazer sentido. Caso contrário, procure evitar. No nosso exemplo, um Colaborador é um Usuario. Note que o contrário não faz sentido: um Usuario não necessariamente é um Colaborador