2

I have a group of objects in python I'd like to sum without losing access to the functionality implemented in the objects.

To illustrate the point, consider this class:

class PlaneTicket:
    def __init__(self, origin:str, destination:str):
        ...

    def price(self, pricingDate:date)->float:
        '''Returns the best price available on a given date'''
        ...

In my application I need to be able to sum these objects. You can think of it as having to create a journey that requires two plane tickets.

flight1 = PlaneTicket('london', 'new-york')
flight2 = PlaneTicket('new-york', 'paris')

journey = flight1 + flight2

Now, the interesting thing is, I also want to be able to use the methods in the underlying objects. Eg.

journey.price('2021-06-19') 
# Should equal sum(flight.price('2021-06-19') for flight in journey.flights)

So, I could implement a class Journey and make the sum of PlaneTicket objects a Journey object, and also then implement a .price on the Journey class.

However, I may be missing a better solution as I'm sure this is a common problem. Moreover, I'd need different implementations of the Journey class if I'm summing, averaging, or multiplying the PlaneTicket objects.

I suppose the general formulation would be:

  1. I have a collection of objects that implement a method foo()
  2. I want to aggregate these objects (eg. summing them)
  3. I want to be able to call foo on the aggregation and have the return values of the constituent objects aggregated.
MYK
  • 1,988
  • 7
  • 30
  • Does this answer your question? [python operator overloading \_\_radd\_\_ and \_\_add\_\_](https://stackoverflow.com/questions/51298551/python-operator-overloading-radd-and-add) – JonSG Jan 06 '22 at 15:42
  • Why do you think, you need different implementations of the `Journey` class? I can only think of multiplying by a scalar `flight1 * 2` which is the same as `flight1 + flight1`. Multiplying a flight by another flight wouldn't make sense. Not sure what averaging the plane tickets would mean. It sounds more like a function of the resulting `Journey` class to me. – Wups Jan 06 '22 at 20:11

1 Answers1

2

You could implement a custom __add__ method like my example below.

class PlaneTicket:
    def __init__(self, origin: str, destination: str, price: int):
        self.origin = origin
        self.destination = destination
        self.price = price

    def get_price(self):
        return self.price

    def __add__(self, other):
        assert self.destination == other.origin
        new_ticket = PlaneTicket(self.origin, other.destination, self.price + other.price)
        return new_ticket


flight1 = PlaneTicket("london", "new-york", 1000)
flight2 = PlaneTicket("new-york", "paris", 2000)

journey = flight1 + flight2
print(f"Flying from {journey.origin} to {journey.destination} costs {journey.get_price()}")

Output

Flying from london to paris costs 3000
S P Sharan
  • 1,101
  • 9
  • 18
  • To add to this since the OP mentioned it in their post, the tickets can be multiplied in a similar manner by implementing a custom `__mul__` method. – cazman Jan 06 '22 at 15:39
  • You should implement `__radd__` so that things like `sum()` will work – JonSG Jan 06 '22 at 15:41