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)
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)
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).
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.
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
A partir do momento que já temos uma classe criada, podemos criar outras classes a partir desta, ou seja, herança é reaproveitar funcionalidades de uma classe base (classe pai), e a classe filha, herdará funcionalidades da classe pai.
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