pythonclassinheritance

Python try/catch in superclass for error handling, logic handling / error raised in subclass method


I can't seem to figure this out and it seems like something I should be able to do but I'm dumb and stupid so help me out internet.

I want to have superclass which requires an implementation of a method by it's inheritors, but ultimately has generic error handling which is to log the error and raise it. I prefer this method as I have a bunch of subclasses which use this object so updating the parent class is much less code changes and also just seems cleaner versus adding try/catch to every flavor of childClass I have

e.g.

class Super(object):
    logger = logging.GetLogger(__name__)

    def my_method(some_value):
        try:
            raise RuntimeError("my_method must be implemented")
        except Exception as e:
            logger.error("error raised: %s" % e)
            raise e

class childClass(Super):
    def my_method(some_value):
        # do some stuff, maybe an error gets raised         

I've implemented something like the above but I'm not seeing a log message being created


Solution

  • childClass isn't extending Super so much as providing its implementation. If you choose to use inheritance, do as juanpa.arrivillaga suggested, and override a private method that does the real work of my_method.

    class Super:
        logger = logging.GetLogger(__name__)
    
        def my_method(self, some_value):
            try:
                self._my_method(some_value)
            except Exception as e:
                logger.error("error raised: %s" % e)
                raise e
    
        def _my_method(self, some_value):
            raise NotImplementedError("_my_method must be implemented")
    
    
    class childClass(Super):
        def _my_method(self, some_value):
            ...
    

    Or, if Super only provides a logging context for arbitrary code, and have it be a context manager instead of using inheritance.

    class LoggingContext:
        logger = logging.GetLogger(__name__)
    
        def __enter__(self):
            pass
    
        def __exit__(self, exc=None, *args):
            if exc is not None:
                self.logger.error("error raised: %s", exc)
    
    
    class Child:
        def my_method(self, some_value):
            ...
    
    
    c = Child()
    
    with LoggingContext():
        c.my_method(foo)
            
    

    The with statement "catches" any exception raised by Child.my_method and passes it to __exit__, which will log it and, by not returning True, have the with statement automatically reraise the error.