self

When you see classes defined in Python you'll see the variable self used quite a bit.

What is self? And how does it work?

Other languages use this. In Python we use self. We're egocentric in Python. We don't talk about the object as different from us, we are the object.

Every method needs self

Let's say we have a class that looks like this:

class Thing:
    def __init__(self, color, value):
        self.color = color
        self.value = value
        self.original_color = color
        self.original_value = value
    def reset(self):
        self.color = self.original_color
        self.value = self.original_value
    def paint_it_black(self):
        self.color = "black"
    def __repr__(self):
        return f"Thing({self.color!r}, {self.value!r})"

Note that every method accepts an argument called self as its first argument.

That self represents the instances of our Thing class. Each Thing object will have the __init__ called on it to initialize the object and the Thing object will be passed in as the first argument to __init__.

In Python you can add or update attributes on an object at any time (by default at least) so we can assign attributes on this self object (which points to our class instance) wherever we'd like.

Here's an example of this class being used:

>>> door = Thing("red", 4)
>>> door
Thing('red', 4)
>>> door.paint_it_black()
>>> door
Thing('black', 4)
>>> door.value = 0
>>> door
Thing('black', 0)
>>> door.reset()
>>> door
Thing('red', 4)

The variable name self isn't special

Note that if you change self to this everywhere:

class Thing:
    def __init__(this, color, value):
        this.color = color
        this.value = value
        this.original_color = color
        this.original_value = value
    def reset(this):
        this.color = this.original_color
        this.value = this.original_value
    def paint_it_black(this):
        this.color = "black"
    def __repr__(this):
        return f"Thing({this.color!r}, {this.value!r})"

This class will still work just as it did before.

>>> door = Thing("red", 4)
>>> door
Thing('red', 4)
>>> door.paint_it_black()
>>> door
Thing('black', 4)

The name self isn't special and it's not a keyword.

The first argument to our each method will be the class instance: what we actually call that argument is up to us though.

You shouldn't actually use the variable this because you'll confuse other Python programmers: always use self. The variable self is just a convention, but it's a very strong convention.

You can't go without self

If you try to remove the name self from any method, that method won't work anymore. If we remove self from our __repr__ method:

    def __repr__():
        return f"Thing({self.color!r}, {self.value!r})"

Our string representation will break:

>>> door = Thing("red", 4)
>>> door
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __repr__() takes 0 positional arguments but 1 was given

Python is saying that __repr__ takes 0 positional arguments but 1 was given. The one argument was self.

If we try to remove self everywhere, we'll get an error in all our methods:

class Thing:
    def __init__(color, value):
        color = color
        value = value
        original_color = color
        original_value = value
    def reset():
        color = original_color
        value = original_value
    def paint_it_black():
        color = "black"
    def __repr__():
        return f"Thing({color!r}, {value!r})"

We can't even make a new instance because __init__ is broken now:

>>> Thing("red", 4)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() takes 2 positional arguments but 3 were given

Our method expected 2 arguments (color and value) but Python gave it self as the first argument, in addition to color and value.

Note that it is possible to modify our methods to not require self or to send the object type into our method instead of the class instance, but we need to use decorators or other techniques for modifying our class methods.

self is our instance

If we make a what_am_i method on our Thing class:

    def what_am_i(self):
        return id(self)

You'll see that the id of the door variable which (points to our Thing object) is the same as the id of self when we call door.what_am_i():

>>> door = Thing("red", 4)
>>> door.what_am_i()
140311244921768
>>> id(door)
140311244921768

Anything you can do with self you could do with that door object because they're the same object.

There are some exceptions to this rule (name mangling is one) but they're rare.

implicitly passed by the function caller, explicitly passed to the function author

When we made an instance of our class:

>>> door = Thing("red", 4)

And then called a method on this instance:

door.paint_it_black()

Python translated this to:

```pycon
>>> Thing.paint_it_black(door)

Whenever you lookup a method on a class, Python will return a bound method instead:

>>> door.paint_it_black
<bound method Thing.paint_it_black of Thing('red', 4)>
>>> Thing.paint_it_black
<function Thing.paint_it_black at 0x7f9cc1e92f28>

So these two lines are the same:

```pycon
>>> Thing.paint_it_black(door)
>>> door.paint_it_black()

This principle applies to all classes.

Given a string and a list:

>>> greeting = "hello"
>>> numbers = [1, 2, 3]

Calling a method on either of these objects is the same as calling the method on the class and passing the class instance in.

So these two lines are equivalent:

>>> greeting.upper()
'HELLO'
>>> str.upper(greeting)
'HELLO'

As are these two:

>>> numbers.append(4)
>>> list.append(numbers, 4)

You shouldn't call MyClass.my_method(my_instance). That's Python's job. The way we as Python programmers call methods is my_instance.my_method(). But under the hood Python translates that to type(my_instance).my_method(my_instance).

Recap

Unlike other languages which have a magical context-dependent this keyword, Python has a self argument which must be accepted as the first argument in all class methods (methods are functions that live on classes).

Facts about self that are commonly overlooked include:

  • The self argument points to the class instance
  • The variable name self is just a convention, but it's a very strong one
  • Every method needs to accept self as its first argument (Python's going to pass the instance in whether you want it to or not)
  • Whenever we call a method on an instance, Python looks on the class for our function and then passes the instance and all other arguments in