Importing Relative Paths
00:00 In the previous lesson, I showed you how to locally install a package. In this lesson, I’ll be adding features to that same package that won’t work because of a relative import.
00:10 An absolute import is one that uses the fully qualified module name using all the dots. This case doesn’t care where the module is in comparison to the thing doing the importing.
00:20
Whereas a relative import imports things relative to where the importer is doing the importing. There are two ways of doing a relative import. The first is to use a .
in the import statement to mean the current location.
00:35
You can in fact include other modules after the dot. For example, I could do from .canada import maple_syrup
if maple_syrup
were a thing in the canada
module.
00:45 The second way is to use the module name relative to where you are. Strictly speaking, this isn’t a relative import. This is working because the local directory is in the module search path, but in practice, it has the same issues as a relative import.
01:00 In both cases, the location of the importer is relative to the thing being imported.
01:06 So why would you relative import? Well, mostly because it saves you typing if you’ve got a really deep package structure. The cons kind of outweigh the typing relief, though.
01:15 If you move your script, the import breaks. If you package your script, it breaks. Did you know you can zip up a package and run it directly from Python? Guess what I’m going to say next? Yep.
01:25 If you do that, relative imports break. This is why relative imports aren’t recommended. PEP 8 explicitly tells you to use absolute imports. Although it feels like PEP 8 has been around forever, it was created in 2001 while Python itself started out in the eighties.
01:43 In the previous lesson I showed you how to create an installable package. Let’s revisit that. Adding a bit more code to show you the problem with relative imports.
01:53
I’ve added two new files in the installable package’s source directory, box.py
, and insides.py
. I’ve also added another run-it-test-it kind of script like getgift
, called getbox
.
02:06
Let’s start with box.py
inside the package.
02:11
Nothing too crazy here, just two lines of code. They import the CONTENTS
constant from the insides
module and print a little message.
02:22
And this is the insides
module where the CONTENTS
constant is defined and also a message. Now I’ll open a REPL session in the src
package directory, and I can import box
. So far, so good. box
gets imported, which then imports contents
from insides
.
02:42
The key part of this working is my current location. I’m in the actual directory, but I won’t always be, will I? Recall from the previous lesson the test-it-style script called getgift
.
02:57
This is its equivalent getbox
. Like before, I manually inject the src
directory into the module path, but this time, instead of importing something from gift
, I’m importing something from box
.
03:09 I already told you this is going to fail, so this won’t be a surprise.
03:17
And although I’ve added src
to the module path, getbox
doesn’t work. When it tries to import box
, which tries to import the insides
module, Python can’t find the module.
03:28 This is because it was relative to the script and I’m no longer in that directory. Remember, the current directory is in the module path, but that’s only useful if you’re running in the directory where the import is happening.
03:40
Recall that I installed this package locally using pip install -e
. That means the package automatically is in my module path.
03:55
and that’s not a problem. But when I import box
,
04:02
I have the same issue that getbox
had. Relative imports only work if you are relative to the right location. As soon as you’re not, things start falling apart.
04:12 In short, if you’re going to use relative imports, only use them for locally running scripts. Honestly, even in that case though, your script is more future-proof if you stick to absolute imports. Tired of keeping all your things in one place?
Become a Member to join the conversation.