1

I'm currently working on a pricing tool which has several level of calculations.

For instance, I have an object Quote which itself has one or several QuoteItem attached.

I think there should be class inheritance but I don't want to initialize my Quote every time I create a QuoteItem since all QuoteItems share exactly the same Quote with the same characteristics.

Is that class inheritance with super class ? Or should it be 2 independent class ? I can't find any documentation nor resource dealing about my scenario which I think to be very common.

I have a list of quoteitems which are attached to one quote, I would like first to create the quote and then the quoteitems. If I start from the quoteitems I feel that it will create everytime a quote which isn't at all the expected behaviour since there should be only 1 quote for all my quoteitems.

Is that a correct approach ?

class Quote():
    def __init__():
        # this will set parameter global to the quote
        print('Quote created')


class QuoteItem(Quote):
    def __init__():
        # this will set specific details for all quote items attached to one specific quote
        print ('QuoteItem created')

Or should those 2 classes be totally independent ?

Any use case or documentation about such scenario is welcome. The parent/subclass document I found deals only with object which are very similar. In my example they are not the same, they are children, i.e quoteitems can't exist without quote.

Thanks

yeye
  • 503
  • 4
  • 19

2 Answers2

3

When thinking of inheritance, you're using an "is-a" relationship.

class Vehicle(object):  # a Vehicle IS AN object
    pass
class Car(Vehicle):     # a Car     IS A  Vehicle
    pass
class Sedan(Car):       # A Sedan   IS A  Car
    pass

What you're probably looking for in a quote and its items is a "has-a" relationship.

class Tire(object):     # a Tire IS AN object, but...
    pass

class Vehicle(object):
    def __init__(self, num_tires=4):
        self.tires = [Tire() for _ in num_tires]
                        # a Vehicle HAS A Tire  (or in this case 4 tires)

To extend the metaphor for your specific use case:

class QuoteItem(object):
    def __init__(self, modelnumber, quantity, totalprice):
        self.modelnumber = modelnumber
        self.quantity = quantity
        self.totalprice = totalprice
        # I'm guessing at what you'd want here


class Quote(object):
    _last_quote_number = 0

    @property
    @classmethod
    def next_quote_number(cls) -> int:
        cls._last_quote_number += 1
        return cls._last_quote_number

    def __init__(self, customerid):
        self.number = self.next_quote_number
        self.customerid = customerid
        self.items = []

    def add_item(self, modelnumber, quantity, totalprice) -> None:
        item = QuoteItem(modelnumber, quantity, totalprice)
        self.items.append(item)

Adam Smith
  • 52,157
  • 12
  • 73
  • 112
  • That is very clear thank you ! This answers my point as to how I create subitems. I call a method from the Quote class which will call the QuoteItem class. I wasn't sure this was best practice but that's fine now. If there are many quoteitems to create at once, what should I do ? should I send a list and have the method in Quote converting the list into a for loop ? or should the deagregation made in the QuoteItem list ? or should the for loop made when calling the add_item method ? – yeye Jun 09 '19 at 18:02
  • What I've used in the past is to make another `classmethod` that's essentially an alternate constructor that is smart enough to do something like parse a list (or read from a csv or etc). Then that method would do `quoteitem = cls(customerid); for modelnumber, quantity, totalprice in parsed_item_details: quoteitem.add_item(modelnumber, quantity, totalprice); return quoteitem`. Then you can create a `Quote` from your list of items with `quote = Quote.yournewclassmethod(customerid, list_of_items)` – Adam Smith Jun 09 '19 at 18:04
2

Using inheritance here isn't the best approach. Just let Quote have a container (for example a list) with all of its QuoteItems.

When using inheritance like this, you are saying a QuoteItem is a special sort of Quote which it isn't. QuoteItem is a part of Quote.

DSC
  • 1,153
  • 7
  • 21
  • OK that is clear, thank you ! And in terms of conception, how do I call the constructor in my QuoteItem class ? Should I have another main class which initializes first the Quote, then the QuoteItem ? I'm thinking of putting a method in the Quote class which will initialize all the quote items and loop through them, does that seem correct ? Noob question, what is a container ? – yeye Jun 09 '19 at 17:46
  • @yeye That depends on what you want to achieve. You probably want `Quote` to create the `QuoteItem` – DSC Jun 09 '19 at 17:49
  • @yeye Containers are any object that holds an arbitrary number of other objects. See https://stackoverflow.com/questions/11575925/what-exactly-are-containers-in-python-and-what-are-all-the-python-container – DSC Jun 09 '19 at 17:50