Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Python Object-Oriented Python Inheritance Multiple Superclasses

Flore W
Flore W
4,744 Points

Why change the order from Thief(Character, Agile, Sneaky) to Thief(Agile, Sneaky, Character) and what's better?

In the Multiple Superclasses video, Kenneth initially had the code:

class Character:
    def __init__(self, name, **kwargs):
        self.name = name
        for key, value in kwargs.items():
            setattr(self, key, value)

class Sneaky:
    sneaky = True

    def __init__(self, sneaky = True, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.sneaky = sneaky

    def hide(self, light_level):
        return self.sneaky and light_level < 10


class Agile:
    agile = True

    def __init__(self, agile = True, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.agile = agile

    def evade(self):
        return self.agile and random.randint(0, 1)


class Thief(Character, Agile, Sneaky):
    def pickpocket(self):
        return self.sneaky and bool(random.randint(0,1))

Later on in the video he changed the order of the classes called in Thief to:

class Thief(Agile, Sneaky, Character):
    def pickpocket(self):
        return self.sneaky and bool(random.randint(0,1))

and subsequently had to change code for Character to:

class Character:
    def __init__(self, name="", **kwargs):
        if not name:
            raise ValueError("'name' is not required")
        self.name = name

        for key, value in kwargs.items():
            setattr(self, key, value)

Both codes work and give the same results, so what's are the pros and cons for each and which one is best practice? (To me the first option seemed much simpler)

1 Answer

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,454 Points

As it is coded currently it is a wash either way. Because Character.__init__() does not include a call to super().__init__(), if Character is the first class listed theinitmethods ofAgileandSneakywill not be run. This appears to be OK since both of these classes set the attribute toTrueby default and any keyword arguments to set them toFalseis handled in thefor key, value in kwargs.items():loop ofCharacter`.

However, if a super call isn't added to Character then it is better to have this class last. This covers the case where if/when either the Agile or Sneaky class change and include other functionality in their __init__ methods that must run for proper initialization it will properly be executed.

The short answer is all classes other than the last one listed should have a call to super() in their __init__ to insure full initialization.

Flore W
Flore W
4,744 Points

Thank you Chris!