Depois de mais de um mês, vamos voltar à nossa programação normal dos tópicos de Python, já entrando no clima do curso que vai ser feito nos chats de tecnologia. Por aqui, o assunto já está um pouco mais à frente, o assunto é programação orientada a objetos e hoje vamos falar de herança, usando exemplo de classes de cachorros, hoje de raças de cachorros.
Imaginem que eu precise de um programa que vá ter várias classes de cachorros que representam suas raças.
class Poodle:
def __init__(self, patas, rabo, olhos, cor_do_pelo, porte):
self.patas = patas
self.rabo = rabo
self.olhos = olhos
self.cor_do_pelo = cor_do_pelo
self.porte = porte
def latir(self):
print('Au au!')
def rosnar(self):
print('Grrrr!')
def cavar(self):
print('Cavando...')
def esconder_o_osso(self):
print('Escondendo o osso...')
class PastorAlemao:
def __init__(self, patas, rabo, olhos, cor_do_pelo, porte):
self.patas = patas
self.rabo = rabo
self.olhos = olhos
self.cor_do_pelo = cor_do_pelo
self.porte = porte
def latir(self):
print('Au au!')
def rosnar(self):
print('Rrrrrrrr!')
def cavar(self):
print('Cavando mais fundo que o poodle...')
def esconder_o_osso(self):
print('Não escondo o osso, eu como')
def uivar(self):
print('Auuuuu!')
class BorderCollie:
def __init__(self, patas, rabo, olhos, cor_do_pelo, porte):
self.patas = patas
self.rabo = rabo
self.olhos = olhos
self.cor_do_pelo = cor_do_pelo
self.porte = porte
def latir(self):
print('Au au!')
def rosnar(self):
print('Grrrrrr!')
def cavar(self):
print('Cavo mais rápido que o Poodle e o Pastor Alemão')
def esconder_o_osso(self):
print('Não escondo o osso, eu como')
def uivar(self):
print('Auuuuu!')
def fingir_de_morto(self):
print('Me fingindo de morto')
def rolar(self):
print('Rolando...')
class ViraLataCaramelo:
def __init__(self, patas, rabo, olhos, cor_do_pelo, porte):
self.patas = patas
self.rabo = rabo
self.olhos = olhos
self.cor_do_pelo = cor_do_pelo
self.porte = porte
def latir(self):
print('Au au!')
def rosnar(self):
print('Grrrrrrrr!')
def cavar(self):
print('Como vim das ruas eu escondo tudo mais rápido que todos pra guardar meus recursos')
def esconder_o_osso(self):
print('Que osso? Eu já comi')
def uivar(self):
print('Não perco tempo uivando, prefiro catar migalha pela casa')
def fingir_de_morto(self):
print('Deixo essa chatice pro Border Collie')
def rolar(self):
print('Deixo essa chatice pro Border Collie também')
Como já falei outras vezes, programador odeia repetição de código.
Menos código significa menos bugs, menos testes, menos manutenção, maior previsibilidade...
E logo de cara podemos ver que nossas 4 classes acima, apesar de serem classes diferentes, apresentam algumas similaridades.
A inicialização de toda classe é igual, com o método __init__ sendo igual em todas as 4 classes.
Todos os 4 cachorros apresentam um método "latir" igual em todos os 4 casos.
As diferenças acontecem nos outros métodos. Tem cachorro que tem o método uivar, tem cachorro que não tem. Tem cachorro que uiva de um jeito, tem cachorro que prefere não uivar. Enfim, acho que deu pra pegar o espírito da coisa.
Como eu posso aproveitar código nesse caso, evitando repetição de código?
Por meio de herança, que é um termo de programação orientada a objetos.
E como fazer uma herança nesse caso?
Podemos criar uma classe base Cachorro, que apresenta as partes de código que são comuns entre todas as outras 4 classes. E as outras classes irão herdar da classe base cachorro.
class Cachorro:
def __init__(self, patas, rabo, olhos, cor_do_pelo, porte):
self.patas = patas
self.rabo = rabo
self.olhos = olhos
self.cor_do_pelo = cor_do_pelo
self.porte = porte
def latir(self):
print('Au au!')
Acima, temos a classe base.
Vamos criar uma instância da classe Cachorro pra testar no console:
In [1]: cachorro = Cachorro(4, True, 2, 'caramelo', 'medio')
In [2]: cachorro.latir()
Au au!
In [3]: cachorro.rabo
Out[3]: True
In [4]: cachorro.cor_do_pelo
Out[4]: 'caramelo'
In [5]: cachorro.porte
Out[5]: 'medio'
Tudo certo, minha classe base tá apresentando o comportamento esperado.
Agora como eu faço para as outras classes que criamos acima herdarem da classe base Cachorro?
Ao definir as subclasses, eu tenho que passar como se fosse um argumento de função a classe base (superclasse) ao definir a função.
Mas pra visualizar melhor, o que é uma superclasse e o que é uma subclasse?

