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, __init__ , and self.argument

I am trying to understand when you need a self.argument for an instance of a class, and when you do not. Prior to using init, we were able to have instances such as jubjub = Monster() and then look at attributes such as jubjub.color, without using self.color. It is looking to me like you use self.attribute whenever you are inside a Method. But in the final monster game, I see a variable called player_choice inside the player_turn Method, and that variable name does not have a self modifier, so I am confused.

8 Answers

Chris Freeman
MOD
Chris Freeman
Treehouse Moderator 68,468 Points

self refers to an instance. When attributes are added to a class they are referred to as an attribute of that object using self. Since players_choice is not intended to become used as a persistent attribute, a local variable works.

class Monster():
    # class attributes
    height = '6'
    color = 'blue'

    def change_color(self, newcolor):
        '''Change monster color'''
        self.color = newcolor

# new instance
dragon = Monster()
dragon.color # will be blue
dragon.change_color('green')
dragon.color # will be green

In this code, dragon has the same methods as Monster'. Whendragon.change_color()is called, the method needs to know which instance of Monster is changing colors. Python realizes this and automatically passes the instance as the first parameter. This instance reference is assigned toselfduring the method execution. Nowself.color` is referencing the color of this dragon instance.

self is used to reference attributes of an object. If a variable is not indented to persist with the instance for later use, there isn't a need to make it an attribute using self

Ready to Stretch Your Mind?!?

The "class variables" are in their own namespace. That is, when the instance dragon changes colors or add other attributes, they are part of the instance namespace and not the base class Monster(). Here an example from ipython:

in [157]: class Monster():
   .....:     color = 'blue'
   .....:     def change_color(self, newcolor):
   .....:         self.color = newcolor
   .....:         

In [158]: dragon = Monster()

In [159]: dragon.color  # class color
Out[159]: 'blue'

In [160]: dragon.color = 'green'

In [161]: dragon.color  # instance color overrides (not overwrites) class color
Out[161]: 'green'

In [162]: del dragon.color # delete instance attribute

In [163]: dragon.color #color reverts to class color
Out[163]: 'blue'

In [164]: Monster.color = 'cyan'  # change color at the base class

In [165]: dragon.color # color changes too because it has no instance color so references class color
Out[165]: 'cyan'

I'll take a stab at this :)

Using self is necessary to access the instance itself while writing methods and creating attributes. Self gives you the ability to have different names for the instances. If you used jubjub while writing your methods and attributes instead of self, you could only ever have an instance called jubjub. But with self you can call it anything when you create and instance and still access your attributes/methods.

self.color will only be used in writing the attribute/method, but you must use the jubjub.color or whatever the particular instance is called to access that specific instance.

The use of init does not necessarily change this. init allows you to inherit from another class while also defining new initialize attributes.

I hope this helps. This is how I understand it, but am certainly no expert. I would enjoy hearing some more explanation on these topics. Cheers.

Hmm, I am not sure I get what you have stated here. I feel like I could create a class called Monster. Then type color = 'yellow' (without using self), then use a def init(self) to define a weapon to be a sword (using self). Then if I create an instance called jubjub by typing jubjub = Monster(), I would find that the color is yellow and the weapon is a sword. So self is not necessary for creating attributes outside of methods. I can create any number of monsters this way, with different names, and they would all have the color yellow, without ever using self. Self is only necessary inside methods, and I understand that it is needed there.

So, I am wondering how the instructor got away with not using the self modifier inside the method player_turn.

Thanks for your input!

I think that self.variable is not needed for a variable that is only used inside of the method. Perhaps you need to use self.variable with variables that are passed around the class, inside and outside of methods.

Hold on, wait, wait, wait, I don't have a very stretchable mind! Let me go back and ask - if I make a class called Monster, and then set the color to 'yellow' without doing anything else, no def init, etc. Then I go to my console and make a Monster called jubjub. Is jubjub an instance of Monster? Is color an attribute of jubjub? In this very simple case, I can reference the an attribute of jubjub without using self, correct? I only need self when I am passing instances into methods, because the method needs to know which instance to deal with, correct?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,468 Points

if I make a class called Monster, and then set the color to 'yellow' without doing anything else, no def init, etc. Then I go to my console and make a Monster called jubjub. Is jubjub an instance of Monster? Yes!

Is color an attribute of jubjub? Yes, though since it did not set it within the instance, it inherits it from Monster.

In this very simple case, I can reference the an attribute of jubjub without using self, correct? Yes and no. In refering to jubjub in other code you can use jubjub.self, when referreing to color within methods of jubjub you will need to use self.color

I only need self when I am passing instances into methods, because the method needs to know which instance to deal with, correct? Yes, if you mean need self as in it being the first argument of a defined method parameter list.

Think about this: color is an attribute of an object. You access it by identifying instance DOT color whether that be self.color or dragon.color

