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émtabela
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!