Sobrescrevendo Funcionalidades da Classe Base em Python
Para entender como uma classe derivada pode herdar e modificar funcionalidades de uma classe base, vamos considerar o seguinte exemplo. Suponha que temos uma classe Person que define atributos e métodos comuns e uma classe Employee que herda diretamente de Person. Nesse caso, Employee incorpora automaticamente todos os métodos e atributos de Person, sem precisar redefini-los:
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")Mas e se quisermos modificar algumas dessas funcionalidades? Por exemplo, podemos desejar adicionar um novo atributo ao funcionário no construtor para armazenar a empresa onde ele trabalha ou alterar a implementação do método display_info. O Python permite que sobrescrevamos funcionalidades da classe base.
Vamos modificar as classes da seguinte forma:
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 __init__(self, name, company):
super().__init__(name)
self.company = company
def display_info(self):
super().display_info()
print(f"Company: {self.company}")
def work(self):
print(f"{self.name} works")
tom = Employee("Tom", "Microsoft")
tom.display_info() # Name: Tom
# Company: MicrosoftAqui, a classe Employee adiciona um novo atributo, self.company, que armazena a empresa do funcionário. O método __init__() agora recebe três parâmetros: o segundo para definir o nome e o terceiro para definir a empresa. Porém, se a classe base já definiu um construtor pelo método __init__, e queremos alterar a lógica do construtor na classe derivada, precisamos chamar o construtor da classe base no construtor da classe derivada. No caso da classe Employee, o construtor chama o construtor da classe Person.
Para acessar a classe base, utilizamos a expressão super(). Assim, no construtor de Employee, fazemos a chamada:
super().__init__(name)Essa expressão chama o construtor da classe Person, passando o nome do funcionário, pois o nome é estabelecido no construtor de Person. Já no construtor de Employee, estabelecemos apenas o atributo company.
Além disso, na classe Employee, o método display_info() é sobrescrito para incluir a exibição da empresa do funcionário. Poderíamos definir esse método da seguinte maneira:
def display_info(self):
print(f"Name: {self.name}")
print(f"Company: {self.company}")No entanto, essa abordagem duplicaria a linha de código para exibir o nome, que já existe na classe Person. Para evitar redundância, utilizamos super() para chamar a implementação de display_info da classe Person:
def display_info(self):
super().display_info() # chama display_info da classe Person
print(f"Company: {self.company}")Assim, podemos criar um objeto Employee e chamar o método display_info:
tom = Employee("Tom", "Microsoft")
tom.display_info()O resultado será:
Name: Tom Company: Microsoft
Verificação de Tipo do Objeto
Ao trabalhar com objetos, pode ser necessário realizar operações específicas com base no tipo do objeto. Com a função isinstance(), podemos verificar o tipo de um objeto. Esta função aceita dois parâmetros:
isinstance(objeto, tipo)O primeiro parâmetro representa o objeto, e o segundo é o tipo para o qual a verificação é feita. Se o objeto for do tipo especificado, a função retorna True. Por exemplo, considere a seguinte hierarquia de classes Person-Employee/Student:
class Person:
def __init__(self, name):
self.__name = name # nome da pessoa
@property
def name(self):
return self.__name
def do_nothing(self):
print(f"{self.name} does nothing")
# classe Employee
class Employee(Person):
def work(self):
print(f"{self.name} works")
# classe Student
class Student(Person):
def study(self):
print(f"{self.name} studies")
def act(person):
if isinstance(person, Student):
person.study()
elif isinstance(person, Employee):
person.work()
elif isinstance(person, Person):
person.do_nothing()
tom = Employee("Tom")
bob = Student("Bob")
sam = Person("Sam")
act(tom) # Tom works
act(bob) # Bob studies
act(sam) # Sam does nothingAqui, a classe Employee define o método work(), enquanto a classe Student define o método study().
A função act verifica, usando isinstance, se o parâmetro person representa um tipo específico e, conforme o resultado, chama o método apropriado do objeto.