1

Suppose I have the following code:

class Classy:
    def other(self):
        print("other")

    def method(self):
        print("method")
        self.other()


obj = Classy()
obj.method()

The output:

method
other

So I invoke another object/class method from inside the class. I invoke the other method within the 'method' method.

Now if I run the following code:

class Classy:
    def other(self):
        print("other")

    def method(self):
        print("method")
        Classy.other(self)


obj = Classy()
obj.method()

The output is the same. Now my question is: What is the difference between these two?

I am not sure if it is just a different style of calling - so it is basically the same - or if there is a difference in the logic. If yes, I would be interested in an example where the difference matters.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Leona
  • 19
  • 2
  • What is `self` is an instance of a class that _inherits_ from `Classy`, and _overrides_ `other`? – jonrsharpe Oct 20 '21 at 16:33
  • 1
    Does this answer your question? [What is the purpose of the word 'self'?](https://stackoverflow.com/questions/2709821/what-is-the-purpose-of-the-word-self) – ddejohn Oct 20 '21 at 16:34
  • 1
    The code: `Classy.other(self)` is what python turns: `self.other()` into. It is more conventional to use the latter. – quamrana Oct 20 '21 at 16:37
  • 1
    @quamrana it is **not** just a matter of convention, in any non-trivial case the _behaviour_ can be different. – jonrsharpe Oct 20 '21 at 16:42

1 Answers1

0

Let's set it up so we can run them side by side:

class Classy:
    def other(self):
        print("Classy.other")
    def method(self):
        print("Classy.method")
        self.other()

class NotClassy:
    def other(self):
        print("NotClassy.other")
    def method(self):
        print("NotClassy.method")
        NotClassy.other(self)

So far, so good:

>>> Classy().method()
Classy.method
Classy.other
>>> NotClassy().method()
NotClassy.method
NotClassy.other

But what if inheritance gets involved, as it so often does in ? Let's define two subclasses that inherit method but override other:

class ClassyToo(Classy):
    def other(self):
        print("ClassyToo.other")

class NotClassyToo(NotClassy):
    def other(self):
        print("NotClassyToo.other")

Then things get a bit problematic; although the subclasses have almost identical implementation, and the parent classes seemed to behave exactly the same, the outputs here are different:

>>> ClassyToo().method()
Classy.method
ClassyToo.other
>>> NotClassyToo().method()
NotClassy.method
NotClassy.other  # what about NotClassyToo.other??

By calling NotClassy.other directly, rather than invoking the method on self, we've bypassed the overridden implementation in NotClassyToo. self might not always be an instance of the class the method is defined in, which is also why you see super getting used - your classes should cooperate in inheritance to ensure the right behaviour.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437