Explaining the 'self' variable to a beginner
Question:
I’m pretty much ignorant of OOP jargon and concepts. I know conceptually what an object is, and that objects have methods. I even understand that in python, classes are objects! That’s cool, I just don’t know what it means. It isn’t clicking with me.
I’m currently trying to understand a few detailed answers that I think will illuminate my understanding of python:
In the first answer, the author uses the following code as an example:
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
I don’t immediately grok what self
is pointing to. This is definitely a symptom of not understanding classes, which I will work on at some point. To clarify, in
>>> def func():
... for i in range(3):
... print i
I understand that i
points to an item in the list range(3)
which, since it is in a function, isn’t global. But what does self
“point to”?
Answers:
It may help you to think of the obj.method(arg1, arg2)
invocation syntax as purely syntactic sugar for calling method(obj, arg1, arg2)
(except that method
is looked up via obj
‘s type, and isn’t global).
If you view it that way, obj
is the first argument to the function, which traditionally is named self
in the parameter list. (You can, in fact, name it something else, and your code will work correctly, but other Python coders will frown at you.)
self
refers to an instance of the class.
self
refers to the current instance of Bank
. When you create a new Bank
, and call create_atm
on it, self
will be implicitly passed by python, and will refer to the bank you created.
I don’t immediately grok what self
is pointing to. This is definitely a symptom of not understanding classes, which I will work on at some point.
self
is an argument passed in to the function. In Python, this first argument is implicitly the object that the method was invoked on. In other words:
class Bar(object):
def someMethod(self):
return self.field
bar = Bar()
bar.someMethod()
Bar.someMethod(bar)
These last two lines have equivalent behavior. (Unless bar
refers to an object of a subclass of Bar
— then someMethod()
might refer to a different function object.)
Note that you can name the “special” first argument anything you want — self
is just a convention for methods.
I understand that i
points to an item in the list range(3)
which, since it is in a function, isn’t global. But what does self
“point to”?
The name self
does not exist in the context of that function. Attempting to use it would raise a NameError
.
Example transcript:
>>> class Bar(object):
... def someMethod(self):
... return self.field
...
>>> bar = Bar()
>>> bar.field = "foo"
>>> bar.someMethod()
'foo'
>>> Bar.someMethod(bar)
'foo'
>>> def fn(i):
... return self
...
>>> fn(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
NameError: global name 'self' is not defined
The reason “self” is there (by convention) is that when the Python runtime sees a call of the form Object.Method(Param1,Param2), it calls Method with parameters (Object,Param1,Param2). So if you call that first parameter “self”, everyone will know what you are talking about.
The reason you have to do this is the subject of another question.
As far as a metaclass, it’s something rarely used. You might want to look at:
http://python-history.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html, the original author and current Benevolent Dictator For Life of Python explains what this is, and how it came to be. He also has a nice article on some possible uses, but most people never directly use it at all.
I’ll try to clear up some confusion about classes and objects for you first. Lets look at this block of code:
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
The comment there is a bit deceptive. The above code does not “create” a bank. It defines what a bank is. A bank is something which has a property called crisis
, and a function create_atm
. That’s what the above code says.
Now let’s actually create a bank:
>>> x = Bank()
There, x
is now a bank. x
has a property crisis
and a function create_atm
. Calling x.create_atm();
in python is the same as calling Bank.create_atm(x);
, so now self
refers to x
. If you add another bank called y
, calling y.create_atm()
will know to look at y
‘s value of crisis, not x
‘s since in that function self
refers to y
.
self
is just a naming convention, but it is very good to stick with it. It’s still worth pointing out that the code above is equivalent to:
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(thisbank) :
... while not thisbank.crisis :
... yield "$100"
“self” is the instance object automatically passed to the class instance’s method when called, to identify the instance that called it. “self” is used to access other attributes or methods of the object from inside the method. (methods are basically just functions that belong to a class)
“self” does not need to be used when calling a method when you already have an available instance.
Accessing the “some_attribute” attribute from inside a method:
class MyClass(object):
some_attribute = "hello"
def some_method(self, some_string):
print self.some_attribute + " " + some_string
Accessing the “some_attribute” attribute from an existing instance:
>>> # create the instance
>>> inst = MyClass()
>>>
>>> # accessing the attribute
>>> inst.some_attribute
"hello"
>>>
>>> # calling the instance's method
>>> inst.some_method("world") # In addition to "world", inst is *automatically* passed here as the first argument to "some_method".
hello world
>>>
Here is a little code to demonstrate that self is the same as the instance:
>>> class MyClass(object):
>>> def whoami(self, inst):
>>> print self is inst
>>>
>>> local_instance = MyClass()
>>> local_instance.whoami(local_instance)
True
As mentioned by others, it’s named “self” by convention, but it could be named anything.
One Rubyist’s perspective (Ruby is my first programming language so I apologize for whatever oversimplified, potentially wrong abstractions I’m about to use)
as far as I can tell, the dot operator, for example:
os.path
is such that os
gets passed into path()
as its first variable “invisibly”
It is as if os.path
is REALLY this:
path(os)
If there were a daisy chain I’d imagine that this:
os.path.filename
Would be sort of like this in reality*:
filename(path(os))
Here comes the offensive part
So with the self variable all that’s doing is allowing the CLASS METHOD (from a rubyist perspective python ‘instance methods’ appear to be class methods…) to act as an instance method by getting an instance passed into it as its first variable (via the “sneaky” dot method above) which is called self
by convention. Were self not an instance
c = ClassName()
c.methodname
but the class itself:
ClassName.methodname
the class would get passed in rather than the instance.
OK, also important to remember is that the __init__
method is called “magic” by some. So don’t worry about what gets passed into generate a new instance. To be honest its probably nil
.
I’m pretty much ignorant of OOP jargon and concepts. I know conceptually what an object is, and that objects have methods. I even understand that in python, classes are objects! That’s cool, I just don’t know what it means. It isn’t clicking with me.
I’m currently trying to understand a few detailed answers that I think will illuminate my understanding of python:
In the first answer, the author uses the following code as an example:
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
I don’t immediately grok what self
is pointing to. This is definitely a symptom of not understanding classes, which I will work on at some point. To clarify, in
>>> def func():
... for i in range(3):
... print i
I understand that i
points to an item in the list range(3)
which, since it is in a function, isn’t global. But what does self
“point to”?
It may help you to think of the obj.method(arg1, arg2)
invocation syntax as purely syntactic sugar for calling method(obj, arg1, arg2)
(except that method
is looked up via obj
‘s type, and isn’t global).
If you view it that way, obj
is the first argument to the function, which traditionally is named self
in the parameter list. (You can, in fact, name it something else, and your code will work correctly, but other Python coders will frown at you.)
self
refers to an instance of the class.
self
refers to the current instance of Bank
. When you create a new Bank
, and call create_atm
on it, self
will be implicitly passed by python, and will refer to the bank you created.
I don’t immediately grok what
self
is pointing to. This is definitely a symptom of not understanding classes, which I will work on at some point.
self
is an argument passed in to the function. In Python, this first argument is implicitly the object that the method was invoked on. In other words:
class Bar(object):
def someMethod(self):
return self.field
bar = Bar()
bar.someMethod()
Bar.someMethod(bar)
These last two lines have equivalent behavior. (Unless bar
refers to an object of a subclass of Bar
— then someMethod()
might refer to a different function object.)
Note that you can name the “special” first argument anything you want — self
is just a convention for methods.
I understand that
i
points to an item in the listrange(3)
which, since it is in a function, isn’t global. But what doesself
“point to”?
The name self
does not exist in the context of that function. Attempting to use it would raise a NameError
.
Example transcript:
>>> class Bar(object):
... def someMethod(self):
... return self.field
...
>>> bar = Bar()
>>> bar.field = "foo"
>>> bar.someMethod()
'foo'
>>> Bar.someMethod(bar)
'foo'
>>> def fn(i):
... return self
...
>>> fn(0)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in fn
NameError: global name 'self' is not defined
The reason “self” is there (by convention) is that when the Python runtime sees a call of the form Object.Method(Param1,Param2), it calls Method with parameters (Object,Param1,Param2). So if you call that first parameter “self”, everyone will know what you are talking about.
The reason you have to do this is the subject of another question.
As far as a metaclass, it’s something rarely used. You might want to look at:
http://python-history.blogspot.com/2009/04/metaclasses-and-extension-classes-aka.html, the original author and current Benevolent Dictator For Life of Python explains what this is, and how it came to be. He also has a nice article on some possible uses, but most people never directly use it at all.
I’ll try to clear up some confusion about classes and objects for you first. Lets look at this block of code:
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(self) :
... while not self.crisis :
... yield "$100"
The comment there is a bit deceptive. The above code does not “create” a bank. It defines what a bank is. A bank is something which has a property called crisis
, and a function create_atm
. That’s what the above code says.
Now let’s actually create a bank:
>>> x = Bank()
There, x
is now a bank. x
has a property crisis
and a function create_atm
. Calling x.create_atm();
in python is the same as calling Bank.create_atm(x);
, so now self
refers to x
. If you add another bank called y
, calling y.create_atm()
will know to look at y
‘s value of crisis, not x
‘s since in that function self
refers to y
.
self
is just a naming convention, but it is very good to stick with it. It’s still worth pointing out that the code above is equivalent to:
>>> class Bank(): # let's create a bank, building ATMs
... crisis = False
... def create_atm(thisbank) :
... while not thisbank.crisis :
... yield "$100"
“self” is the instance object automatically passed to the class instance’s method when called, to identify the instance that called it. “self” is used to access other attributes or methods of the object from inside the method. (methods are basically just functions that belong to a class)
“self” does not need to be used when calling a method when you already have an available instance.
Accessing the “some_attribute” attribute from inside a method:
class MyClass(object):
some_attribute = "hello"
def some_method(self, some_string):
print self.some_attribute + " " + some_string
Accessing the “some_attribute” attribute from an existing instance:
>>> # create the instance
>>> inst = MyClass()
>>>
>>> # accessing the attribute
>>> inst.some_attribute
"hello"
>>>
>>> # calling the instance's method
>>> inst.some_method("world") # In addition to "world", inst is *automatically* passed here as the first argument to "some_method".
hello world
>>>
Here is a little code to demonstrate that self is the same as the instance:
>>> class MyClass(object):
>>> def whoami(self, inst):
>>> print self is inst
>>>
>>> local_instance = MyClass()
>>> local_instance.whoami(local_instance)
True
As mentioned by others, it’s named “self” by convention, but it could be named anything.
One Rubyist’s perspective (Ruby is my first programming language so I apologize for whatever oversimplified, potentially wrong abstractions I’m about to use)
as far as I can tell, the dot operator, for example:
os.path
is such that os
gets passed into path()
as its first variable “invisibly”
It is as if os.path
is REALLY this:
path(os)
If there were a daisy chain I’d imagine that this:
os.path.filename
Would be sort of like this in reality*:
filename(path(os))
Here comes the offensive part
So with the self variable all that’s doing is allowing the CLASS METHOD (from a rubyist perspective python ‘instance methods’ appear to be class methods…) to act as an instance method by getting an instance passed into it as its first variable (via the “sneaky” dot method above) which is called self
by convention. Were self not an instance
c = ClassName()
c.methodname
but the class itself:
ClassName.methodname
the class would get passed in rather than the instance.
OK, also important to remember is that the __init__
method is called “magic” by some. So don’t worry about what gets passed into generate a new instance. To be honest its probably nil
.