Classes em Python (POO)
- Amanda Nascimento
- 25 de set. de 2024
- 5 min de leitura
Atualizado: 8 de jun.
Se você já passou pelos princípios de Python funções, laços (For e While) e condicionais (if, elif e else), esta na hora e começar a estudar sobre classes (POO - Programação Orientada a Objetos).
Na POO, tudo é objeto, e de uma classe, gera um objeto. O programador molda esses objetos do mundo real(abstrato) e faz estes objetos interagirem entre si.
Um programa é uma coleção de objetos dizendo uns aos outros o que fazer.
Para fazer uma requisição a um objeto, envia-se uma mensagem a este objeto, enviar uma mensagem, é uma ação, certo? Então esta mensagem é um método.

Classe é como se fosse um "molde" para criar objetos, definindo um conjunto de propriedades (atributos) e comportamentos (métodos) que os objetos criados a partir dela terão.
A classe é como se fosse uma extensão das funções (que podem ter 1 ou + tarefas), porem além das características de uma função, a classe possui atributos (variáveis) e métodos (ações de um objeto). Em Python, por convenção, nomes de classes devem começar com letra maiúscula (estilo chamado PascalCase).
Objeto é uma instância dessa classe (algo concreto). Ele é criado a partir da classe, e a partir desse ponto, ele tem atributos (dados específicos) que são as características que o objeto vai ter (ex: nome, idade) e métodos que são as ações que o objeto pode realizar (ex conforme imagem abaixo: latir, envelhecer).

Todos os cachorros possuem em comum um nome, uma raça, uma idade e um peso, essas são características em comum de todos os objetos(cachorros) da classe dogs. 🐾


Quando criamos um objeto a partir de uma classe, usamos o que é chamado de construtor. Em Python, o construtor é o método especial init(), que serve para inicializar os atributos do objeto. O método init() serve para configurar esses atributos quando o objeto é criado, ou seja, o init é chamado automaticamente quando você cria um novo objeto — e os parâmetros dele podem vir de qualquer lugar: teclado, banco de dados, API etc.

Método para ser executado em todos os objetos:

Métodos em classes
As classes podem conter vários tipos de métodos:

🛑 Método Construtor: (.__init__) é chamado automaticamente quando uma nova instância da classe é criada. Ele é usado para inicializar os atributos do objeto.
(inicializa atributos)

🛑 Método de Instância: Métodos que operam em uma instância da classe. Eles podem acessar e modificar os atributos do objeto. Todos os métodos de instância têm o primeiro parâmetro como self, que refere-se à própria instância.
Operam sobre instâncias (ex: latir).

🛑 Método de Classe: Métodos que têm acesso à própria classe e podem modificar o estado da classe. Eles são definidos com o decorador @classmethod e o primeiro parâmetro é normalmente chamado de cls.
Acessam/modificam o estado da classe (ex: obter_total_cachorros).

🛑 Método Estáticos: Não operam em uma instância ou classe específica. Eles são definidos com o decorador @staticmethod e não têm acesso a self ou cls. São úteis quando você precisa de uma função que não depende do estado do objeto ou da classe.
Não acessam nem instância nem classe (ex: fazer_som).

🛑 Métodos Mágicos: Métodos que têm nomes especiais que começam e terminam com dois sublinhados (__). Eles são usados para definir comportamentos especiais em classes, como adição, comparação e representação de strings. Além de init, exemplos incluem:
str: Define como a instância deve ser representada como uma string.
repr: Fornece uma representação mais detalhada da instância.
len: Define o comportamento da função len() para a instância.
(Comportamentos especiais, como str, len, etc.)
Herança
Herança é quando uma classe "filha" (ou derivada) aproveita características e comportamentos de uma classe "pai" (ou base). Isso permite criar uma estrutura hierárquica entre as classes.
Classe base: contém os atributos e métodos comuns (ex: Cachorro)
Classe derivada: estende a classe base, podendo adicionar ou modificar comportamentos (ex: Filhote)
A partir do momento que já temos uma classe criada, podemos criar outras classes a partir desta, que contém atributos e métodos da qual deriva, ou seja, herança é reaproveitar funcionalidades de uma classe base (classe pai), e a classe filha, herdará funcionalidades da classe pai, ou seja, a classe Filhote herda os métodos e atributos da classe Cachorro, podendo criar novos métodos ou sobrescrever métodos existentes, trazendo organização e evita repetição de código, refletindo melhor o mundo real!

Tipo de herança em POO

