Very new to Python, trying to create a game in which any number of armies can be created, but each army will pre-render the names of the soldiers.
I think I need to be using super init to really cut down on duplicate code, but I cannot for the life of me figure out how to make it work. From what I understand my class Army should be the Parent class, with RedArmy and Scout as subclasses. I'm just struggling to understand where the super().__init__() should come in?
class Army:
def __init__(self):
self.color = None
self.scoutname = None
self.demomanname = None
self.medicname = None
def train_scout(self, weapon):
return Scout(self.color, self.scoutname, weapon)
class RedArmy(Army):
def __init__(self):
self.color = "Red"
self.scoutname = "Yankee"
self.demomanname = "Irish"
self.medicname = "Dutch"
class BlueArmy(Army):
pass
class Scout:
specialization = "fast captures"
def __init__(self, color, scoutname, weapon):
self.color = color
self.scoutname = scoutname
self.weapon = weapon
def introduce(self):
return (f'Hi I\'m {self.scoutname}, I do {self.specialization} and I wield a {self.weapon}')
my_army = RedArmy()
soldier_1 = my_army.train_scout("baseball bat")
print(soldier_1.introduce())
Where to put the super().__init__ (if anywhere) depends on the specifics of your class hierarchy.
Most commonly, if it matters where you put it, you want it at the very start of the subclass's __init__ method. This makes sure that all of the base-class variables are set up, all of its invariants are met, and all of its methods can be called by the rest of the subclass __init__ code.
In your case, it matters because you're setting the same attributes in the base class and the subclass. You obviously want the subclass version to be the one that takes, so it has to come after the default assignments, not before:
class RedArmy(Army):
def __init__(self):
super().__init__()
self.color = "Red"
self.scoutname = "Yankee"
self.demomanname = "Irish"
self.medicname = "Dutch"
However, it's worth considering whether you really want the base class to set these variables to None in the first place.
I assume that in your real code, BlueArmy isn't just going to pass, but is instead going to do the same thing as RedArmy, replacing all of those values with some strings.
Also, the rest of your code is presumably going to assume that there are valid strings there, not None. An exception like TypeError: '<' not supported between instances of 'NoneType' and 'str' is harder to debug than AttributeError: 'GreenArmy' object has no attribute 'scoutname', not easier, so why not just leave the defaults out? Then you can eliminate Army.__init__ entirely, and you don't have to worry about calling super in the subclass initializers in the first place.
Or, alternatively, you could have Army.__init__ take parameters that are used to assign the values, and have the subclasses call super().__init__("Red", "Yankee", "Irish", "Dutch"). Then, Army() will raise a TypeError instead of creating an invalid Army instance. Or you could make an @abstractmethod named self._setup() that Army.__init__ calls and expects each subclass to provide, so Army() will raise an even more meaningful TypeError about instantiating an abstract class. These refinements make it easier to debug your Army subclasses—if you just have two of them, they may just be a waste of time, but if you have a bunch of them, which will be developed by a variety of people or over a long period of time, it might be worth it.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With