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/