
Accessing code from other modules
We'll start off this section by understanding the difference between absolute and relative imports, then move on to writing those, and finally, we'll look at cyclic dependencies.
When we are importing one of the package's modules from outside the package, there's only one sensible way that it could work-we tell Python which package and module we want, and it either finds and imports it or raises an exception if it can't. Simple!
import packagename.modulename
When we're already inside a package, the situation is more ambiguous because import name could just as easily mean "look for name within this package" or "look for name in the Python search path." Python breaks this ambiguity by defining import name to mean that a package or module called name should be searched for in Python's search path:
import name
Also, it also gives us a way to specify a relative import if we'd rather have it just look within the current package. We can specify a relative import by putting a dot in front of the name of the module we want to import, as shown in the following code:
import .name
When Python sees this, it will look for a module called name in the same package as the module our code is running in.
Often, we only need one or two objects from another module and it's more convenient to import those objects directly into our global scope than it would be to import the module as a whole and access its contents. Python lets us do that with a slight variation on the import syntax:
from .name import Foo
Finally, sometimes we want to rename an object within our scope as we import it. We could do that by modifying our import with the as keyword:
from .name import Foo as Bar
In the preceding example, even though the object is called Foo in the name module, in our current module, it's named Bar. This trick works for absolute imports too by the way.