Welcome to the Treehouse Community
The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)
Looking to learn something new?
Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.
Philip Schultz11,343 Points
When to use self.value when overloading
Can someone explain to me what is happening in this video? Why is Kenneth using 'self.value' in some cases and 'self' in others. How are we suppose to know when to use one or the other?
For example, here is a piece of code from the video on using
__add __ .
def __add__(self, other): if '.' in self.value return float(self) + other return int(self) + other
The magic methods above the
__add__ methods all use self.value.
For example, here is the
def __int__(self): return int(self.value)
How can you use int(self) if the instance is more complex? I'm assuming this is a simple example in the video and the class only has one attribute, but what if there are multiple attributes. Wouldn't you have to use self.value or self.paycheck or what attribute you wan't to do the math with?
Also, can someone explain how
__radd__ is working? I thought the purpose of making it is because we are not able to add an instance of NumString to a number if it's located on the right of the equation. If that is the case why are we typing self + other and not other + self, with the instance on the right side. Is it implicitly calling
__add__ somehow? Why don't we have to check the value is a float or an int like in
[MOD: added ` escapes on method names -cf]
Chris FreemanTreehouse Moderator 67,994 Points
Good questions Philip!
In the following explanation keep in mind that
self.value refers to the stored string value and
self refers to the
NumString object. The key to knowing which to use is to think about the context. Is the string value needed or the object itself needed? The answer is sometimes it doesn't matter.
__add__ method, addition usually returns a number, so the
__add__ method needs to convert the stored string value to a number before adding to the other operand passed in. The simplest way would be to use the methods from this class since they have been written explicitly for this purpose. That is, the
__float__ methods return the appropriate numeric representation of the NumString instance for use in addition. Calling
float(self) will explicitly call the
__float__ method of the "self" object. Since both the
__float__ methods operate on a NumString object, an object must be passed to it.That is why
self is used. The condition in the
if statement is checking for a decimal point in the value, so it must use
self.value to see the actual object value.
__int__ method, the object is to get back a numeric integer value.
self.value is used to as the argument to
int() so that the objects value can be converted from a string to an integer. If
return int(self) had been used, it would trigger another call to
__int__ causing an infinite loop. This recursive call to
__int__ would end in an "
RecursionError: maximum recursion depth exceeded while calling a Python object" Yikes!
NumString class, the
__add__ method could have used
int(self.value) instead of using
__int__(self) which returns
The main point of using the object reference in
int(self) is that it is not always obvious which attribute should be used in the context of addition or exactly how a numeric value for an object should be created. Using
int(self) will always call the
__int__ method of the class which is explicitly written to provide the numeric context value. If the
__add__ method converted the object to a numeric context in its own way it could possible differ from the process used in
__int__ and would most certainly violate the DRY principle.
__radd__ method, by using
self + other it triggers a call to
__add__ with the same arguments since the "self" is now on the left side of the operator instead of the right side. In most cases, object addition is symmetrical (a + b == b + a), so it is effectively passing the task along to
__add__ method. If
other + self had been used in
__radd__, an infinite loop would be created as
other + self triggers another call to
__radd__. Yikes, again!
__radd__ redirects the call to
__add__, there is not need to check the if the value is a
float or an
int since it is covered in the
I hope I covered it all. Post back if you have more questions! Good luck!!
Iulia Maria Lungu16,923 Points
I would like to add something to the great explanation of @Chris Freeman already gave because it made me understand things better. Regarding this:
Also, can someone explain how
__radd__is working? I thought the purpose of making it is because we are not able to add an instance of NumString to a number if it's located on the right of the equation. If that is the case why are we typing self + other and not other + self, with the instance on the right side. Is it implicitly calling
This would not work if the implemented methods were not
__rsub__, just because addition or multiplication are commutative mathematical operations but subtraction for instance is not. Below is what I did to have subtraction in place.
class NumString: def __init__(self, value): self.value = str(value) def __int__(self): return int(self.value) def __str__(self): return self.value def __add__(self, other): return int(self) + other def __radd__(self, other): return self + other def __sub__(self, other): return int(self) - other def __rsub__(self, other): return - (self - other)
Anthony CrespoPython Web Development Techdegree Student 12,961 Points
I'm no expert but maybe I can help.
self represents the instance of the class. By using the "self" keyword we can access the attributes and methods of the class in python.
Outside of a class you call an object by it's name.
Var_one + Var_two Var_one.function()
But when you are writing a function inside your class the name of your variable is lost. That's why we call "self" and not the "Variable_name". So when you create the __ int__ function you write:
def __int__(self): return int(self.value) # self.value equal to variable_name.value if it was outside "class"
When you create that function above inside your class, your class now have the possibility of been represented in an integer value. Without that function it doesn't know what to return if you want to turn your object in to an integer. It's the same thing for an object of type int. Inside that int class there is some functions that does the same to represent that int value in other variable type. But if you create a new type of variable like "Character" and want to convert it in to an int like this:
>>> variable = Character() # variable type is Character >>> int(variable) # You pass a Character type object to an int # You get this message error cause it doesn't know how to represent a Character in to an int. TypeError: int() argument must be a string, a bytes-like object or a number, not 'Character'
TLDR : Inside your __ int__ function you return int(self.value) that represent a str type, a type int already know how to represent and inside your __ add__ function you return int(self) cause now it's possible to represent your object in to an int cause of that other function.