• Unidade 1
  • Capítulo 1 - Introdução ao Curso
  • Atividades
  • 2 - Revisão Python
  • 2.1 - Introdução à Classes no Python

Classes em Python

Uma classe em Python é um mecanismo usado para criar novos tipos de objetos definidos pelo usuário, que combinam propriedades e comportamentos específicos. Classes são a estrutura básica do paradigma de programação orientada a objetos (POO), que permitem agrupar funções e variáveis relacionadas em um único objeto, facilitando a organização e a modularidade do código.

Por exemplo, se quisermos representar um carro em nosso programa, podemos criar uma classe chamada "Carro". Esta classe pode ter atributos como "cor", "marca", "modelo", "ano" e pode ter métodos como "acelerar", "frear", "estacionar".

1. Como Usar Classes em Python

Vamos começar criando uma classe simples chamada Carro.

class Carro:
    def __init__(self, cor, marca, modelo, ano):
        self.cor = cor
        self.marca = marca
        self.modelo = modelo
        self.ano = ano

    def acelerar(self):
        print("O carro está acelerando.")

    def frear(self):
        print("O carro está freando.")

No exemplo acima, __init__ é um método especial, chamado de construtor, que é chamado automaticamente sempre que criamos um novo objeto a partir dessa classe. Ele inicializa os atributos da classe.

Importante: Note que __init__ é definido com dois sublinhados antes e depois do nome. Isso é uma convenção em Python para identificar métodos e atributos especiais.

Os métodos acelerar e frear são comportamentos que o carro pode realizar.

Podemos criar uma instância da classe Carro da seguinte forma:

Meu_carro = Carro("Vermelho", "Ferrari", "458 Italia", 2020)

Em seguida, podemos usar os métodos e acessar os atributos da seguinte maneira:

print(Meu_carro.cor)  # Saída: Vermelho
Meu_carro.acelerar()  # Saída: O carro está acelerando.
Vermelho
O carro está acelerando.

2. Uso da instância interna da Classe

O atributo self é uma referência à instância atual da classe e é usado para acessar variáveis e métodos da classe. O self é sempre o primeiro parâmetro de qualquer método da classe.

Vamos usar a nossa classe Carro como exemplo:

class Carro:
    def __init__(self, cor: str, marca: str, modelo: str, ano: int):
        self.cor = cor
        self.marca = marca
        self.modelo = modelo
        self.ano = ano

    def acelerar(self):
        print(f'O {self.modelo} está acelerando.')

    def frear(self):
        print(f'O {self.modelo} está freando.')

Meu_carro = Carro("Vermelho", "Ferrari", "458 Italia", 2020)
Meu_carro.acelerar()
Meu_carro.frear()
O 458 Italia está acelerando.
O 458 Italia está freando.

2.1 Composição

Ou, podemos criar uma classe Pessoa que tem uma instância interna da classe Carro:

class Pessoa():
    def __init__(self, motorista: bool):
        self.motorista = True
        self.carro = Carro("Vermelho", "Ferrari", "458 Italia", 2020)

    def dirigir(self):
        if self.motorista:
            self.carro.acelerar()
            print(f'O {self.carro.modelo} está em movimento.')
            self.carro.frear()
            print(f'O {self.carro.modelo} parou.')
        else:
            print('Você não é um motorista.')

motorista = Pessoa(True)
motorista.dirigir()
O 458 Italia está acelerando.
O 458 Italia está em movimento.
O 458 Italia está freando.
O 458 Italia parou.

3. Decorador @staticmethod

Em Python, o decorador @staticmethod é usado para indicar que um método é um método estático, ou seja, um método que pertence à classe, mas não é uma instância da classe.

Isso significa que um método estático pode ser chamado sem criar um objeto da classe.

Note que o método estático não pode acessar atributos da classe, pela ausência do parâmetro self.

class Carro:
    def __init__(self, cor: str, marca: str, modelo: str, ano: int):
        self.cor = cor
        self.marca = marca
        self.modelo = modelo
        self.ano = ano

    def acelerar(self):
        print(f'O {self.modelo} está acelerando.')

    def frear(self):
        print(f'O {self.modelo} está freando.')

    @staticmethod
    def numero_de_rodas():
        print("O carro possui 4 rodas.")

Carro.numero_de_rodas()
O carro possui 4 rodas.

4. Herança de Classes

