-: Hi guys and welcome back. In this video,
we're going to talk about relative imports in Python.
This is something that's really confusing
for new Python beginners, and to be honest,
it's a bit weird.
And you're not going to be using them very much at all
but I just wanted to talk about them
so that you all use them precisely
because they work very differently
than what you might expect.
What I've got here is four files now.
I've got code, and mymodule in the same folder.
Then we've got our libs folder that contains mylib.
And then we've got our operations folder
that contains operator.
So code imports mymodule, mymodule imports libs.mylib,
and mylib imports libs.operations.operator.
And each one prints out their name.
So if we press play right now, what you get back is--
Well first of all, something important to note is that--
I may not have mentioned it in the last video,
is that when you run the import,
that immediately jumps into the next file
and starts running it.
So of course, code.py imports mymodule
so that stops code.py from running
and Python jumps to mymodule. This imports mylib.
So this stops running and jumps to mylib.
This imports operator so that stops running
and jumps to operator, and that prints.
Then we go back to mylib and then we print,
then we go back to mymodule, then we print,
then we go back to code and then we print.
So that's why the order here is reversed
from the order in which the files are running.
Code is running first but that prints out last
because of that tree of imports that's going on.
So this is not relative imports.
These are just absolute imports where you have to define
the path that you're importing from.
So here and the path is libs.operations.operator
and we're doing from libs.operations import operator,
or you could do import libs.opererations.operator
if you preferred, although then
you would have to access things like
libs.operations.operator.divide.
If a divide function was defined inside that file,
which it's not.
At the moment, nothing's defined inside these files.
They're just printing out their names.
So that is absolute imports.
Let's talk about relative imports.
A relative import is one that can import
from the current folder that the file is in.
But it cannot import unless there is a folder name
in the import path, in the module path.
So, here's what that means.
Libs.mylib when it prints out the name
you can see that there is a folder inside the import path
that is separated from other things in the path
by a full stop, a period.
So here you've got the libs folder
and inside it you've got the mylib file.
You can tell this is the file
because it's the last thing in the import.
Similarly, the operator.py has the file operator,
that's where we're importing from
and two folders, operations and libs.
So, from these two you can do relative imports
because there is a folder.
From these two you cannot do relative imports
because there's no folder.
So let me show you what happens
if you try to do a relative import
and you don't have a folder.
In order to do a relative import
you need to use the from syntax.
So you can do from .mymodule import divide let's say
and I'm going to just add a divide function here.
So (mumbles) divide function there it doesn't do anything
and we're gonna try to import it from .mymodule.
So what that means is from the current folder
look at the mymodule file and import the divide function.
So that makes sense because mymodule is in the same folder
as code.py. You can see down here they're in the same folder
so they should be fine.
But when you try to do that,
what it does is it tries to import from __main.mymodule.
So as you can see because the name of this file was __main
and it doesn't have a folder,
it tries to import from the current place it's in
and Python won't let you do that.
If you are importing from the file you run,
you can't use relative imports.
Going into mymodule.py you could do from .libs import mylib
and what that's going to do is it's going to try to access
the libs folder inside the current folder,
that's what the dot means.
But again, if you try to run this code,
you're going to get that you attempted a relative import
with no known parent package.
Again, mymodule has no information about the folder it's in
so Python can't do a relative import from it.
I'll show you again these paths here,
because what you've got--
Oh, sorry I'll run code.py so it's the same as before.
What you've got is that mymodule and main
are at the top level.
When you're trying to do a relative import,
what Python's going to do is it's going to remove the file
and it's just going to try to append
whatever you import from into the rest of the import path.
So if we go to mylib and then we do from .operations
import operator, what that's gonna do is it's gonna say,
"Okay, mylib, you are inside libs.mylib."
So, because you're trying to do a relative import,
we're going to remove the file
and we're gonna try to put operations at the end
and import from there.
So here it'll work because it'll do libs.operations
and then it'll import operator from that.
So if I run code.py again,
you can see that it all works fine.
There's no errors whatsoever.
However, if by any reason you want to run your mylib file,
for example to debug it or run some code inside it,
make sure it works or something like that,
you won't be able to because, of course,
this now becomes main, if you run it,
and then you can't use relative imports from inside it.
So, if you are going to use relative imports,
you always have to run the same file at the top level,
otherwise you may encounter some issues.
Going into operator.py,
you can actually do from ..mylib import star, let's say,
and what this does in Python
is it accesses the parent folder.
So again if operator is inside libs.operations,
dot dot is going to try to remove the operation
and go direct to the previous one.
So it'll try to do libs.mylib. That's what the dot dot means
it just skips the parent folder and goes up to the next one.
So, of course in order to do that,
you need to be at least two levels deep.
Otherwise if you try to do that for example from libs.mylib,
you're going to try to skip libs and go to the previous one,
but there is no previous one, so you'll find that error.
So, again in order to do this,
you need to do something like that,
and that you can see works totally fine.
Let's go back to why we didn't print anything else out
when we ran this code because as you can see
this output is exactly identical to the one we had before,
so it seems that this did nothing.
But really what's happened is Python has realised
that libs.mylib had already been imported by mymodule
before we imported operator.
So, it didn't try to import it again.
This just reuses the import that's already on six modules.
So that's why we didn't see any more output.
mylib.py didn't run again when we tried to import this.
It was already in dot modules.
I also wanted to say that at any point in time
if you wanted to import say operator.py from mymodule,
you can do import libs.operations.operator,
or of course, from libs.operations import operator.
You can do that as well.
By the way, this just means import everything
that is inside this path here.
So if there were multiple functions,
you would import them all.
If there's multiple variables defined in there,
you would also import them, and so on.
All right that's everything for this video.
Thank you for joining me. I know this stuff is confusing,
but my advice is to not use relative imports in Python.
They are difficult to understand, they're confusing,
they only work if you always run the same files,
and they won't work if you try to run other files
such as the ones that use relative imports
for debugging or to try things out.
So, don't use them. Use absolute imports instead.
Your life will be much easier, and really,
you're not gonna encounter any problems with that.
So thanks for joining me and I'll see you in the next one.