1

Following an online tutorial, I typed up the following code:

class Car:
    # define and initialize some attributes of Car object
    def __init__(self):
        self.speed = 0
        self.odometer = 0
        self.time = 0

    # 'get' function for current speed
    def say_state(self):
        print("I'm going {} kph!".format(self.speed))

    # 'set' function for current speed
    def accelerate(self):
        self.speed += 5

    # 'set' function for current speed
    def brake(self):
        self.speed -= 5

    # 'set' function for trip time and distance
    def step(self):
        self.odometer += self.speed
        self.time += 1

    # 'get' function for average speed
    def average_speed(self):
        return self.odometer / self.time


if __name__ == "__main__":
    my_car = Car()
    print("I'm a car")
    while True:
        action = input("What should I do? [A]ccelerate, [B]rake, "
                       "show [O]dometer, or show average [S]peed").upper()
        if action not in "ABOS" or len(action) != 1:
            print("I don't know how to do that.")
            continue
        if action == "A":
            my_car.accelerate()
        elif action == "B":
            my_car.brake()
        elif action == "O":
            print("My car has driven {} kilometers".format(my_car.odometer))
        elif action == "S":
            print("My car's average speed was {} kph".format(my_car.average_speed()))

        my_car.step()
        my_car.say_state()

Then, I broke from the tutorial because it didn't tell me what the if __name__ == "main" business was about. Reading elsewhere, I kind of understood that this statement prevents the code following that if statement from executing if the module isn't being run as the main class, but rather is imported. So to test this out I typed up another small module "import_practice.py:

import Car

corolla = Car()
corolla.say_state()

This code would not run, with the error "Car is not callable", so I figured my import was wrong. I replaced import Car with from Car import Car and it worked, but according to the following answer, it shouldn't make a difference, right? In fact, if that answer is correct, it isn't the behavior I'm looking to get out of my import at all.

rocksNwaves
  • 5,331
  • 4
  • 38
  • 77
  • Try `from Car import *` ,Then use `object=Car()` – Ubdus Samad Jan 09 '18 at 18:49
  • @UbdusSamad no, that is not the recommended way to do things. – juanpa.arrivillaga Jan 09 '18 at 18:54
  • Are you coming from a Java background by chance? Your problem is that you named your *module* the same as a *class in the module*. That is generally *not advisable* in Python. But to access the class, you need `Car.Car()`. – juanpa.arrivillaga Jan 09 '18 at 18:55
  • @juanpa.arrivillaga Yes, Java is the only language I kind of remember from college. I'm just getting back into programming. I appreciate you notifying me of that best practice violation. – rocksNwaves Jan 09 '18 at 19:03
  • 1
    @rocksNwaves yes, Python is quite different from Java. Modules are the fundamental programming unit, not classes. Your module could be something like `vehicles.py` and then you could `import vehicles` and use `vehicles.Car`. Or even just lower-case `car.py`. – juanpa.arrivillaga Jan 09 '18 at 19:07
  • @juanpa.arrivillaga So just name the file and the class two separate things is the convention? – rocksNwaves Jan 09 '18 at 19:19
  • @juanpa.arrivillaga . I suggested him import all, cause he only had a single class in the other code. – Ubdus Samad Jan 09 '18 at 19:40
  • @rocksNwaves well, the convention is that python modules are `lowercase.py` – juanpa.arrivillaga Jan 09 '18 at 19:42

3 Answers3

6

If you do this:

import Car

Then your code should be:

corolla = Car.Car()
corolla.say_state()

When you "import" a module, you are not bringing all its components to the current namespace. You are just loading it. If you want to refer to a component on that module, you must refer it through its module name: Car.Car. Here, first Car is the name of the module, and the second one is the name of the class.

If you actually want to import all module's components to the current namespace, you can do from Car import *. But I would not recommend that.

After that, you did from Car import Car. Here, the sentence is stating that you are bringing the name Car to the current namespace, from the Car module. Hence, you can just use Car on your code after this.

Please do note that the answer you are referring to is not saying that import Car is the same as from Car import Car.

Pablo Santa Cruz
  • 176,835
  • 32
  • 241
  • 292
  • So, would you say that importing the entire module allows you to then use any object defined in it, but requires you specify which object you want each time, while using the `from` method specifies EXACTLY which object you are going to use, and therefore makes all the other bits and pieces inaccessible? If that is correct, would you say it is more efficient to use the `from` method when you just want one object or symbol from a module so you aren't loading extraneous stuff? – rocksNwaves Jan 09 '18 at 19:35
3

The line

import Car

loads the module Car, and makes all the thing it declares (ie., the class Car) available inside the namespace Car.

The line

from Car import Car

loads the module Car (the from Car import part), then makes the name Car declared in that module (which is the class Car) available in the current namespace. That is,

import Car
Car.Car()

is equivalent to

from Car import Car
Car()

except for what the name Car in the global namespace refers to (the whole module, or just the one class).

Note that import statements also support as. With that you can change the name given in the current namespace:

import Car as CarModule
CarModule.Car()

and

from Car import Car as CarClass
CarClass()

also do the same thing as the other two, again except for names.

Daniel H
  • 7,223
  • 2
  • 26
  • 41
  • So using `from Car import Car` does double duty? It imports the class/module AND creates an instance of it? If I understand correctly, that's fairly interesting. What if I wanted to create a second Car object, would I have to do another import? – rocksNwaves Jan 09 '18 at 18:52
  • @rocksNwaves no, it does not do that at all. All it does is import the **module**. It does no instantiating of anything else unless you have code in your module which happens to instantiate a class (e.g., inside your `if __name__ == '__main__'` which the guard prevents from being executed if imported as a module) – juanpa.arrivillaga Jan 09 '18 at 18:56
  • The `from Car import Car` line doesn’t create an *object* of type `Car`; it only makes the *class* available. It mean so that when you type `Car`, Python knows what that is; you still need `corolla = Car()` to create one. The difference is that the name `Car` means the class, not the module. – Daniel H Jan 09 '18 at 18:56
  • @juanpa.arrivillaga The point of the `if __name__ == "__name__"` is to prevent that code from running, so it doesn’t actually create a `Car` when you `import` the module. – Daniel H Jan 09 '18 at 18:57
2

Import troubles

If you have a file called Car.py and you call import Car, that will add the entire module to the current scope.

import Car
print(dir(Car))
# [ ... 'Car' ]

This means you can also do things like:

# import the module and alias it
import Car as c

# add class to local scope as `Car`
Car = c.Car

On the other hand, if you use the from keyword, you are getting something in that module and adding it to the current scope:

from Car import Car
corolla = Car.Car()
corolla.say_state()

What is this __name__ == '__main__' nonsense?

When you call a file python <my-file-name> it sets the special variable __name__ to be the string __main__. if __name__ == '__main__' translates to "if someone is trying to run this as an independent script, then do the following". On the other hand, if someone calls import on that same file, that area will not trigger.

Community
  • 1
  • 1
cwallenpoole
  • 79,954
  • 26
  • 128
  • 166