Em Python, uma classe pode herdar de outra classe. Na nomeclatura de orientação a objetos, a classe que herda é chamada de filha e a classe que é herdada é chamada de pai. O uso de herança permite que a classe filha tenha todos os atributos e métodos da classe pai, além de poder adicionar, ou modificar os atributos e métodos.

# Classe filha Caminhao que herda de Carro
class Caminhao(Carro):
    def __init__(self, cor: str, marca: str, modelo: str, ano: int, capacidade_carga: int):
        super().__init__(cor, marca, modelo, ano)  # Chama o construtor da classe pai
        self.capacidade_carga = capacidade_carga  # Atributo adicional

    def carregar(self, carga: int):
        if carga <= self.capacidade_carga:
            print(f"Carregando {carga} toneladas no caminhão.")
        else:
            print("Carga excede a capacidade máxima do caminhão!")

    # Sobrescrevendo o numero de rodas
    @staticmethod
    def numero_de_rodas():
        print("O caminhão possui 6 rodas.")

    # Sobrescrevendo o método frear

# Exemplo de uso
carro = Carro("Vermelho", "Toyota", "Corolla", 2020)
caminhao = Caminhao("Azul", "Volvo", "FH16", 2021, 20)

carro.acelerar()
carro.numero_de_rodas()
caminhao.carregar(15)
caminhao.numero_de_rodas()
O Corolla está acelerando.
O carro possui 4 rodas.
Carregando 15 toneladas no caminhão.
O caminhão possui 6 rodas.

4.1. Herança vs Composição

Herança e composição são formas de reutilizar código. Na herança, uma classe filha herda atributos e métodos de uma classe pai, criando uma relação do tipo "é um". Na composição, uma classe contém instâncias de outras classes, formando uma relação do tipo "tem um". A principal diferença é que herança estabelece uma hierarquia, enquanto composição combina funcionalidades de diferentes classes.

5. Herança Multipla

A herança múltipla em Python é um recurso que permite que uma classe herde de mais de uma classe pai. Isso significa que a classe filha pode acessar atributos e métodos de todas as classes das quais herda.

Primeiramente vamos criar mais uma classe pai chamada Barco:

class Barco:
    def __init__(self, tipo: str, marca: str):
        self.tipo = tipo
        self.marca = marca

    def navegar(self):
        print(f'O {self.tipo} está navegando na água.')

Agora, vamos criar a classe VeiculoAnfibio que herda de ambas as classes Carro e Barco:

  • Note que foi nescessario chamar o construtor de ambas as classes pai diretamente. Neste caso, usar super() só chamaria o construtor da primeira classe pai, que é a classe Carro.

Tarefa: Leia atentamente o código abaixo e ao erro gerado. Corrija o erro e execute novamente.

class VeiculoAnfibio(Carro, Barco):
    def __init__(self, cor: str, marca_carro: str, modelo: str, tipo_barco: str, marca_barco: str):
        Carro.__init__(self, cor, marca_carro, modelo)
        Barco.__init__(self, tipo_barco, marca_barco)

    def modo_estrada(self):
        print(f"Modo estrada ativado: {self.modelo} de {self.marca} está dirigindo.")

    def modo_mar(self):
        print(f"Modo marítimo ativado: {self.tipo} de {self.marca} está navegando.")

veiculo_anfibio = VeiculoAnfibio("Verde", "Amphicar", "770", "Barco a Motor", "Amphicar")
veiculo_anfibio.modo_estrada()
veiculo_anfibio.modo_mar()
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Input In [8], in <cell line: 12>()
      9     def modo_mar(self) -> None:
     10         print(f"Modo marítimo ativado: {self.tipo} de {self.marca} está navegando.")
---> 12 veiculo_anfibio = VeiculoAnfibio("Verde", "Amphicar", "770", "Barco a Motor", "Amphicar")
     13 veiculo_anfibio.modo_estrada()
     14 veiculo_anfibio.modo_mar()

Input In [8], in VeiculoAnfibio.__init__(self, cor, marca_carro, modelo, tipo_barco, marca_barco)
      2 def __init__(self, cor: str, marca_carro: str, modelo: str, tipo_barco: str, marca_barco: str) -> None:
----> 3     Carro.__init__(self, cor, marca_carro, modelo)
      4     Barco.__init__(self, tipo_barco, marca_barco)

TypeError: __init__() missing 1 required positional argument: 'ano'

6. Pratica

  1. Adicionem um atributo chamado velocidade na classe Carro e modifiquem o método acelerar para que ele incremente o valor da velocidade em 10. Modifiquem o método frear para que ele zere a velocidade do carro.