Can an object be promoted from a class to another one ? (from padawan to jedi master)

Viewed 71

I want to model the jedi order from Star Wars as follows:

a novice can:

  • (1) learn with books

a padawan can:

  • (1) learn with books
  • (2) learn with his master

a knight can:

  • (3) go to war
  • (4) take the test to become a master
  • (5) become a master (if he passes the test)

a master can:

  • (3) go to war
  • (6) take a novice as a padawan (and transform the novice into padawan)
  • (7) complete the training of his padawan and make him a knight (and transform the padawan into knight)

The pain point I'm going through is that at some point I would like to do this:

anakin  # novice
obiwan  # master
obiwan.takes_padawan(anakin)
anakin  # padawan

In other words, I'd like to promote an instance of Novice class to an instance of Padawan class. I saw some solutions that only solved partially the above enumerated constraints like:

  • using metaclasses (meh)
  • having only one class with an attribute grade and several promote methods

H.E.L.P haha

Thank you folks :)

1 Answers

You don't want to promote the same object, but you could create a new object based on the old one - something like:

padawan = Padawan(novice) #creates a new Padawan using information from a novice

However, I'd go a step further and separate the person and the skill level / rank, so that the person object can stay but you can replace the rank (or however it should be called). This can make it nice and clean to have the war skills etc. in their own classes. This is the aggregation, or composition, over inheritance pattern. Not a perfect solution but maybe gives the idea:

class Person:
  def __init__(self, name):
    self.name = name
    self.rank = None

  def update(self):
    if self.rank is not None:
      self.rank.do()

class Novice:
  pass

class Padawan:
  def __init__(self, person, master):
    self.person = person
    self.master = master

  def do(self):
    print(f"I am Padawan {self.person.name}, Learning from my master {self.master.person.name}")

class Master:
  def __init__(self, person):
    self.person = person
    self.padawans = []

  def take_padawan(self, person):
    person.rank = Padawan(person, self)
    self.padawans.append(person)

anakin = Person("Anakin")
anakin.rank = Novice()
obiwan = Person("Obi-Wan")
obiwan.rank = Master(obiwan)

print(anakin.rank)
obiwan.rank.take_padawan(anakin)
print(anakin.rank)
anakin.update()

You can run that at https://repl.it/@ToniAlatalo/RealCompetentDevices#main.py

Related