Pular para o conteúdo

    Capítulo 26, Intermediário

    Classes e objetos

    Uma classe agrupa dados e comportamento que pertencem juntos. Eu mostro o essencial e, principalmente, quando **não** criar uma.

    Código deste capítulo: intermediario/cap26_classes.py

    A classe é o molde, o objeto é a coisa

    Uma classe descreve como são e o que fazem os objetos de um tipo. Cada objeto criado a partir dela é uma instância, com os seus próprios dados:

    intermediario/cap26_classes.pylinhas 10 a 22
    class Cachorro:
        def __init__(self, nome, idade):
            self.nome = nome
            self.idade = idade
    
        def latir(self):
            return f"{self.nome} diz: au au"
    
    
    rex = Cachorro("Rex", 3)
    mel = Cachorro("Mel", 5)
    print(rex.nome, mel.nome)
    print(rex.latir())
    
    Saída
    Rex Mel
    Rex diz: au au
    

    O __init__ é o inicializador: ele roda logo depois que o objeto é criado e prepara os dados iniciais. (Quem de fato cria o objeto é o __new__, que você raramente escreve.) A palavra self é o próprio objeto, e é por ela que cada método sabe de quem são os dados.

    O que o self realmente é

    Uma chamada como rex.latir() é só açúcar para Cachorro.latir(rex). O Python passa o objeto como primeiro argumento. Ver isso uma vez desfaz o mistério do self:

    intermediario/cap26_classes.pylinhas 27 a 28
    print(Cachorro.latir(mel))
    print(type(rex).__name__, isinstance(rex, Cachorro))
    
    Saída
    Mel diz: au au
    Cachorro True
    

    Uma representação que ajuda a depurar

    Imprimir um objeto sem __repr__ mostra algo como <Ponto object at 0x...>, que não ajuda ninguém. Defina o __repr__ em quase toda classe: ele deve mostrar os dados e, de preferência, parecer o código que recria o objeto:

    intermediario/cap26_classes.pylinhas 33 a 44
    class Ponto:
        def __init__(self, x, y):
            self.x = x
            self.y = y
    
        def __repr__(self):
            return f"Ponto(x={self.x}, y={self.y})"
    
    
    p = Ponto(1, 2)
    print(p)
    print(vars(p))
    
    Saída
    Ponto(x=1, y=2)
    {'x': 1, 'y': 2}
    

    O vars() mostra os atributos do objeto como um dicionário. É assim que o Python guarda os dados de cada instância.

    Quando criar uma classe

    Eu crio uma classe quando tenho estado e comportamento que andam juntos, como uma conta bancária, que tem saldo e sabe depositar e sacar. Se a classe só tem métodos e nenhum dado, ela provavelmente deveria ser uma função (ou um módulo). Uma Calculadora com somar(a, b) e subtrair(a, b) sem nenhum atributo é a forma de escrever Java dentro do Python.

    Exercício 1

    Uma conta bancária

    Crie ContaBancaria com titular e saldo inicial (padrão 0), e os métodos depositar e sacar. Valores inválidos e saques acima do saldo levantam ValueError.