A herança é um conceito fundamental na programação orientada a objetos e torna-se crucial para criar aplicações robustas, reutilizáveis e de fácil manutenção. Neste capítulo, exploraremos o conceito de herança em Python, a forma como se define e utiliza classes base e derivadas, e veremos exemplos práticos para solidificar o nosso entendimento.
Introdução à Herança
Herança permite que uma classe (a classe derivada) herde atributos e métodos de outra classe (a classe base). Isto promove a reutilização de código e facilita a criação de novas funcionalidades sem necessidade de reescrever código já escrito. A sintaxe básica para a definição de uma classe derivada é:
class ClasseBase:
def __init__(self):
print("Inicialização ClasseBase")
def metodo_base(self):
print("Método da ClasseBase")
class ClasseDerivada(ClasseBase):
def __init__(self):
super().__init__()
print("Inicialização ClasseDerivada")
def metodo_derivado(self):
print("Método da ClasseDerivada")
Ao usar super().__init__()
, garantimos que o construtor da classe base é chamado, inicializando apropriadamente os componentes da classe base antes de executar qualquer código adicional na classe derivada.
Ao falamos em Herança temos que introduzir um novo conceito:
Protegido
- Atributos e métodos protegidos são indicados com um underscore (_) no início do nome. Estes atributos não podem ser acedidos fora da classe e das suas subclasses.
Exemplo Prático: Sistema de Funcionários
Vamos criar um exemplo prático onde veremos como gerir diferentes tipos de funcionários numa organização, utilizando herança para evitar duplicação de código.
Passo 1: Definir a Classe Base Funcionario
class Funcionario:
def __init__(self, nome, salario):
self._nome = nome
self._salario = salario
def mostrar_detalhes(self):
print(f"Nome: {self._nome}, Salário: {self._salario}")
func = Funcionario("Teste", 200)
func.mostrar_detalhes()
Nome: Teste, Salário: 200
A classe Funcionario
contém atributos genéricos como nome
e salario
, e um método para mostrar esses detalhes.
Passo 2: Definir Classes Derivadas Gerente
e Programador
class Gerente(Funcionario):
def __init__(self, nome, salario, departamento):
super().__init__(nome, salario)
self._departamento = departamento
def mostrar_detalhes(self):
super().mostrar_detalhes()
print(f"Departamento: {self._departamento}")
class Programador(Funcionario):
def __init__(self, nome, salario, linguagens):
super().__init__(nome, salario)
self._linguagens = linguagens
def mostrar_detalhes(self):
super().mostrar_detalhes()
print(f"Linguagens: {', '.join(self._linguagens)}")
Estas classes derivadas estendem Funcionario
, adicionando atributos específicos e modificando o método mostrar_detalhes
para incluir as novas informações.
Passo 3: Utilizar as Classes
gerente = Gerente("Ana", 4000, "Vendas")
programador = Programador("Carlos", 3000, ["Python", "Java"])
gerente.mostrar_detalhes()
programador.mostrar_detalhes()
Este código instanciará objetos das classes Gerente
e Desenvolvedor
e demonstrará como as classes derivadas utilizam e estendem a funcionalidade da classe base.
Herança Múltipla
Python também suporta herança múltipla, onde uma classe pode herdar de mais de uma classe base. Embora poderosa, a herança múltipla deve ser usada com cautela devido a possíveis ambiguidades no momento da resolução de métodos.
class ClasseA:
def metodo(self):
print("Método da ClasseA")
class ClasseB:
def metodo(self):
print("Método da ClasseB")
class ClasseC(ClasseA, ClasseB):
pass
obj = ClasseC()
obj.metodo()
No exemplo acima, o método metodo
da ClasseA
será invocado ao invés do da ClasseB
, pois ClasseA
é listada primeiro na definição da ClasseC
. Porém, podemos usar super()
para invocar métodos específicos de uma cadeia de herança.
Resumo
Neste capítulo, aprendemos sobre a herança em Python e como reutilizar código existente para criar novas funcionalidades. Usamos herança para expandir a funcionalidade de uma classe base em classes derivadas e exploramos a herança múltipla.
Quiz
-
Qual é o principal benefício de utilizar herança em programação orientada a objetos?
- a) Melhorar a performance do programa
- b) Facilitar a reutilização de código
- c) Reduzir o tamanho do código fonte
- d) Todas as anteriores
-
O que faz a função
super()
numa classe derivada?- a) Chama o método inicial da própria classe derivada
- b) Chama o construtor da classe base
- c) Define a prioridade de métodos na herança múltipla
- d) Nenhuma das anteriores
-
O que ocorrerá se uma classe derivate não chamar explicitamente o construtor da classe base?
- a) O Python irá gerar um erro de execução
- b) Os atributos da classe base não serão inicializados
- c) Será usado um construtor de classe base padrão automaticamente
- d) Nada acontecerá, o programa correrá como esperado
-
Na herança múltipla, qual critério o Python usa para decidir qual método chamar se o mesmo método existir em várias classes base?
- a) A complexidade do método
- b) A ordem de definição das classes base
- c) A sintaxe do método
- d) A primeira classe base definida no corpo da classe derivada