class Animal:
pass # Classe base
class Mamifero(Animal):
pass # Classe derivada de Animal
class Cachorro(Mamifero):
pass # Classe derivada de Mamifero, e indiretamente de Animal
Podemos utilizar em python a função issubclass() para comprovar que mesmo no terceiro nível, uma classe ainda é considerada derivada da base original.
# Verificações com issubclass()
print(issubclass(Mamifero, Animal)) # True → Mamifero herda de Animal
print(issubclass(Cachorro, Mamifero)) # True → Cachorro herda de Mamifero
print(issubclass(Cachorro, Animal)) # True → Cachorro herda indiretamente de Animal
1. Herança Simples
Na herança simples, uma classe filha (ou derivada) herda atributos e métodos de apenas uma classe base. É ideal quando há uma relação clara de "é um tipo de".

2. Herança Múltipla (usando Cachorro + outro comportamento)
Agora vamos imaginar que existe outra classe chamada Pet, que define comportamentos de um animal doméstico, como ser adotado ou brincar com crianças. 🐾
A classe Filhote pode herdar tanto de Cachorro quanto de Pet.

Tipo de Herança | Classe Derivada | Herda de... | Exemplo |
Herança Simples | Filhote | Apenas Cachorro | class Filhote(Cachorro) |
Herança Múltipla | Filhote | Cachorro + Pet | class Filhote(Cachorro, Pet) |
Polimorfismo (muitas formas)
O polimorfismo se refere a capacidade de objetos de diferentes classes serem tratados como objetos de uma classe base comum. No contexto da POO (Programação Orientada a Objetos) o polimorfismo permite que um mesmo método ou operação tenha diferentes comportamentos dependendo do objeto que o chama.
Isso é feito por meio da definição de métodos na classe base e sua especialização nas classes derivadas. Com o polimorfismo, é possível escrever script que opere com objetos de maneira genérica, e esses objetos responderão de acordo com suas próprias implementações.

Podemos passar diferentes tipos de Animal para a função:

A função fazer_animal_emitir_som não se preocupa com o tipo específico do Animal que recebe. Ela apenas sabe que qualquer objeto do tipo Animal terá um método emitir_som.
Cada classe derivada (Cachorro e Gato) implementa sua própria versão do método emitir_som, permitindo comportamentos diferentes para a mesma função. Essa é a essência do polimorfismo.
Assim, o polimorfismo permite que a mesma função (fazer_animal_emitir_som) execute diferentes comportamentos, dependendo do tipo do objeto que recebe (classe derivada). Isso é possível porque as classes derivadas (subclasses) Cachorro e Gato herdam da classe base Animal e redefinem o método emitir_som, permitindo uma "interface" comum para todos os Animais, mas com resultados específicos.
class Animal: #classe base
def __init__(self, nome):
self.nome = nome
def emitir_som(self):
return "Algum som genérico"
def __str__(self):
return f"Animal: {self.nome}"
class Cachorro(Animal): #classe derivada
def emitir_som(self):
return "Au Au"
def __str__(self):
return f"Cachorro: {self.nome}"
class Gato(Animal): #classe derivada
def emitir_som(self):
return "Miau"
def __str__(self):
return f"Gato: {self.nome}"
#polimorfismo
def fazer_animal_emitir_som(animal):
print(animal.emitir_som())
cachorro = Cachorro("Rex")
gato = Gato("Felix")
animal_generico = Animal("Animal Genérico")
fazer_animal_emitir_som(cachorro) # Saída: Au Au
fazer_animal_emitir_som(gato) # Saída: Miau
fazer_animal_emitir_som(animal_generico) # Saída: Algum som genérico
Polimorfismo estático(sobrecarga): Ocorre em momento de compilação. O mesmo método é implementado várias vezes na mesma classe, com parâmetros diferentes. A escola do método a ser chamado vai variar de acordo com o parâmetro passado.

Polimorfismo dinâmico (sobreposição): Ocorre em momento de execução. O mesmo método é implementado várias vezes nas subclasses derivadas, com os mesmos parâmetros. A escolha do método depende do objeto que o chama (e consequentemente, da classe que o implementa)

Tipo | Definição | Exemplo |
Polimorfismo Estático | Mesmo método, mas com parâmetros diferentes na mesma classe | emitir_som() ou emitir_som("rugido") |
Polimorfismo Dinâmico | Mesmo método em classes diferentes, com comportamento diferente (herança) | Cachorro.emitir_som() vs. Gato.emitir_som( |