Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

This lesson is for members only. Join us and get access to thousands of tutorials and a community of expert Pythonistas.

Unlock This Lesson

Changing How You Import

In this lesson, you’ll figure out why imports sometimes don’t work. Along the way, you’ll learn:

  • How -m works differently
  • How things get added to PYTHONPATH
  • How to fix the -m version and use absolute imports

00:00 So, the problem here is that this snake module is not in the path, right? So, how might we add that then? Yeah, if we kind of scale back a little bit, because we had the exact same code working when we just did python snakesay without the -mRight, okay, becuase this this one works. Right.

00:20 But the -m doesn’t. Exactly. And this is because the -m treats the path slightly differently. So, there is a convenience, essentially, when you’re running things that the current directory is put into path. Right. Okay, so when you run python snakesay, then the current directory gets added to path. Right. And in that case, that is the snakesay directory, while we do the python -m, this current directory is just the RealPython directory, not RealPythonsnakesay.

00:49 Yes. So, when we run just python snakesay, the directory that’s added to Python’s path is the snakesay directory within this, the RealPython directory that we’re working.

00:59 It’s this directory here. Exactly. With the __main__ and the snake.py. Yeah, so then, therefore, it finds the snake.py file. Okay.

01:07 So then, we can find the __main__.py file, basically, and the snake.py, which needs the import to actually print the bubble and the snake.

01:16 And then in the -m version, does something get added to path here? I think on the -m version, it still adds our current path, but it doesn’t add the snakesay path, or snakesay directory, to path. Okay, so it’s not looking at the subdirectories. Right.

01:34 So because snake from here is kind of within the snakesay directory, it’s saying, “Okay, I can’t find snake.” It’s not going, recursively searching in the subdirectories for all the files.

01:45 Correct. Okay, so, how do we fix this? There’s a couple of different ways, and let’s start with the simplest one, I guess, would be that if you go into your code and now because snake is now part of the snakesay kind of package, we can say from snakesay import snake.

02:08 And now we can test it. Now it should run. Here we go.

02:13 Yay. Okay, cool. So, let’s go back to the code for a second.

02:19 So we’re in snakesay, but at the same time we’re saying from snakesay, so this code, when it’s running, it’s not sure where it is if we call it with the -m.

02:32 We have to sort of assume that since we’re calling it from outside of this package, that everything starts from that point. So we have to explicitly say from outside the package, we have to go into the package and get snake from snakesay. Yes, and what we’re really doing here is that we’re starting using something called absolute imports. So, our import snake earlier—typically I’ll just call it local importit’s technically also an absolute import, but it kind of behaves a little bit differently because it depends on this dynamic path that’s being set. Right.

03:08 It depends on where you’re calling your code from because it will only work if you call it from inside the module in certain ways. But it starts to break when you’re using the -m flag in other places, whereas this has a more explicit pointer towards the snake module.

03:27 Exactly.

Stephen Felsher Jr on Nov. 27, 2022

Add the following line of code to __main__.py if you want to see how the Python path is affected when invoking your script with the options mentioned in this lesson of the tutorial (“Changing How You Import”).

print(f"Python path: {sys.path}")

You may also have to comment out the import of snake and the function call to snake.say to avoid any exceptions.

Become a Member to join the conversation.