Usamos herança e polimorfismo em orientação a objetos para reaproveitar atributos e métodos e evitar duplicidade de código. São parecidos, porém com pequenas diferenças.
Herança
Quando herdamos atributos e métodos de uma superclasse para reutilizar.
from dataclasses import dataclass
@dataclass
class NPC:
nome: str
dano: int
def atacar(self, player):
player.hp -= self.dano
class Globin(NPC):
pass
class KingGlobin(NPC):
pass
# classe de exemplo player
@dataclass
class Player:
hp: int = 1000
# instanciando player
player = Player()
g = Globin(nome="Globin filhote", dano=5)
kg = KingGlobin(nome="Rei Globin", dano=30)
g.atacar(player)
print(f'{g.nome} ataca player. Player HP: {player.hp}')
kg.atacar(player)
print(f'{kg.nome} ataca player. Player HP: {player.hp}')
# RESULTADO:
# Globin filhote ataca player. Player HP: 995
# Rei Globin ataca player. Player HP: 965
Perceba que criamos uma classe NPC que possui atributos nome e dano, e um metodo atacar. Depois aplicamos herança nas subclasses Globin e KingGlobin, herdando a superclasse NPC para reaproveitar o codigo e não precisar replicar.
Polimorfismo
Quando herdamos atributos/metodos de uma superclasse porem implementamos de forma diferente.
from dataclasses import dataclass
@dataclass
class NPC:
nome: str
dano: int
def atacar(self, player):
pass
@dataclass
class Globin(NPC):
count_attack: int = 0
def atacar(self, player):
if self.count_attack == 5:
self.dano += 1
self.count_attack = 0
player.hp -= self.dano
self.count_attack += 1
@dataclass
class KingGlobin(NPC):
fatality: int = 300
count_attack: int = 0
def atacar(self, player):
if self.count_attack == 5:
player.hp -= self.dano + self.fatality
self.count_attack = 0
else:
player.hp -= self.dano
self.count_attack += 1
# classe de exemplo player
@dataclass
class Player:
hp: int = 1000
# instanciando player
player = Player()
g = Globin(nome="Globin filhote", dano=5)
kg = KingGlobin(nome="Rei Globin", dano=30)
# se você atacar 6 vezes com cada um, verá as modificações no HP do player
for x in range(6):
g.atacar(player)
print(f"{g.nome} ataca player. Player HP: {player.hp}")
kg.atacar(player)
print(f"{kg.nome} ataca player. Player HP: {player.hp}")
# RESULTADO
# Globin filhote ataca player. Player HP: 995
# Rei Globin ataca player. Player HP: 965
# Globin filhote ataca player. Player HP: 960
# Rei Globin ataca player. Player HP: 930
# Globin filhote ataca player. Player HP: 925
# Rei Globin ataca player. Player HP: 895
# Globin filhote ataca player. Player HP: 890
# Rei Globin ataca player. Player HP: 860
# Globin filhote ataca player. Player HP: 855
# Rei Globin ataca player. Player HP: 825
# Globin filhote ataca player. Player HP: 819 <-- incremento de dano do globin
# Rei Globin ataca player. Player HP: 489 <-- fatality do rei globin
Perceba que as subclasses Globin e KingGlobin herdam a superclasse NPC, porém o Globin possui um atributo count_attack que a cada vez que ataca é incrementado, e se fizer 5 ataques, ele aumenta em +1 o dano. Já o KingGlobin também possui um count_attack e um fatality, que chegando à 5 ataques o dano é somado com o fatality gerando um dano maior ao player. Ou seja, os 2 herdam o método ataque mas a implementação é diferente.