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 trialClifford Gagliardo
Courses Plus Student 15,069 PointsWhy do we need magic methods here?
I don't understand why we need magic methods here. Maybe I don't understand when or why we need magic methods to begin with. Why do they have to be defined inside of the class and what is this value "other"? Is it a special/reserved word? I don't understand to what "other" is referring in our def arguments.
6 Answers
Chris Freeman
Treehouse Moderator 68,457 PointsThe class D6
inherits from class Die
which, by default, inherits from the built-in class object
. This base object
class which doesn't have a robust sense of "value" or comparison. Without any overridden magic methods, it would compare on the object ID value, which would almost certainly be False. The magic methods are called to resolve how to treat the object when an operator is present (+, /, *, ==, !=, <=, >=, etc.).
Given thing1 operator thing2
, the "operator" magic method of thing1 is called to resolve the expression. thing2 would be "other" in this case. if this operator magic method isn't found then *reverse" version of the method (for example, 'radd" instead of "add") of thing2 is called to resolve the expression. Here, thing1 would be the "other".
Josh Keenan
20,315 PointsOther is an argument being passed in as a comparison with the actual value of the Di and is not a reserved word, anything could have been used.
Clifford Gagliardo
Courses Plus Student 15,069 PointsIf operands are the same everywhere, how come their behavior has to be defined by a magic method within a class? That is the part I don't really understand. Like, with __radd__
helping to make addition work with items on either side of the + operator, but outside of a class, I can get "25" when I add 10+15 or 15+10.
Chris Freeman
Treehouse Moderator 68,457 PointsI misread your previous comment as "operator" instead of "operand". I've updated my comment above and add new comment on operators
Iulia Maria Lungu
17,357 PointsChris Freeman , wouldn't this have been simpler if the class would have extended int
class ? The operations would have been already defined, right? What am I missing? Or is re-defining the __magic_methods__
the whole point of the video?
Thinking twice what I said would not work because when extending not mutable types like int we'd have to use the __new__
method instead of__init__
, but I have a feeling that somehow one can make use of the int class
methods here instead of writing them down by hand. Is this doable?
Update: Just seen this answer of yours from above:
Sometimes creating the required magic methods is trivial by subclassing an built-in class which inherits all of the parent class methods. For example, Die, the parent class to D6 could have subclassed the built-in int class to get all of the int magic methods, but then the lesson on creating the magic methods from scratch would have been missed. How would this look like?
I tried to do it but did not manage to make it work
Chris Freeman
Treehouse Moderator 68,457 PointsGreat question Iulia Maria Lungu! It is certainly possible to build the Die
and D6
class by inheriting from int
by it's a more advanced concept. The difficulty lies in int
is an immutable class type. In addition to defining the __init__
method, the __new__
method also needs to be defined. The __new__
method creates the class instance, and the __init__
method initializes it. For mutable classes, the default __new__
method inherited from the base class object
is usually sufficient.
I'll add a comment to my answer above showing how you can create Die
and D6
by subclassing int
.
amandae
15,727 PointsI'm curious, and not quite sure how to work out the answer. Is it more efficient, in BigO time/space complexity to subclass init, or to list out the magic methods? It seems like there are many repetitive calls in the subclassing example above, but maybe there are just as many the other way? How do the memory requirements compare, to pull in an entire class, vs bringing in individual pieces. I could really see that going either way. Which is a more stable build option? Does subclassing the built in give a more stable base, or does it go the opposite direction, and give more opportunity for unexpected answers?
It obviously doesn't matter for this project, but I'm thinking about how this might be applied elsewhere.
Chris Freeman
Treehouse Moderator 68,457 PointsThe complexities of including math and comparison operators is independent of where the magic method resides. The repetitive calls are part of the structure of python. The built in types int
, float
, str
, etc., are all optimized for performance when using operators. Most class definition is for structured data and rarely needs math support. Also, since __init__
is only run once per class instantiation there is little benefit in trying to optimize it.
Listing out the magic methods to override parent methods with the methods of the same functionality would be confusingly redundant. If a method is not present, it is looked for in the namespace of the first parent. So it’s a one-look-up delay.
Pulling in pieces or “entire classes” really only involves bring in a reference to a name space dictionary. So space is a non-issue. Use it if you need to augment a parent method.
Adding methods that aren’t explicitly needed isn’t DRY (don’t repeat yourself) and could provide a path to introduce errors. If a local Methodist needed, a complicated method will often refer to the parent’s method using super()
to do most of the work and then tweak the result locally.
Post back if you need more help. Good luck!!!
amandae
15,727 PointsThanks, Chris Freeman.
All of that is helpful and makes sense. I appreciate your gracious answers!
Josh Keenan
20,315 PointsJosh Keenan
20,315 PointsThe man, the myth, the legend.
Clifford Gagliardo
Courses Plus Student 15,069 PointsClifford Gagliardo
Courses Plus Student 15,069 PointsThank you. So, do operands behave differently within classes than outside of them and therefore need fine tuning?
Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsThe operators are the same everywhere, in that they trigger the same magic methods. For example, plus will always trigger the
__add__
method. It's the magic method behavior that differs between classes.Edit: meant to say operator instead of operand.
Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsAs for operands
thing1
andthing2
, they behave as their class magic methods are defined regardless of where they're being being used whether inside their own class or not.All built-in types (int, list, string, set, dict, etc.) all have their magic methods predefined making expressions like
10 + 15
work everywhere.Most user-defined classes, like Django models and class views, etc, aren't typically used in math expressions. That's why creating magic methods for classes is a fairly rare task. It's when users create a class that will be used in math expressions that the magic methods will need to be defined.
Sometimes creating the required magic methods is trivial by subclassing an built-in class which inherits all of the parent class methods. For example,
Die
, the parent class toD6
could have subclassed the built-in int class to get all of the int magic methods, but then the lesson on creating the magic methods from scratch would have been missed.If not subclassing when creating a new class that will be used with operators, then all of the magic methods need to explicitly created.
Let's walk through an example of parsing an addition expression:
Natalie Tan
25,519 PointsNatalie Tan
25,519 Pointsrather than go through setting up all these magic methods, could we not just have used 'd6.value' ?
Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsNatalie Tan, using
d.value
whered = D6()
, would depend on what you plan to do. Without the magic methods you would be limited to always using including the attribute name in your coded.value
, or if__int__()
was defined, calling int(d) to give you the numeric value for that object.The purpose of the magic methods is to allow using the simple object reference
d
in whatever context you wish and have the object know how to behave in that context, whether it be adding, or in comparisons to other objects.Please post back if you need more details!
Chris Freeman
Treehouse Moderator 68,457 PointsChris Freeman
Treehouse Moderator 68,457 PointsCreating
D6
andDie
by sub-classing theint
class is more complicated than a simple inheritance due toint
being an immutable class. Sub-classing immutable classes is covered later in the coursework. Below is one way to sub-classint
. Note the print statements are only to show which methods are run.