Why is code outside a class definition run when only the class is imported?

I want to import a python class from another file without importing the rest of the file.

When I import the class using from Exercise_7 import Vehicle (Vehicle being the class), and then run my code it seems that lines from Exercise_7.py that are outside the class definition also run.


Exercise_7.py :

import numpy as np

class Vehicle:
  def __init__(self, typeOfVehicle, velocity, colour, electric):
    self.typeOfVehicle = str(typeOfVehicle)
    self.velocity = tuple(velocity)
    self.velocity = np.array(self.velocity)
    self.colour = str(colour)
    self.electric = bool(electric)
  def updateVelocity(self, velocityTuple):
    self.velocity = np.array(velocityTuple)

  def allAttributes(self):
    attributes = [self.typeOfVehicle, self.velocity, self.colour, self.electric]

  def emissions(self, distance):
    #electric vehicles
    if self.electric == True:
      if self.typeOfVehicle == "Car":
        emission = 1*distance
      elif self.typeOfVehicle == "Truck":
        emission = 5*distance

    else:  #vehicle is not electric
      if self.typeOfVehicle == "Car":
        emission = 10*distance
      elif self.typeOfVehicle == "Truck":
        emission = 50*distance
    return emission

#---TEST CODE THAT IS BEING RUN (when I don't want it to)--- 

vehicle1 = Vehicle("Car", (3,5), "red", False)

Exercise_8.py (The file that when run, runs the unwanted code) :

from Exercise_7 import Vehicle
import numpy as np
import random as r

def newVehicles(type, electric1):
    colours = ["red", "blue", "green", "black", "grey"]
    for i in range(0,50):
        velocity = (r.uniform(1,70), r.uniform(1,70))
        newVehicle = Vehicle(type, velocity, colours[r.randint(0,4)], electric1)

def createVehicles():
    newVehicles("Car", True)
    newVehicles("Car", False)
    newVehicles("Truck", True)
    newVehicles("Truck", False)
    return vehicles

def calculateEmissions(vehicles, time):
    electricCarsEmissions = 0
    nonelectricCarsEmissions = 0
    electricTrucksEmissions = 0
    nonelectricTrucksEmissions = 0
    for vehicle in vehicles:
        speed = (vehicle.velocity[0]**2 + vehicle.velocity[1]**2)**1/2
        distanceTravelled = speed*time
        vehicle.distance = distanceTravelled
        emission = vehicle.emissions(distanceTravelled)
        if vehicle.typeOfVehicle == "Car" and vehicle.electric == True:
            electricCarsEmissions += emission
        elif vehicle.typeOfVehicle == "Car" and vehicle.electric == False:
            nonelectricCarsEmissions += emission
        elif vehicle.typeOfVehicle == "Truck" and vehicle.electric == True:
            electricTrucksEmissions += emission
        elif vehicle.typeOfVehicle == "Truck" and vehicle.electric == False:
            nonelectricTrucksEmissions += emission
    return electricCarsEmissions, nonelectricCarsEmissions, electricTrucksEmissions, nonelectricTrucksEmissions
vehicles = []
listOfVehicles = createVehicles()
print(calculateEmissions(listOfVehicles, 20))

When Exercise_8.py is run, it outputs this :

['Car', array([2, 6]), 'red', False]  #output from Exercise_7.py code
1000 #output from Exercise_7.py code
(1836161.109986278, 16586342.282856379, 7901210.428254995, 74406974.7703749) #desired output

>Solution :

Modules are blocks of executable code, as are def and class statements. They are only well-defined in their entire context of code. As such, it is not possible to load only parts of a module.

Running from Exercise_7 import Vehicle loads the entire module Exercise_7 into the interpreter but only imports the name Vehicle into the file.

Code that is not supposed to run during regular imports should be in a __main__ guard instead:

if __name__ == "__main__":
    vehicle1 = Vehicle("Car", (3,5), "red", False)

Loosely speaking, a module is __main__ only when directly executed – e.g. as python -m Exercise_7 – but not when imported by another module.

Leave a Reply