Executando verificação de segurança...
1

O importante foi compreender a base que é fundamental para todo o aprendizado seja qual for o conteúdo.

Como você se preocupa em aprender a base (o que te parabenizo, é raro isso) é importante lembrar que você ou está misturando conceitos ou aprendeu errado (fica tranquilo que isso é normal, faz parte e é importante aprender errado de vez enquando)

É como se fosse uma "cópia" do modelo que pode ser manipulado individualmente.

Não é bem assim que acontece, Python meio que não deixa transparecer mas não é uma cópia (tem um paradigma de POO que é cópia, mas não é o caso, veja esse exemplo:

class Caneca:
    def __init__(self, cor, material, capacidade):
        self.cor = cor
        self.material = material
        self.capacidade = capacidade
        self.volume_atual = 0

    def descrever(self):
        return f"Uma caneca {self.cor} feita de {self.material} com capacidade de {self.capacidade} ml."
        
def descreve_xicara(self):
        return f"Uma xícara {self.cor} feita de {self.material} com capacidade de {self.capacidade} ml."

minha_caneca = Caneca('azul', 'cerâmica', 350)

print(minha_caneca.descrever())

Caneca.descrever = descreve_xicara

print(minha_caneca.descrever())

O que realmente acontece é melhor ilustrado em Lua:

Caneca = {
  new = function (self, cor, material, capacidade)
    local instance = {}
    instance.cor = cor
    instance.material = material
    instance.capacidade = capacidade
    
    -- Diz pra procurar (__index) chaves nulas de 
    -- instance em self (que é Caneca)
    return setmetatable(instance,{__index = self})
  end,
  descrever = function (self)
    return ("Uma xícara %s feita de %s com capacidade de %d ml."):format(self.cor, self.material, self.capacidade)
  end
}

minha_caneca = Caneca:new('azul', 'cerâmica', 350)
minha_caneca:descrever()

O que acontece em descrever:

  • Busca no objeto minha_caneca pelo campo "descrever"
  • Tem? Chama minha_caneca.descrever(minha_caneca)
  • Não tem? Chama Caneca.descrever(minha_caneca)

O que eu quero ilustrar é que uma classe é um objeto de "fallback" ou seja se o que eu procuro não estiver no objeto, eu procuro na classe, quando você instancia uma classe em um objeto, o que você está dizendo pro compilador (sim, python é compilada) é: "Compilador, seguinte, se eu procurar uma propriedade ou método em minha_caneca e não achar, por favor, procure em Caneca porque provavelmente vai estar lá", é por isso que POO com classes geralmente ocupa menos espaço em RAM em troca de ficar lento quando acontece o inheritance hell (heranças em excesso), isso se chama lookup chain

uma classe é um modelo para criar objetos

Eu inverti a ordem pra facilitar entender o conceito, como a gente viu no exemplo anterior, uma classe é um objeto no qual outros objetos podem usar para buscar propriedades e métodos faltantes, um modelo para crar objetos GERALMENTE é uma função, essa técnica é chamada de prototyping (as vezes como fábricas) em Python seria algo assim:

# Importante porque vamos precisar de acesso a namespace do objeto
import types

def Caneca(cor, material, capacidade):
    def descrever(self):
        return f"Uma caneca {self.cor} feita de {self.material} com capacidade de {self.capacidade} ml."
    # Cria um objeto vazio com acesso direto a namespace
    instance = types.SimpleNamespace()
    # Definimos as propriedades
    instance.cor = cor
    instance.material = material
    instance.capacidade = capacidade
    # E os métodos
    instance.descrever = types.MethodType(descrever,instance)
    # E agora é só retornar
    return instance

minha_caneca = Caneca('azul', 'cerâmica', 350)

minha_caneca.descrever() # Uma caneca azul feita de cerâmica com capacidade de 350 ml.
Carregando publicação patrocinada...