Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pass request to different class based on condition Python

Tags:

python

I am designing an API which deals with different type of vehicles for example cars, buses and vans. There is an endpoint POST /vehicle which will take a defined body.

{
'registration': 'str',
'date_of_purchase': 'datetime str',
'vehicle_type': 'car'
...
}

The first thing that we do is load an object based on the vehicle_type.

if body[vehicle_type] == 'car':
   passed_in_vehicle = Car(body)
elif body['vehicle_type'] == 'bus':
   passed_in_vehicle = Bus(body)
...

Within the python program there are multiple classes including:

  • vehicles.py
  • cars.py
  • vans.py
  • buses.py

The API entry point goes to vehicles.py which does some logic and then depending on the input will route it to one of the other classes to do more specific logic.

Each class has the same set of base methods.

  • update_vehicle_specs
  • register_vehicle

At the moment in the bottom of vehicles.py I have

if is_instance(passed_in_vehicle, Car):
   carService = Cars()
   carService.register_vehicle(passed_in_vehicle)
elif is_instance(passed_in_vehicle, Van):
   vanService = Vans()
   vanService.register_vehicle(passed_in_vehicle)
...

However, this cannot be scalable. What is the correct solution to route to specific classes based on a condition?

like image 473
user7692855 Avatar asked Jun 13 '26 21:06

user7692855


2 Answers

The way it looks to me, you can improve design a bit. Since each vehicle 'knows' where it is serviced, you should probably do in each something like

def __init__(self, ..., service):
    super().__init__(self, ...)
    ...
    ...
    service.register_vehicle(self)

this is coming from the perspective that "the car drives to the garage to register" rather than the "garage looks for new cars".

When you initialize a vehicle, pass it its servicing class, as in

new_car = Car(..., my_car_service)

where

my_car_service = Cars()

somewhere before. This is since we assume each new car needs to register, and we do not make a new service for each new car. Another approach, is for the class to contain (composition) its service object from the get go:

class Car:
    service = Cars()
    def __init__(...)
        ...
        Car.service.register_vehicle(self)

so the class contains the servicing object always, and all initialized objects share the same one through a class variable. I actually prefer this.


First initialization:

With regard to your initial initialization of the vehicle, while using locals might be a nifty solution for that, it might be a bit more type safe to have something like what you have. In Python I like to use the "Python switch dictionary" (TM) for stuff like that:

{'car': Car,
 'bus': Bus,
  ...
 'jet': Jet
}[body[vehicle_type]](body)
like image 112
kabanus Avatar answered Jun 16 '26 00:06

kabanus


I don't know if using locals would be ideal, but at least I believe it would scale better than your current solution:

  • use string name to instantiate classes from built-in locals() which will store imports as a dictionary
class Car(object):
    def print(self):
        print("I'm a car")
class Bus(object):
    def print(self):
        print("I'm a bus")

vehicle_type = "Car"
currV_class = locals()[vehicle_type]
currV_instance = currV_class()
#currV_instance.register_vehicle
currV_instance.print()

vehicle_type = "Bus"
currV_class = locals()[vehicle_type]
currV_instance = currV_class()
#currV_instance.register_vehicle
currV_instance.print()

OUTPUT:

I'm a car
I'm a bus
like image 41
Bernardo stearns reisen Avatar answered Jun 15 '26 22:06

Bernardo stearns reisen