Herança em Python
A herança permite criar uma nova classe com base em uma já existente. Juntamente com a encapsulação, a herança é um dos pilares da programação orientada a objetos.
Os principais conceitos na herança são subclasse e superclasse. A subclasse herda todos os atributos e métodos públicos da superclasse. A superclasse também é chamada de classe base ou classe pai, enquanto a subclasse é conhecida como classe derivada ou classe filha.
O seguinte é o exemplo da sintaxe para herança de classes:
class Subclasse(Superclasse):
métodos_subclassePor exemplo, temos uma classe Person, que representa uma pessoa:
class Person:
def __init__(self, name):
self.__name = name # nome da pessoa
@property
def name(self):
return self.__name
def display_info(self):
print(f"Name: {self.__name}")Agora, vamos supor que precisamos de uma classe Employee para representar um funcionário de uma empresa. Podemos criar essa classe do zero:
class Employee:
def __init__(self, name):
self.__name = name # nome do funcionário
@property
def name(self):
return self.__name
def display_info(self):
print(f"Name: {self.__name}")
def work(self):
print(f"{self.name} works")No entanto, a classe Employee possui os mesmos atributos e métodos que a classe Person, pois um funcionário é, afinal, uma pessoa. O código da classe Employee repete a funcionalidade da classe Person, exceto pelo método work. Para evitar essa duplicação de código, podemos aplicar a herança.
Assim, vamos herdar a classe Employee da classe Person:
class Person:
def __init__(self, name):
self.__name = name # nome da pessoa
@property
def name(self):
return self.__name
def display_info(self):
print(f"Name: {self.__name}")
class Employee(Person):
def work(self):
print(f"{self.name} works")
tom = Employee("Tom")
print(tom.name) # Tom
tom.display_info() # Name: Tom
tom.work() # Tom worksA classe Employee herda totalmente a funcionalidade da classe Person e adiciona seu próprio método work. Dessa forma, ao criar um objeto da classe Employee, podemos utilizar o construtor herdado de Person:
tom = Employee("Tom")Também podemos acessar os atributos e métodos herdados:
print(tom.name) # Tom
tom.display_info() # Name: TomVale lembrar que Employee não pode acessar atributos privados da superclasse, como o atributo __name. Por exemplo, não é possível usar self.__name diretamente no método work:
def work(self):
print(f"{self.__name} works") # Erro!Herança Múltipla
Uma característica distintiva do Python é o suporte à herança múltipla, onde uma classe pode herdar de várias classes:
# Classe Employee
class Employee:
def work(self):
print("Employee works")
# Classe Student
class Student:
def study(self):
print("Student studies")
class WorkingStudent(Employee, Student): # Herança de Employee e Student
pass
tom = WorkingStudent()
tom.work() # Employee works
tom.study() # Student studiesNeste exemplo, WorkingStudent representa um estudante que trabalha, herdando as funcionalidades de Employee e Student. Assim, podemos chamar métodos de ambas as classes:
tom = WorkingStudent()
tom.work() # Employee works
tom.study() # Student studiesOs métodos herdados podem ter funcionalidade mais complexa, como mostrado a seguir:
class Employee:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
def work(self):
print(f"{self.name} works")
class Student:
def __init__(self, name):
self.__name = name
@property
def name(self):
return self.__name
def study(self):
print(f"{self.name} studies")
class WorkingStudent(Employee, Student):
pass
tom = WorkingStudent("Tom")
tom.work() # Tom works
tom.study() # Tom studiesEmbora a herança múltipla seja prática, ela pode gerar confusão caso ambas as classes possuam métodos ou atributos com os mesmos nomes. Veja o exemplo:
class Employee:
def do(self):
print("Employee works")
class Student:
def do(self):
print("Student studies")
class WorkingStudent(Employee, Student):
pass
tom = WorkingStudent()
tom.do() # Qual método será usado?No exemplo, ambas as classes Employee e Student possuem um método do, cada um com um propósito distinto. Quando definimos WorkingStudent com Employee primeiro, o método do de Employee é o que será chamado.
Para alterar a preferência, basta trocar a ordem das classes:
class WorkingStudent(Student, Employee)É possível verificar a ordem de aplicação da funcionalidade das classes bases com o atributo __mro__ ou o método mro():
print(WorkingStudent.__mro__)
print(WorkingStudent.mro())Estes métodos retorna uma listam de classes na ordem em que os métodos são procurados pelo Python.