1

I installed a library that has a custom logging handler in the following form:

class LibraryCustomHandler(logging.handlers.RotatingFileHandler):
    # Other LibraryCustomHandler methods

    def format(self, record):
        message = super(LibraryCustomHandler, self).format(record)
        return library_function(record, message)

    # Other LibraryCustomHandler methods

Note: library_function() is a function and not a method of LibraryCustomHandler.

I want a different library_function(). So, in this case I normally create a subclass of the class I want to change:

class MyCustomHandler(path.to.LibraryCustomHandler):
    def format(self, record):
        message = super(MyCustomHandler, self).format(record)
        return my_function(record, message)

But here the super statement will also call the library_function() from LibraryCustomHandler.format(), which I don't want.

Right now, my working solution is:

class MyCustomHandler(path.to.LibraryCustomHandler):
    def format(self, record):
        message = logging.handlers.RotatingFileHandler.format(self, record)
        return my_function(record, message)

I was wondering if there is a more pythonic or correct way of calling the super of super basically.

cprakashagr
  • 751
  • 11
  • 28
Paco H.
  • 2,034
  • 7
  • 18
  • @moooeeeep I think the answer there is what I give as "My working solution" in my answer. – Paco H. May 31 '17 at 09:16
  • 2
    The conclusion one might draw from that: The solution you have right now is OK and you should have good reasons to introduce a change. Especially if it's to a more unintuitive but in this case equivalent approach. Is it more relevant that you want to call the base's base class method or that you want to call the method provided by this specific class? What if the hierarchy changes? – moooeeeep May 31 '17 at 10:52
  • After re-reading your question I thought _this_ should be the real question: is subclassing in this case the right way to replace that `library_function()` behavior, or is there a better way? – moooeeeep May 31 '17 at 10:59
  • Thank you for your comments @moooeeeep. As you said I didn't formulate my question clearly. My question really was how "_to call the base's base class method_". I think describing my scenario obscured the actual question, a code sample more simply related to the question would have been more appropiated. – Paco H. Jun 08 '17 at 10:08

1 Answers1

3

In this case, calling the RotatingFileHandler method is just fine. You have a straight inheritance model and don't have to worry about possible mixins being used next to LibraryCustomHandler.

That said, you can trivially 'skip' the LibraryCustomHandler method using super() too, by giving super() a different starting point.

The first argument to super() is used to set a starting point for searching in the MRO; normally you set this to the current class, and search starts after this point; for MyCustomHandler the next class in the MRO is LibraryCustomHandler, so that class is searched for a format attribute first. But you are free to set that first argument to LibraryCustomHandler instead:

class MyCustomHandler(path.to.LibraryCustomHandler):
    def format(self, record):
        # Explicitly skip LibraryCustomHandler
        message = super(path.to.LibraryCustomHandler, self).format(record)
        return my_function(record, message)

When you do this, you also cut out any format() implementations that might lie on the MRO between MyCustomHandler and LibraryCustomHandler.

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343