Ir para o conteúdo

Exemplos heranças

Uma classe para linhas retas

Problema:

Fazer uma classe para avaliar linhas $ y = c_0 + c_1 x $

Código:

class Linha:
    def __init__(self, c0, c1):
        self.c0, self.c1 = c0, c1

    def __call__(self, x):
        return self.c0 + self.c1*x

    def tabela(self, L, R, n):
        """Retorna uma tabela com n pontos para L <= x <= R."""
        s = ''
        for x in linspace(L, R, n):
            y = self(x)
            s += '%12g %12g\n' % (x, y)
        return s

Classe para parábolas

Problema:

Fazer uma classe para avaliar parábolas $ y = c_0 + c_1 x + c_2 x^2 $

Código:

class Parabola:
    def __init__(self, c0, c1, c2):
        self.c0, self.c1, self.c2 = c0, c1, c2

    def __call__(self, x):
        return self.c2*x**2 + self.c1*x + self.c0

    def tabela(self, L, R, n):
        """Retorna uma tabela com n pontos para L <= x <= R."""
        s = ''
        for x in linspace(L, R, n):
            y = self(x)
            s += '%12g %12g\n' % (x, y)
        return s

Observação:

É praticamente o mesmo código da classe Linha, exceto pelas parcelas com $ c_2 $.

Classe Parabola como uma subclasse de Linhas - Princípios

  • Código da Parabola: Código da Linha + um extra com o termo $ c_2 $.
  • Podemos utilizar o código da classe Linha na classe Parabola?
  • Isto é herança!

Escrevendo:

class Parabola(Linha):
    pass

Faz Parabola herdar todos os métodos e atributos de Linha, então Parabola possui os atributos $ c_0 $ e $ c_1 $ e três métodos.

  • Linha é uma superclasse, Parabola é uma subclasse (classe pai, classe base e classe filha ou classe derivada);
  • A classe Parabola deve adicionar código no construtor de Linha (um atributo $ c_2 $ extra), __call__(um termo extra), porém tabela pode ser utilizado sem alterações.
  • O princípio é reutilziar o máximo de código possível em Linha e evitar duplicatas.

Classe Parabola como uma subclasse de Linhas - Código

Um método de uma subclasse pode chamar um método de uma superclasse da seguinte forma:

superclasse_nome.metodo(self, arg1, arg2, ...)

Classe Parabola como uma subclasse de Linha:

class Parabola(Linha):
    def __init__(self, c0, c1, c2):
        Linha.__init__(self, c0, c1)  ## Linha armazena c0, c1
        self.c2 = c2

    def __call__(self, x):
        return Linha.__call__(self, x) + self.c2*x**2

O que foi ganho?

  • A classe Parabola apenas adiciona código à um código já existente na classe Linha, nenhuma duplicata de $ c_0 $ e $ c_1 $ e do cálculo de $ c_0 + c_1 x $;
  • A classe Parabola também possui o método tabela, ele é herdado;
  • __init__ e __call__ são sobrescritos e redefinidos na subclasse.

Classe Parabola como uma subclasse de Linhas - chamada

p = Parabola(1, -2, 2)
p1 = p(2.5)
print p1
print p.table(0, 1, 3)

Saída:

8.5
           0            1
         0.5          0.5
           1            1

Podemos verificar o tipo da classe e as relações da classe

Pode ser feito utilizando isinstance(obj, tipo) e issubclass(subclassenome, superclassenome)

>>> from Linha_Parabola import Linha, Parabola
>>> l = Linha(-1, 1)
>>> isinstance(l, Linha)
True
>>> isinstance(l, Parabola)
False

>>> p = Parabola(-1, 0, 10)
>>> isinstance(p, Parabola)
True
>>> isinstance(p, Linha)
True

>>> issubclass(Parabola, Linha)
True
>>> issubclass(Linha, Parabola)
False

>>> p.__class__ == Parabola
True
>>> p.__class__.__name__   ## versão de texto do nome da classe
'Parabola'

Invertendo: Linha como uma subclasse de Parabola

  • Subclasses são normalmente casos especiais de superclasses;
  • A linha $ c_0 + c_1 x $ é um caso especial de uma parábola $ c_0 + c_1 x + c_2 x^2 $;
  • A Linha pode ser uma subclasse de Parabola?
  • Sem problemas, isto é escolha do programador;
  • Muitos podem preferir esta relação de redução de código.

Linha como uma subclasse de Parabola - código

class Parabola:
    def __init__(self, c0, c1, c2):
        self.c0, self.c1, self.c2 = c0, c1, c2

    def __call__(self, x):
        return self.c2*x**2 + self.c1*x + self.c0

    def tabela(self, L, R, n):
        """Retorna uma tabela com n pontos para L <= x <= R."""
        s = ''
        for x in linspace(L, R, n):
            y = self(x)
            s += '%12g %12g\n' % (x, y)
        return s

class Linha(Parabola):
    def __init__(self, c0, c1):
        Parabola.__init__(self, c0, c1, 0)

Nota: __call__ e tabela podem ser reutilizados na classe Linha!