0

I have 2 classes: Vehicle & Car.

Vehicle Class has a dictionary of Car objects & a heap.

ClassV.py:

from ClassC import Car
import heapq

class Vehicle:
    MapOfCars_ID = {}
    heap = [] # Stores the load factor of each car
    counter = 0

    def createCar(number, idnum):
        C = Car(number, idnum) # Create a car object
        self.MapOfCars_ID[counter] = C # Dict of Car_ID : Car Object
        self.heapq.heappush(heap, (0.0, counter)) # Heap stores load factor, Car_ID
        counter += 1

    def AssignCar():
        t = heapq.heappop(heap)
        MapOfCars_ID[t[1]].addPassenger()

ClassC.py is the logic for creating a Car:

from ClassV import Vehicle

class Car:
    size = 0;
    occupiedSeats = 0
    carId = -1
    def __init__(size, id_number):
        self.size = size
        self.carId = id_number
        print "Created Car with size " + self.size + " and ID number "+ self.carId

    def addPassenger():
        if self.occupiedSeats < self.size:
            self.occupiedSeats += 1
            # Code below adjusts the load factor of the car in the heap when a passenger is added to the car 
            # Load factor = seat-occupied/total-seats-in-the-car
            for index, value in Vehicle.heap:
                if value[1] == self.carId:
                    Vehicle.heap[index] = heap[-1]
                    heap.pop()
                    t = (float(self.occupiedSeats/self.size), self.carId)
                    heap.append(t)
                    heapq.heapify(Vehicle.heap)
                    break
        else:
            print "Car is full!"

The program is run from another file, main.py:

from ClassV import Vehicle
from random import randint

def main():
    for i in range(1, 10): # Create 10 cars
        r = randint(1,6) # Maximum number of seats could be 6 in a car
        Vehicle.createCar(r, i) # <Car size, ID>
    Vehicle.AssignCar()

if __name__ == "__main__":
    main()

The intention of this program is to create 10 cars and then assign passengers to the car having minimal occupancy.
As shall be evident from the program, The heap which is a class attribute of the class Vehicle is being updated in Car Class. And, Class Vehicle is creating an array of Car objects.

This gives me an error:

File "/home/Testing/ClassC.py", line 1, in <module>
    from ClassV import Vehicle
ImportError: cannot import name Vehicle

I have searched around but could really find a resolution to this problem. What is the right way to resolve this problem?

Update: I got a few comments which explain that this is possibly a problem of circular imports and has 2 solution:

  1. Refactor the program to avoid circular imports
  2. Move the imports to the end of the module

I am looking for feedback as to how do I do either of these.

user248884
  • 851
  • 1
  • 11
  • 21

1 Answers1

1

Update: I got a few comments which explain that this is possibly a problem of circular imports and has 2 solution:

  1. Refactor the program to avoid circular imports
  2. Move the imports to the end of the module

Several things wrong here:

  1. Your chosen nomenclature is confusing/wrong. Why is the Vehicle class a container for Car instances? I would call it something like VehicleRegistry, or similar, to make its intent explicit.
  2. You have a fundamental design flaw, in that you are violating the responsibilities of your two classes. An instance of Car should be able to stand in isolation, and when I add a passenger to it, it should only affect the internal state of that instance, it should not affect the state of Vehicle, this is a recipe for fragile code, that breaks easily.
  3. Do not use class level attributes, unless you know exactly what you're doing. Altering the state of a class level attributes can alter the state of said attribute for all instances of that class, leading to some very interesting and unexpected behaviour.

This is what I mean by a class level attributes:

class Person(object):
    first_name = "Bob"
    last_name = "Smith"

These are tied to the class, not an instance.

Possible solution:

Herewith some code to illustrate what I mean:

Your addPassenger method should only add a passenger to the car and return whether it was successful or not, nothing else.

def add_passenger(self) -> bool:
    if self.capacity > self.number_of_passengers:
        self.capacity = self.capacity + 1
        return True
    return False

You place the updating of your load factor logic in the assign_car method, for example:

def assign_car(self):
    car_id = heapq.heappop(self.heap)
    car = self.vehicle_registry[car_id]
    result = car.add_passenger()

    if result:
        # Put your load factor update logic here ...
        print("A passenger was successfully added to: {0}".format(car.id_number))
    else:
        print("A passenger could not be added to the car.")

Edit[2018/09/24]:

Alternatively, if load factor is an attribute of the Car, then it makes sense to place it on the instance of car itself, and allow the VehicleRegistry to consume the load factor state.

Community
  • 1
  • 1
Marley
  • 373
  • 1
  • 4
  • 9