Welcome to the CSC Q&A, on our server named in honor of Ada Lovelace. Write great code! Get help and give help!
It is our choices... that show what we truly are, far more than our abilities.


+7 votes

I know that if you do import graphics, you have to type graphics.(whatever) and if you do from graphics import* you can leave out graphics.

But what actually happens in python when you do these two? Is one more efficient for python to use? What's the magic behind the spell??

asked in CSC201 Spring 2021 by (4.8k points)

2 Answers

+3 votes

import graphics uses less resources, but is a lot less convenient if you're using it constantly.

answered by (8 points)
+2 votes

It's not really about efficiency. The trade-off is "convenience" vs "being careful".

It's convenient to be able to write Point without having to say graphics.Point.
However, in more complex programs, where you import a dozen different modules, it quickly becomes unclear to you (and to others reading your code) where the Point class came from -- was it from this graphics module, or from a different graphics module, or maybe a special geometry module, or a world_map module that lets you find points of interest along a Route.

Perhaps even more importantly, you can also create very difficult-to-track-down bugs by importing some name that you didn't intend to, or redefining something. For example, if you did:

from graphics import *
from world_map import *

then you would only end up with the Point class from world_map, and any time you tried to create a Point object to use for graphics, it would actually be trying to create a world_map Point object, and it would probably fail with an error saying that you are giving it the wrong parameters. If you did it in the opposite order:

from world_map import *
from graphics import *

Then you'd be able to use the Point class from graphics, but when you tried to create a Point of interest on the world map, you'd get an error.

This may seem unlikely, but again, in larger programs that import a dozen modules, the chances of some name in ONE module conflicting with some name in another one actually becomes pretty high. And it can be very frustrating to track down bugs like this, because Python doesn't warn you when you're re-defining a variable/function that was already defined before.

Long story short: for big software projects, and professional Python programming, proper style is to avoid using from X import *. However, for small projects that only use one library, the convenience of typing shorter (and thus also more readable code) may outweigh the concerns I just mentioned.

The import module as othername syntax can sometimes provide a middle ground. For example, we could use:

import graphics as gr

Then we could write code like:

window = gr.GraphWin(...)
p = gr.Point(...)

You'd still have to go back to the top of your code to see which module gr was referring to, but at least you wouldn't have to check all 12 modules that you imported, to see which ones contained a Point class, etc.

This whole conversation relates to a concept called a "namespace" in programming. If you want to dig deeper into the details of how namespaces work in Python, and how it relates to the scope of different variables and functions, here's a link https://realpython.com/python-namespaces-scope/

answered by (17k points)