O que é Herança e Como Ela Promove a Reutilização de Código?

Herança é o próximo conceito chave da programação orientada a objetos (OOP) que abordaremos. Vamos analisar mais profundamente esse conceito e como ele permite que você escreva código reutilizável. Com herança, uma subclasse (ou classe filha) pode usar os atributos e métodos de uma classe base (ou classe pai). Isso permite reutilizar código, criar hierarquias claras de classes e personalizar o comportamento sem reescrever tudo. Você pode personalizar estendendo métodos existentes ou sobrescrevendo-os na classe filha. Aqui está a sintaxe básica para herança:
class Parent:
    # Parent attributes and methods

class Child(Parent):
    # Child inherits, extends, and/or overrides where necessary
Para a classe Child herdar da classe Parent, você precisa passar o Parent para o Child. Esse estilo é chamado de herança simples, já que uma classe filha herda de exatamente uma classe pai. Aqui está um exemplo:
class Animal:
    def __init__(self, name):
        self.name = name

    def sound(self):
        return f'{self.name} makes a sound'

class Dog(Animal):
    bark = 'woof! woof!! woof!!!'

jack = Dog('Jack')
print(jack.sound())  # Jack makes a sound
print(jack.bark)  # woof! woof!! woof!!!
Você pode ver que somos capazes de reutilizar o atributo self.name e o método sound() da classe pai Animal na classe filha Dog. Vamos sobrescrever o método sound() da classe pai Animal na classe filha Dog para que possamos fazer o sound() usar a variável de classe bark:
class Animal:
    def __init__(self, name):
        self.name = name

    def sound(self):
        return f'{self.name} makes a sound.'

class Dog(Animal):
    bark = 'woof! woof!! woof!!!'

    # Override sound() to use bark class variable
    def sound(self):
        return f'{self.name} barks {self.bark}'

jack = Dog('Jack')
print(jack.sound())  # Jack barks woof! woof!! woof!!!
Se você quiser manter o valor de retorno de sound() e adicionar a variável de classe bark depois, você pode estender sound() usando a função super():
class Animal:
    def __init__(self, name):
        self.name = name

    def sound(self):
        return f'{self.name} makes a sound'

class Dog(Animal):
    bark = 'woof! woof!! woof!!!'

    # Call Animal.sound(), then append bark
    def sound(self):
        base = super().sound()
        return f'{base}, then {self.name} barks {self.bark}'

jack = Dog('Jack')
print(jack.sound())  # Jack makes a sound, then Jack barks woof! woof!! woof!!!
Neste exemplo, base é o resultado de chamar o método sound() da classe Animal e então adicionamos o som específico da classe Dog a ele. Desta forma, você pode estender a funcionalidade da classe pai Animal mantendo seu comportamento original. Também existe herança múltipla, onde uma classe filha pode herdar de mais de uma classe pai. Aqui está a sintaxe básica de herança múltipla:
class Parent:
    # Attributes and methods for Parent

class Child:
    # Attributes and methods for Child

class GrandChild(Parent, Child):
    # GrandChild inherits from both Parent and Child
    # GrandChild can combine or override behavior from each
Uma maneira simples de demonstrar herança múltipla é com um sapo, que pode tanto andar em terra e nadar na água:
class Walker:
    def walk(self):
        return 'I can walk on land'

class Swimmer:
    def swim(self):
        return 'I can swim in water'

# Amphibian inherits from both Walker and Swimmer
class Amphibian(Walker, Swimmer):
    def __init__(self, name):
        self.name = name

    def introduce(self):
        return f"I'm {self.name} the frog. {self.walk()} and {self.swim()}."

frog = Amphibian('Freddy')
print(frog.introduce())
# Output: I'm Freddy the frog. I can walk on land and I can swim in water.
Este módulo não possui perguntas. Marque como concluído.