Classes e Métodos Abstratos em Python
Em programação, as classes geralmente representam objetos do mundo real. No entanto, há casos em que precisamos trabalhar com entidades sem uma forma específica. Por exemplo, a entidade "animal": existem animais específicos, como gato e cachorro, mas "animal" em si é um conceito abstrato. O mesmo ocorre com "figura geométrica": temos retângulos, quadrados, círculos, triângulos, mas "figura geométrica" não representa uma forma concreta. Para descrever tais entidades, utilizamos classes abstratas.
Em Python, os recursos para criar classes abstratas estão no módulo especial abc
, que deve ser importado separadamente no código:
import abc
As principais ferramentas desse módulo são a classe ABC
e o decorador @abstractmethod
. A classe ABC
simplifica a criação de uma classe abstrata, e todas as classes abstratas devem herdar dela. O decorador @abstractmethod
é usada para definir métodos abstratos.
Classes abstratas são definidas de maneira semelhante às classes comuns, exceto que elas herdam da classe ABC
do módulo abc
. Por exemplo, vamos definir uma classe abstrata para figuras geométricas:
import abc
class Shape(abc.ABC):
pass
Geralmente, classes abstratas declaram funcionalidades que serão comuns às classes derivadas. Essas funcionalidades podem não ter implementação, devendo ser definidas nas classes herdeiras. Esse tipo de funcionalidade é representado por métodos abstratos. Por exemplo, a classe "figura geométrica" pode ter métodos para calcular perímetro e área, mas a fórmula para calcular a área varia para cada figura. Podemos definir o método de cálculo de área como abstrato, utilizando a anotação @abstractmethod
do módulo abc
:
import abc
class Shape(abc.ABC):
@abc.abstractmethod
def area(self): pass # área da figura
Aqui, o método area()
é abstrato. Como ele não requer uma implementação específica, utilizamos o operador pass
.
É importante notar que não podemos instanciar uma classe abstrata com métodos abstratos diretamente, usando o seu construtor:
import abc
class Shape(abc.ABC):
@abc.abstractmethod
def area(self): pass
shape = Shape() # Erro - isso não é permitido
print(shape)
As classes derivadas devem implementar todos os métodos abstratos da classe abstrata. Por exemplo, vamos criar uma classe para representar um retângulo:
import abc
class Shape(abc.ABC):
@abc.abstractmethod
def area(self): pass
# classe retângulo
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
rect = Rectangle(30, 50)
print("Rectangle area:", rect.area()) # Rectangle area: 1500
Aqui, a classe Rectangle
recebe a largura e altura no construtor e usa esses valores para calcular a área no método area()
.
Da mesma forma, podemos definir outras figuras. Por exemplo, vamos adicionar uma classe para representar um círculo:
import abc
class Shape(abc.ABC):
@abc.abstractmethod
def area(self): pass
# classe retângulo
class Rectangle(Shape):
def __init__(self, width, height):
self.width = width
self.height = height
def area(self):
return self.width * self.height
# classe círculo
class Circle(Shape):
def __init__(self, radius):
self.radius = radius
def area(self):
return self.radius * self.radius * 3.14
def print_area(shape):
print("Area:", shape.area())
rect = Rectangle(30, 50)
circle = Circle(30)
print_area(rect) # Area: 1500
print_area(circle) # Area: 2826.0
Neste exemplo, definimos uma função print_area
que recebe qualquer figura e exibe sua área.
Atributos e Métodos Não Abstratos
Classes abstratas também podem definir construtores, atributos e métodos não abstratos, que podem ser utilizados pelas classes derivadas:
import abc
class Shape(abc.ABC):
def __init__(self, x, y):
self.x = x
self.y = y
@abc.abstractmethod
def area(self): pass # método abstrato
def print_point(self): # método não abstrato
print("X:", self.x, "\tY:", self.y)
# classe retângulo
class Rectangle(Shape):
def __init__(self, x, y, width, height):
super().__init__(x, y)
self.width = width
self.height = height
def area(self):
return self.width * self.height
rect = Rectangle(10, 20, 100, 100)
rect.print_point() # X: 10 Y: 20
Aqui, a classe abstrata Shape
recebe as coordenadas X e Y para o ponto de referência da figura (como o canto superior esquerdo de um retângulo ou o centro de um círculo) e define o método não abstrato print_point
, que exibe essas coordenadas no console.