I wrote the questions above because you said "self is used to reference attributes of an object". My point is that self is not always used. Is that correct? If you have very simple code like I described above, Python operates without using self, correct? You only need to bring in self when you start adding methods and passing arguments into and out of them, correct?

Thanks for ans my question about when you do not use self inside methods. It looks like I figured that one out correctly, that self is not needed on a variable that is not an attribute of the instance and that is only being used locally (within the method).

"When dragon.change_color()is called, the method needs to know which instance of Monster is changing colors. Python realizes this and automatically passes the instance as the first parameter."

So this is what I find confusing. Why does Python need to pass the instance as the first parameter (self), when the instance was spelled out at the front of dragon.change_color()?

Chris Freeman
Chris Freeman
Treehouse Moderator 68,468 Points

Getting deeper! Hang on...

change_color() is a method of the class Monster. There are not multiple versions of this code hanging around. There is just the version that is attached to the base class. An instance doesn't get its own copy, rather python points dragon.change_color() to the class method Monster.change_color(). The passed self is how this single piece of code can tell which instance it is actually operating on.

Similar to the "brain expanding" example of class verses instance color attributes, the change_color() methods also use the same process where an instance method overrides (not overwrites) the class method. It would seem possible if dragon created its own instance version for change_color() that it would need self, since, it is the dragon's version. To keep the paradigm method usage the same, self is passed to both. self is also needed to differentiate attributes of dragon from local variables in the dragon method code.

So what I find confusing is that when you type out dragon.change_color() it is already clear what self is (an instance called dragon). I would think that Python could grab that information from dragon.change_color() and pass it through on it's own, without having to require the programmer to pass self as an argument. It is sort of like asking someone to pass out pictures of themselves so that people know what they look like, when all the receiver of the picture needed to do was to look at the giver.

OK, I am ready to stretch my mind. So it seems from your example that when you use dragon.color = 'green' you are setting to a fixed variable, but when the dragon is getting it's color from the class, it is pointing to a color location in class that will change whenever someone changes the variable in that location.

Chris Freeman
Chris Freeman
Treehouse Moderator 68,468 Points

Very close.

When referencing dragon.color, python first looks in the instance attributes, then in the class attributes to get the value.

When setting dragon.color, python always sets the instance attribute. The class attribute is not affected. This happens whether the code uses dragon.color = 'green' or whether there is a method called such as dragon.change_color('green'). Since the self passed to the change_color() method refers to the instance and self is the dragon instance, self.color will change the instance attribute.

So when using dragon.color = 'green', the instance attribute is set to the string 'green'. More accurately, the instance attribute is set to a pointer to an object that is a string 'green'. Everything is an object and all assignments are actually pointers to other objects. You can use id(some_object) to see the "id" of the object.

Going deeper still.... Let's look at the object IDs as the colors are changed. Ignore this if it "to deep".

In [187]: Monster.color  #get class color
Out[187]: 'blue'

In [188]: id(Monster.color) # id class color
Out[188]: 140054661784104

In [189]: dragon.color # get instance color
Out[189]: 'cyan'

In [190]: id(dragon.color) # id instance color
Out[190]: 140054662210032

In [191]: id('blue') # id string "blue"
Out[191]: 140054661784104

In [192]: id('cyan')  # id string "cyan"
Out[192]: 140054662210032

In [193]: del dragon.color # delete instance color attribute 

In [194]: dragon.color # get instance color does not exist, python uses class color
Out[194]: 'blue'

In [195]: id(dragon.color) # id instance color which is now class color
Out[195]: 140054661784104

In [196]: Monster.color = 'red' # change class color

In [197]: id(Monster.color) # id new class color
Out[197]: 140054662212832

In [198]: id('red') # id string 'red'
Out[198]: 140054662212832

In [199]: id(dragon.color) # id instance color attribute
Out[199]: 140054662212832

In [200]: dragon.color = 'blue' # set instance attribute

In [201]: id(dragon.color) # id new instance color attribute
Out[201]: 140054661784104

In [210]: id('black') # id some other string
Out[210]: 140054661568584

In [211]: id('black') # id same string
Out[211]: 140054661568360

In [212]: id('black') # id same string
Out[212]: 140054661568640

Whoa! Why is the id for "black" changing? Since this string is not referenced (by a pointer created during some previous assignment), that is, its "reference count" is zero, the string object is tossed and its memory space is recovered during garbage collection. At the next id('black'), a new string is created at some other location. If an object attribute is set to 'black' then the string created would persist and all others needing a string 'black' would reference the same memory location.

Wow, cool, I actually got this! Thanks! Everything is an object, every argument is a pointer. The pointing is like a family tree, with the top of the tree being a location number (where that family is located) and then with other things descending but with arrows pointing back to the top (the location). If an object does not settle down with a family, then it moves around.