3

I have a class.

class IncorrectOfferDetailsOfferException(Exception):
    def __init__(self, offer):
        self.offerName = offer[0]
        self.offerType = offer[1]
        self.message = "Offer \"" + self.offerName + "\" could not be completed. It appears to be of type \"" + self.offerType + "\", but this may be what is wrong and causing the exception."
        super(IncorrectOfferDetailsOfferException, self).__init__(self.message)

I want to write a more general class to expand it.

class BadOfferException(Exception):
    def __init__(self, offer):
        self.offerName = offer[0]
        self.offerType = offer[1]
        self.message = "Offer \"" + self.offerName + "\" caused a problem."

How can I relate those two together to remove the redundant code and override the more general message text with the more specific one? You know, class inheritance. I'm having a lot of trouble understanding how to use super the right way to do this.

2
  • 1
    First, for inheritance, the key question isn't how to share code, it's whether one is a subtype of the other. If you do except BadOfferException:, should that catch an IncorrectOfferDetailsOfferException? If so, then make IncorrectOfferDetailsOfferException a subclass of BadOfferException. If not, there are other ways to share code—a mixin class, a class decorator, a helper function… So, decide that first, and then we can help you with the next step. Commented Mar 22, 2018 at 4:34
  • @abarnert IncorrectOfferDetailsOfferException should be a subclass of BadOfferException. I don't understand how to do that and use the former to summon a specialized version of the latter. Commented Mar 22, 2018 at 4:47

2 Answers 2

2

How about a method that is overriden by the sub-type:

class BadOfferException(Exception):
    def __init__(self, offer):
        self.offerName = offer[0]
        self.offerType = offer[1]
        self.message = self._construct_message()
        super(BadOfferException, self).__init__(self.message)

    def _construct_message(self):
        return 'Offer "{}" caused a problem'.format(self.offerName)


class IncorrectOfferDetailsOfferException(BadOfferException):
    def _construct_message(self):
        return 'Offer "{}" could not be completed. It appears to be of type "{}", but this may be what is wrong and causing the exception.'.format(self.offerName, self.offerType)

Then when you raise IncorrectOfferDetailsOfferException it just "works"

Sign up to request clarification or add additional context in comments.

1 Comment

I love this. Seems clever and really does get the job done. Thank you. I understand this.
2

First, the way you make a subclass is through the base class list at the top:

class BadOfferException(Exception):
    # etc.

class IncorrectOfferDetailsOfferException(BadOfferException):
    # etc.

I just replaced Exception with BadOfferException. (We don't need both, because BadOfferException is already a subclass of Exception) And you have to declare the superclass first, and the subclass afterward, so I switched the order.


Now, you'll want to make the implementation of the superclass to be a little more generic, so the subclass can override only the part it cares about. The only thing that's different is the message, right? So allow that to be passed in:

class BadOfferException(Exception):
    def __init__(self, offer, message=None):
        self.offerName = offer[0]
        self.offerType = offer[1]
        if message is None:
            message = "Offer \"" + self.offerName + "\" caused a problem."
        self.message = message

And now, that's all you have to pass via super. That means we can't use offerName and offerType, since they haven't been defined yet, but that isn't a problem here:

class IncorrectOfferDetailsOfferException(BadOfferException):
    def __init__(self, offer):
        message = "Offer \"" + offer[0] + "\" could not be completed. It appears to be of type \"" + offer[1] + "\", but this may be what is wrong and causing the exception."
        super(IncorrectOfferDetailsOfferException, self).__init__(offer, message)

That's all you need to do.


But while we're at it, you might want to make BadOfferException into a nicer subclass of Exception. People expect to be able to see the args on an Exception instance—it's not mandatory; you can leave it off and it'll just be an empty tuple, but it is nice. You can do that by calling super(BadOfferException, self).__init__(offer).

2 Comments

This is a clean solution.
@SmallBlueGarbageCollector I think salparadise's is cleaner, and more powerful, for many use cases. This is the simplest solution, but it's not necessarily the best.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.