To understand this you will need to understand how self works. You can learn more here:
Understanding self in python
In a nutshell, self refers to the calling object. Invoking self.variable
refers to the variable associated with the calling object. Python is smart enough to create one if it doesn't exist.
Calling self.variable
inside a class is the same as calling object.variable
with your object reference
Consider the following example to prove this:
class Example:
def print_x(self):
print(self.x)
obj = Example()
obj.x = 5; # Create a new attribute of the object and assign it a value 5
print(obj.x) # Outputs 5
obj.print_x() # Outputs 5
In your example, I've added a couple of print statements to help you understand the state of the program during the execution:
class Example:
def __init__(self, name):
print(dir(self)) # Printing object contents before initializing name
self.name = name # New attribute 'name' created
print(dir(self)) # Printing object contents after initializing name
def foo(self):
print("Before foo, self.name = "+ self.name)
self.name = 'John'
print("After foo, self.name = "+ self.name)
bar = Example('Jake')
bar.foo()
print(bar.name)
The output of the above code is
['__doc__', '__init__', '__module__', 'foo']
['__doc__', '__init__', '__module__', 'foo', 'name']
Before foo, self.name = Jake
After foo, self.name = John
John
I will walk you through this code. When we first create bar, the __init__()
method is called. Here we print the contents of the object using dir(self)
. The output ['__doc__', '__init__', '__module__', 'foo']
indicates that the object has only one member, the 'foo' method.
Now we create a new attribute called 'name' and assign it the value 'Jake'. Thus the object now has another member, the 'name' attribute as seen by the output of the next dir(self) ['__doc__', '__init__', '__module__', 'foo', 'name']
Now we call the foo method and print the value before and after the method. Before the name
is changed in foo, the value of name
associated with the object is "Jake". However, after the name
is changed, the value of self.name
is "John". This is indicated by
Before foo, self.name = Jake
After foo, self.name = John`
We next verify that the change made by changing self.name
has indeed changed the value of name
in bar
by printing bar.name
which gives us the expected output, John
Now coming back to your question, self.name
is not an ordinary variable inside some method that is lost when we are out of scope. self
can be used essentially anywhere inside the class to refer to the calling object (bar in this case). It is used to manipulate this calling object. Now since bar
is within the scope, we are able to print its name
attribute.
In normal functions any variables are forgotten but in methods it
seems data is actually appended to the object itself
self
manipulates the attributes in the object and is not limited to the scope of the method.