I'm trying to replicate the API of a Java library for a vehicle routing problem and it's highlighted something I don't understand about Python classes.
A vehicle fleet can be broken down into two basic criteria; the first is the types of vehicle you own (instances of VehicleType to define capacities, running costs etc.) and individual vehicles (Vehicle with different shift patterns etc.).
In my simplified example, I want to define one VehicleType and then a single Vehicle that takes the attributes of the VehicleType passed to the constructor. Following the answer by Lennart here, using __getattr__ works perfectly in a general case. However, imagine that I have a driver of one van out of 50 that has a special qualification to carry something hazardous, so I want to add an extra capacity property on the Vehicle instance. I tried the following:
class VehicleType(object):
def __init__(self, fixed_cost=0, cost_per_distance=0, cost_per_time=0):
self.capacities = {}
self.fixed_cost = fixed_cost
self.cost_per_distance = cost_per_distance
self.cost_per_time = cost_per_time
def add_capacity_dimension(self, dimension_id, dimension_size):
""" Define a package type and how many of them this vehicle type can carry """
self.capacities[dimension_id] = dimension_size
class Vehicle(object):
def __init__(self, vehicle_type=None, identifier=None):
self._vehicle_type = vehicle_type
self.identifier = identifier
def add_capacity_dimension(self, dimension_id, dimension_size):
self.capacities[dimension_id] = dimension_size
def __getattr__(self, name):
return getattr(self._vehicle_type, name)
if __name__ == '__main__':
van_type = VehicleType()
van_type.add_capacity_dimension("general items", 34)
special_van = Vehicle(vehicle_type=van_type)
special_van.add_capacity_dimension("hazardous chemicals", 50)
print("Capacities of special van: {}".format(special_van.capacities))
print("Capacity of van_type: {}".format(van_type.capacities)) # Why?
I don't understand why my approach has also affected the capacities of the van_type. Vehicle does not directly inherit from VehicleType and I have defined add_capacity_dimension within the Vehicle class. This also contradicts my understanding of the docs about __getattr__:
Called when an attribute lookup has not found the attribute in the usual places (i.e. it is not an instance attribute nor is it found in the class tree for self). name is the attribute name.
Can someone please explain why the instance van_type is also affected here?