Na programação orientada a objetos, uma classe funciona como um molde que define a estrutura e o comportamanto que seus objetos terão. O objeto, por sua vez, é a materialização concreta dessa classe. Cada objeto possui características próprias (atributos) e ações que pode executar (métodos). Ao agruparmos objetos que compartilham propriedades e comportamentos similares, abstraímos esses elementos comuns para formar uma classe.
Criando Classes em Python
A palavra-chave class é utilizada para declarar uma classe. Dentro dela, definimos funções que representam os métodos do objeto. Veja um exemplo:
class Aluno:
def __init__(self, nome, idade):
self.nome = nome
self.idade = idade
def estudar(self, disciplina):
print(f'{self.nome} está estudando {disciplina}.')
def assistir_filme(self):
if self.idade < 18:
print(f'{self.nome} só pode assistir filmes infantis.')
else:
print(f'{self.nome} está assistindo um filme para adultos.')
Instanciando e Utilizando Objetos
Após definir a classe, podemos criar instâncias e interagir com elas:
def executar():
aluno1 = Aluno('Carlos', 20)
aluno1.estudar('Estrutura de Dados')
aluno1.assistir_filme()
aluno2 = Aluno('Ana', 15)
aluno2.estudar('Matemática')
aluno2.assistir_filme()
if __name__ == '__main__':
executar()
Controle de Visibilidade de Atributos e Métodos
Em linguagens como Java e C#, existe controle rígido sobre a visibildiade de atributos e métodos (private, protected, public). Em Python, existem essencialmente dois níveis: público e privado. Para marcar um atributo ou método como privado, basta prefixá-lo com dois sublinhados (__).
class Exemplo:
def __init__(self, valor):
self.__valor = valor
def __exibir(self):
print(self.__valor)
def executar():
obj = Exemplo('dados secretos')
# obj.__exibir() # gera AttributeError
# print(obj.__valor) # gera AttributeError
No entanto, Python não impede rigorosamente o acesso a membros privados. Na verdade, o interpretador renomeia esses membros aplicando uma técnica chamada name mangling, adicionando o nome da classe como prefixo. Assim, ainda é possível acessá-los:
def executar():
obj = Exemplo('dados secretos')
obj._Exemplo__exibir()
print(obj._Exemplo__valor)
Essa flexibilidade reflete a filosofia do Python, onde se assume que desenvolvedores são responsáveis por suas próprias decisões. Na prática, a convenção amplamente adotada é utilizar um único sublinhado (_) como prefixo para indicar que um atributo ou método deve ser tratado como protegido, sinalizando que o acesso externo deve ser evitado, embora não seja proibido pela linguagem.
Pilares da Orientação a Objetos
Os três pilares fundamentais são: encapsulamento, herança e polimorfismo. O encapsulamento consiste em ocultar os detalhes internos de implementação, expondo apenas uma interface simples para interação. Quando definimos métodos em uma classe, estamos encapsulando dados e suas operações. O usuário do objeto precisa apenas conhecer a assinatura dos métodos (parâmetros e retorno), sem se preocupar com a lógica interna.
Exercícios Práticos
Exercício 1: Relógio Digital
from time import sleep
class Cronometro:
"""Representa um relógio digital simples."""
def __init__(self, hora=0, minuto=0, segundo=0):
self._hora = hora
self._minuto = minuto
self._segundo = segundo
def avancar(self):
"""Incrementa o tempo em um segundo."""
self._segundo += 1
if self._segundo >= 60:
self._segundo = 0
self._minuto += 1
if self._minuto >= 60:
self._minuto = 0
self._hora += 1
if self._hora >= 24:
self._hora = 0
def hora_formatada(self):
"""Retorna o horário no formato HH:MM:SS."""
return f'{self._hora:02d}:{self._minuto:02d}:{self._segundo:02d}'
def executar():
relogio = Cronometro(23, 59, 58)
while True:
print(relogio.hora_formatada())
sleep(1)
relogio.avancar()
if __name__ == '__main__':
executar()
Exercício 2: Ponto no Plano Cartesiano
from math import sqrt
class Coordenada:
"""Representa um ponto em um plano 2D."""
def __init__(self, eixo_x=0, eixo_y=0):
self.x = eixo_x
self.y = eixo_y
def deslocar_para(self, novo_x, novo_y):
"""Define uma nova posição absoluta."""
self.x = novo_x
self.y = novo_y
def deslocar_por(self, delta_x, delta_y):
"""Move o ponto por um deslocamento relativo."""
self.x += delta_x
self.y += delta_y
def distancia_ate(self, outro_ponto):
"""Calcula a distância euclidiana até outro ponto."""
diff_x = self.x - outro_ponto.x
diff_y = self.y - outro_ponto.y
return sqrt(diff_x ** 2 + diff_y ** 2)
def __str__(self):
return f'({self.x}, {self.y})'
def executar():
ponto_a = Coordenada(3, 5)
ponto_b = Coordenada()
print(ponto_a)
print(ponto_b)
ponto_b.deslocar_por(-1, 2)
print(ponto_b)
print(ponto_a.distancia_ate(ponto_b))
if __name__ == '__main__':
executar()