Chapters
Python114 chapters

Classes and objectsChapter 63 of 114

self

What self actually is, and why you have to write it.

self is the object

When you call rex.learn("sit"), Python turns it into Dog.learn(rex, "sit"). The first parameter receives the object the method was called on:

Python
class Dog:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} says woof"

rex = Dog("Rex")
print(rex.speak())
print(Dog.speak(rex))

Output

Rex says woof
Rex says woof

Both lines do the same thing. The dotted form is sugar for the second.

It is a name, not a keyword

self is a convention, not a rule. This works:

Python
class Dog:
    def __init__(banana, name):
        banana.name = name

    def speak(banana):
        return f"{banana.name} says woof"

print(Dog("Rex").speak())

Output

Rex says woof

Never do this. Every Python reader expects self, and using anything else costs them a double-take for no gain.

Forgetting it

Leave self out of the definition and the call fails, because Python still passes the object:

Python
class Dog:
    def speak():
        return "woof"

try:
    Dog().speak()
except TypeError as problem:
    print("TypeError:", problem)

Output

TypeError: Dog.speak() takes 0 positional arguments but 1 was given

The error message is the clue: one argument was given, invisibly.

Attributes need self too

Inside a method, a bare name is a local variable. To reach the object's data you have to go through self:

Python
class Counter:
    def __init__(self):
        self.value = 0

    def broken(self):
        value = 99          # a local, thrown away

    def working(self):
        self.value = 99     # the object's attribute

c = Counter()
c.broken()
print(c.value)
c.working()
print(c.value)

Output

0
99

This is why Python makes you write it. There is no ambiguity about whether a name is local or an attribute, because the two look different.

self in one method, visible in another

Anything you attach in __init__ is available everywhere else on the object:

Python
class Dog:
    def __init__(self, name):
        self.name = name
        self.tricks = []

    def learn(self, trick):
        self.tricks.append(trick)

    def count(self):
        return len(self.tricks)

rex = Dog("Rex")
rex.learn("sit")
print(rex.count())

Output

1

Bound methods

rex.speak without brackets is a bound method: the function with rex already attached. You can store and pass it around:

Python
class Dog:
    def __init__(self, name):
        self.name = name

    def speak(self):
        return f"{self.name} woofs"

rex = Dog("Rex")
talk = rex.speak
print(talk())
print([d.speak() for d in [Dog("A"), Dog("B")]])

Output

Rex woofs
['A woofs', 'B woofs']

self is not special inside

It is an ordinary parameter holding an ordinary object, so you can compare it, return it, or pass it on:

Python
class Dog:
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def older_than(self, other):
        return self.age > other.age

rex = Dog("Rex", 5)
fido = Dog("Fido", 3)
print(rex.older_than(fido))

Output

True

Test yourself

2 questions

What is self?

Show the answer

The object the method was called on — rex.speak() is sugar for Dog.speak(rex). The name is only a convention.

Inside a method, what does a bare 'value = 99' do?

Show the answer

Creates a local variable that is thrown away — Attributes need self. That explicitness is exactly why Python makes you write it.

Next chapter

Inheritance

Build a class on top of another, and override what differs.