Todas as 4 classes abaixo derivam da classe de cima. As 4 classes que definem uma raça são subclasses e a superclasse é a classe base cachorro.
Vamos criar a primeira subclasse de Cachorro, a classe Poodle:
class Poodle(Cachorro):
def rosnar(self):
print('Grrrr!')
def cavar(self):
print('Cavando...')
def esconder_o_osso(self):
print('Escondendo o osso...')
Observem a primeira linha. Eu passo como se fosse um argumento de função a superclasse para a subclasse.
Observem que não defini um método __init__. Será que dá certo eu inicializar a classe Poodle agora?
Vamos ver:
In [1]: poodle = Poodle(4, True, 2, 'branco', 'medio')
In [2]: poodle.rabo
Out[2]: True
In [3]: poodle.latir()
Au au!
In [4]: poodle.cavar()
Cavando...
In [5]: poodle.patas
Out[5]: 4
Observem que eu aproveitei o código da classe base, a superclasse, e não precisei repetir esse código na subclasse.
O método latir, por exemplo, é definido na superclasse e não na subclasse, a subclasse herdou da superclasse e o comportamento foi dentro do esperado.
Dessa forma, podemos recriar nossas 4 classes originais dessa forma:
class Cachorro:
def __init__(self, patas, rabo, olhos, cor_do_pelo, porte):
self.patas = patas
self.rabo = rabo
self.olhos = olhos
self.cor_do_pelo = cor_do_pelo
self.porte = porte
def latir(self):
print('Au au!')
class Poodle(Cachorro):
def rosnar(self):
print('Grrrr!')
def cavar(self):
print('Cavando...')
def esconder_o_osso(self):
print('Escondendo o osso...')
class PastorAlemao(Cachorro):
def rosnar(self):
print('Rrrrrrrr!')
def cavar(self):
print('Cavando mais fundo que o poodle...')
def esconder_o_osso(self):
print('Não escondo o osso, eu como')
def uivar(self):
print('Auuuuu!')
class BorderCollie(Cachorro):
def rosnar(self):
print('Grrrrrr!')
def cavar(self):
print('Cavo mais rápido que o Poodle e o Pastor Alemão')
def esconder_o_osso(self):
print('Não escondo o osso, eu como')
def uivar(self):
print('Auuuuu!')
def fingir_de_morto(self):
print('Me fingindo de morto')
def rolar(self):
print('Rolando...')
class ViraLataCaramelo(Cachorro):
def rosnar(self):
print('Grrrrrrrr!')
def cavar(self):
print('Como vim das ruas eu escondo tudo mais rápido que todos pra guardar meus recursos')
def esconder_o_osso(self):
print('Que osso? Eu já comi')
def uivar(self):
print('Não perco tempo uivando, prefiro catar migalha pela casa')
def fingir_de_morto(self):
print('Deixo essa chatice pro Border Collie')
def rolar(self):
print('Deixo essa chatice pro Border Collie também')
Vamos criar instâncias de cada subclasse agora:
In [1]: poodle_john = Poodle(4, True, 2, 'branco', 'pequeno')
In [2]: pastor_k9 = PastorAlemao(4, True, 2, 'marrom', 'grande')
In [3]: border_collie_jaco = BorderCollie(4, True, 2, 'preto', 'grande')
In [4]: vira_lata_caramelo = ViraLataCaramelo(4, True, 2, 'caramelo', 'medio')
In [5]: vira_lata_caramelo.latir()
Au au!
In [6]: border_collie_jaco.cavar()
Cavo mais rápido que o Poodle e o Pastor Alemão
In [7]: pastor_k9.esconder_o_osso()
Não escondo o osso, eu como
In [8]: poodle_john.esconder_o_osso()
Escondendo o osso...
Ainda tem coisa que dá pra melhorar nesse código, ainda tem repetição, mas o recado de hoje era um recado inicial sobre herança, nos próximos tópicos teóricos continuamos de onde paramos.