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: Microsoft
Aqui, 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 nothing
Aqui, 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.