es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo combinas objetos personalizados en Python para crear una colección que mantenga la interfaz de los objetos subyacentes?

Tengo un grupo de objetos en Python que me gustaría sumar sin perder acceso a la funcionalidad implementada en los objetos.

Para ilustrar el punto, considera esta clase:

class PlaneTicket:
    def __init__(self, origin:str, destination:str):
        ...
def price(self, pricingDate:date)->float:
    '''Returns the best price available on a given date'''
    ...

En mi aplicación, necesito poder sumar estos objetos. Puedes pensarlo como tener que crear un viaje que requiere dos boletos de avión.

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

journey = flight1 + flight2

Ahora, lo interesante es que también quiero poder usar los métodos en los objetos subyacentes. Por ejemplo:

journey.price('2021-06-19')

Debería ser igual a la suma de (flight.price(‘2021-06-19’) for flight in journey.flights)

Entonces, podríamos implementar una clase Journey y hacer que la suma de objetos PlaneTicket sea un objeto Journey, y también implementar un .price en la clase Journey.

Sin embargo, puede que esté perdiendo una mejor solución ya que estoy seguro de que este es un problema común. Además, necesitaría diferentes implementaciones de la clase Journey si estoy sumando, promediando o multiplicando los objetos PlaneTicket.

Supongo que la formulación general sería:

  1. Tengo una colección de objetos que implementan un método foo().
  2. Quiero agregar estos objetos (por ejemplo, sumándolos).
  3. Quiero poder llamar a foo en la agregación y tener los valores de retorno de los objetos constituyentes agregados.
Tags:  , ,

Answer

  1. Avatar for davy.ai

    Una solución a este problema es utilizar el método __add__ de la clase PlaneTicket para devolver una nueva clase que agregue los precios de los dos billetes. Esta nueva clase también puede almacenar referencias a los objetos PlaneTicket subyacentes, lo que nos permite llamar a sus métodos price en la clase Journey.

    Aquí hay una implementación de ejemplo:

    class Journey:
        def __init__(self, *tickets):
            self.tickets = tickets
    
        def __add__(self, other):
            tickets = self.tickets + other.tickets
            total_price = sum(ticket.price(date) for ticket in tickets)
            return JourneyTicket(tickets, total_price)
    
        def price(self, date):
            return sum(ticket.price(date) for ticket in self.tickets)
    
    
    class JourneyTicket:
        def __init__(self, tickets, total_price):
            self.tickets = tickets
            self.total_price = total_price
    
        def price(self, date):
            return self.total_price
    
    
    class PlaneTicket:
        def __init__(self, origin:str, destination:str):
            ...
    
        def price(self, pricingDate:date) -> float:
            '''Devuelve el mejor precio disponible en una fecha dada'''
            ...
    
        def __add__(self, other):
            return Journey(self, other)
    

    Con esta implementación, ahora podemos crear un objeto Journey sumando objetos PlaneTicket:

    vuelo1 = PlaneTicket('londres', 'nueva-york')
    vuelo2 = PlaneTicket('nueva-york', 'parís')
    
    viaje = vuelo1 + vuelo2
    

    Y podemos llamar al método price en el objeto viaje para obtener el precio total:

    viaje.price('2021-06-19')
    

    También podemos llamar al método price en los objetos PlaneTicket subyacentes accediendo al atributo tickets del objeto Journey:

    for billete in viaje.tickets:
        billete.price('2021-06-19')
    

    Esta implementación nos permite agregar fácilmente objetos PlaneTicket y seguir accediendo a su funcionalidad subyacente. También podemos crear diferentes clases para diferentes tipos de agregaciones (por ejemplo, JourneyAverage), si es necesario.

Comments are closed.