Well, I created some classes to explain some important concepts.
The Athlete class is the base where you will have the attributes and the common methods in all other classes.
class Atleta:
def __init__(self, tipo, aposentado, idade):
self.tipo = tipo
self.aposentado = aposentado
self.idade = idade
def imprime(self):
print(f'Tipo: {self.tipo} | Aposentado: {self.aposentado} | Idade: {self.idade}')
def aposentar(self):
if self.aposentado == 'Não':
if self.idade >= 65:
self.aposentado = 'Sim'
print(f'{self.tipo} de {self.idade} anos acabou de se aposentar!')
else:
print(f'{self.tipo} de {self.idade} anos ainda não tá na hora de se aposentar!')
else:
print(f'{self.tipo} de {self.idade} anos já é aposentado!')
def aquecer(self):
print(f'{self.tipo} de {self.idade} anos está aquecendo!')
Therefore, to create another custom class, it is passed as inheritance the class Atleta and inherited methods and attributes, leaving only to declare the method responsible for this type of Athlete.
class Corredor(Atleta):
def __init__(self, tipo, aposentado, idade):
super(Corredor, self).__init__(tipo, aposentado, idade)
def correr(self):
print(f'{self.tipo} de {self.idade} anos está correndo!')
class Nadador(Atleta):
def __init__(self, tipo, aposentado, idade):
super(Nadador, self).__init__(tipo, aposentado, idade)
def nadar(self):
print(f'{self.tipo} de {self.idade} anos está nadando!')
class Ciclista(Atleta):
def __init__(self, tipo, aposentado, idade):
super(Ciclista, self).__init__(tipo, aposentado, idade)
def pedalar(self):
print(f'{self.tipo} de {self.idade} anos está pedalando!')
It is possible to notice that Triathlete inherits the other 3 classes, so it is possible to pass to this class the unique methods of every class, that is code reuse!
class TriAtleta(Corredor, Nadador, Ciclista):
def __init__(self, tipo, aposentado, idade):
super(TriAtleta, self).__init__(tipo, aposentado, idade)
Here a dictionary is created with the appropriate actions like string of each type of class, that is, if you pass an Athlete as a parameter, it is returned ['prints', 'retire', 'warm up'].
acoes = {
'Atleta': ['imprime', 'aposentar', 'aquecer'],
'Corredor': ['imprime', 'aposentar', 'aquecer', 'correr'],
'Nadador': ['imprime', 'aposentar', 'aquecer', 'nadar'],
'Ciclista': ['imprime', 'aposentar', 'aquecer', 'pedalar'],
'TriAtleta': ['imprime', 'aposentar', 'aquecer', 'correr', 'nadar', 'pedalar'],
}
Here are Instantiated the Classes generating the Object of each type of athlete.
atleta = Atleta('Atleta', 'Não', 78)
corredor = Corredor('Corredor', 'Não', 66)
nadador = Nadador('Nadador', 'Sim', 70)
ciclista = Ciclista('Ciclista', 'Sim', 76)
triatleta = TriAtleta('TriAtleta', 'Não', 65)
As @epx well commented, it is possible to traverse a loop for each athlete and the other loop is for each action of that particular athlete. The getattr method calls the function with the name of each action of the current athlete, if it does not find the method, it returns a function that returns an empty string. That is polymorphism.
for pessoa in [atleta, corredor, nadador, ciclista, triatleta]:
for acao in acoes[pessoa.tipo]:
getattr(pessoa, acao, lambda: '')()
References
https://wiki.python.org.br/ProgramacaoOrientadaObjetoPython