Why calling an inexistent method

Hi forum,

I see the following code on an post which posted two years ago. It stated that the code is from the book “Python GUI Programming with Tkinter”, p.76. I don’t have the book.

I wonder, the Line 11 call super().display() in class LoggerMixin. The class does not inherit any other class except the common object class. How can it use super() and eventually super().display() leads to Displayer.display()?

And the LoggerMixin class calling an inexistent makes the Mixin concept?

So many new in Python for me!

Thanks

class Displayer:
    def display(self, message):   # Line 2
        print(message) 

class LoggerMixin:
    def log(self, message, filename='logfile.txt'):
        with open(filename, 'a') as fh:
            fh.write(message)

    def display(self, message):
        super().display(message)  # Line 11, calls Line 2
        self.log(message)

class MySubClass(LoggerMixin, Displayer):
    def log(self, message):
        super().log(message, filename='subclasslog.txt')

subclass = MySubClass()
subclass.display('This string will be shown and logged in subclasslog.txt')

This is the MRO:

print(MySubClass.__mro__)

(<class '__main__.MySubClass'>, <class '__main__.LoggerMixin'>, <class '__main__.Displayer'>, <class 'object'>)

I see the following code on an post which posted two years ago. It
stated that the code is from the book “Python GUI Programming with
Tkinter”, p.76. I don’t have the book.

Me either.

I wonder, the Line 11 call super().display() in class LoggerMixin. The class does not inherit any other class except the common object class. How can it use super() and eventually super().display() leads to Displayer.display()?

And the LoggerMixin class calling an inexistent makes the Mixin concept?
[…]

This works because LoggerMixin is a mixin class. Such a class pretty
much exists to provide methods but doesn’t work on its own, only in
combination with another class.

So what you’ve got is this:

class Displayer:
    def display(self, message):   # Line 2
        print(message)

A class which just defines a display() method. I’d call this a mixin
also (only methods, no __init__, doesn’t do much on its own).

class LoggerMixin:
    def log(self, message, filename='logfile.txt'):
        with open(filename, 'a') as fh:
            fh.write(message)

    def display(self, message):
        super().display(message)  # Line 11, calls Line 2
        self.log(message)

This is the mixin which calls a display method from its superclass.

class MySubClass(LoggerMixin, Displayer):
    def log(self, message):
        super().log(message, filename='subclasslog.txt')

and here is the concrete, complete class which uses both of these. An
instance of this class can call super() meaningfully. super()
returns a proxy, and in the case of LoggerMixin.display the proxy is a
one which looks for display in the classes from the MRO which come
after LoggerMixin (because the method calling it came from
LoggerMethod).

Notice that MySubClass(LoggerMixin,Displayer) has LoggerMixin ahead
of Displayer, so that LoggerMixin.display is found before
Displayer.display, and LoggerMixin.display can use super() to find
the next display in the MRO after it.

By contrast, LoggerMixin.display calls self.log(message), which
finds MySubClass.log, which in turn calls super().log(...) which
inda the log method in the MRO after MySubClass, thus
LoggerMixin.log.

Cheers,
Cameron Simpson cs@cskk.id.au

1 Like

In Python, mixin classes are just classes. They aren’t any different from normal classes, except that by convention mixins are used to provide extra methods, they aren’t intended to be used alone.

When you use super().method it resolves the method by looking at the entire MRO of the calling instance, not just the class where the call occurs.

You have three classes:

  • class Displayer # contains display() method

  • class LoggerMixin # calls super()

  • class MySubClass(LoggerMixin, Displayer)

You are probably thinking something like this:

When LoginMixin calls super(), it looks at the superclass of LoginMixin, which is object, but that doesn’t have the display() method. But how does it know to find the display() method in Displayer?

What actually happens is this. You have an instance of MySubClass, which you call “subclass”, but that’s a horrible name. Your variable “subclass” is not a class, it is an instance.

# This is a better name.
instance = MySubClass()

Remember that in Python, classes are values too. We can do things like this:

class MyString(str): pass
class YourString(str): pass

subclass = MyString if name == "me" else YourString

Anyway, back on topic: you have an instance which calls a method:

instance.display(message)

Python looks up the MRO:

  • MySubClass has no display() method;

  • search the first parent: LoginMixer has a display() method, so call that.

That method, LoginMixer.display(), calls super().display(), then logs the message. super() knows three things:

  • that the object being called (instance, what you called subclass) is a MySubClass instance;

  • that it is being called from the LoginMixer class;

  • and that the next class in the caller’s MRO (instance) is Displayer;

so it knows to look for a display() method in Displayer, not object.

See here:

More documentation here:

https://docs.python.org/3/library/functions.html#super

and how the MRO is computed:

1 Like

Hi Steven,

class super([type[, object-or-type]])
Return a proxy object that delegates method calls to a parent or sibling class of type

Is the last of a typo, should it be or?

This works because LoggerMixin.display() method is calling a sibling method Displayer.display(), right?

Thanks for the reference links.

Hi Steven,

The self.log() call inside method LoggerMixin.display, triggers MySubClass.log(). Why the subclass method gets called?

EDIT:
I did some test.
The self. can refer to the class used to create the instance. The instance issued the call to the method.
The super(). can only refer to sibling or parent method.