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

Simon Amz
Simon Amz
4,606 Points

Calling super class inheritance

Hi, I don't understand why in the Agile and Sneaky classes, we don't inherit from Character. Indeed, the declaration is :

"class Agile:" and "class Sneaky:" instead of "class Agile(Character):" and "class Sneaky(Character):"

in this case, when you're using "super()" with def __init__, which is the super class it inherit from as the class is not specified?

5 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,423 Points

Good question! The classes Agile and Sneaky certain could have been declared as inheriting from Character. It still would work but it starts to become less than clear what the intentions are.

class Agile(Character):
class Sneaky(Character):
class Thief(Agile, Sneaky):
# or
class Thief(Agile, Sneaky, Character): # still works

By having them both inherit from Character, it implies that one might wish to create an Agile instance or a Sneaky instance, but this isn't the goal of this code. Kenneth wished to create add-in (or "mix-in") attributes that could be used generically to add to any class.

An extension would be if there was a Monster class, then the Agile and Sneaky could be reused to add those attributes to a specific monster class, as opposed to creating a monster version of "agile" that inherited from Monster instead of Character.

Given the original code class Thief(Agile, Sneaky, Character): The super().__init__() order is the same as the Method Resolution Order (MRO):

>>> from thieves import Thief                                                             
>>> Thief.__mro__                                                                         
(<class 'thieves.Thief'>, <class 'attributes.Agile'>, <class 'attributes.Sneaky'>, <class 'characters.Character'>, <class 'object'>)                                                

You might think the MRO would be:

Thief --> Agile --> object --> Sneaky --> object --> Character --> object

But since Character depends on object, the earlier object references are removed and only the last object is retained:

Thief --> Agile --> Sneaky --> Character --> object

Post back if you have more questions. Good luck!

Edit: Hara and Pete ask: why use super() in Agile and Sneaky?

When using multiple inheritance (inheriting from more than one class) all references are resolved by looking in the local code first, then one by one each of the inherited classes are checked for the reference. Once a reference is found it is used immediately and the search stops.

The use of super() indicates to continue searching for the indicated reference down the Method Resolution Order (MRO) for more code to execute.

In the case of creating a new instance, the __init__ method is called. If the Thief class had an __init__ method without a super() call, execution would stop there. If there isn't a local __init__ then the search would continue with the inherited classes.

By using super() in the Agile and Sneaky class you guarantee that __init__ method in all inherited class will get an opportunity to be executed.

Edit: Kafe Hezam asks: why not remove *args from both Agile and Sneaky?

In this case, since no positional arguments are used *args could be removed. However, not removing the generic positional placeholder *args allows the attribute classes Agile and Sneaky to be used with other classes besides Character where positional arguments may be in use. It’s common practice to include both *args and **kwargs to allow greater reuse.

Thanks a lot :)

Hara Gopal K
PLUS
Hara Gopal K
Courses Plus Student 10,027 Points

Chris Freeman

understood to some extent, but still not so clear. the question is, what are we trying to achieve by using the super() in Sneaky and Agile classes. In other words, what are we inhering, and from where, and why ?

thanks for some clarifications hara

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

Hara Gopal K, great question. I've expanded my answer above. Post back if you have more questions.

Pete P
Pete P
7,613 Points

I have the same question. In the previous examples, it was obvious to me what super() was being used for. In this video I do not see the purpose for using super() in the Sneaky and Agile class.

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

Pete P, great question, I've expanded my answer above. Post back if you have more questions.

Pete P
Pete P
7,613 Points

Thank you Chris! I found your's and ds1's answers to this question very helpful!

Much appreciated.

Bob Pickles
Bob Pickles
1,363 Points

They aren't supposed to be inheriting from Character, they are inheriting from object. Keep in mind that all classes inherit from object. In python 3 this inheritance is implicit so Sneaky() is the same as Sneaky(object)

Reference: https://stackoverflow.com/questions/4015417/python-class-inherits-object

Chris Freeman, When Kenneth explicitly sets name to equal "Kenneth" which gets store into **kwargs since its a keyword argument. So if I delete *args from both classes Agile and Sneaky It'l give me the same answer as if it was not deleted. Then what's the point of keeping *args? :))

Chris Freeman
Chris Freeman
Treehouse Moderator 68,423 Points

Great question! The short answer is using both *args and **kwargs allows for wider reuse of code. See expanded answer above.